Added non-correcting error recovery stuff
This commit is contained in:
385
util/LLgen/src/savegram.c
Normal file
385
util/LLgen/src/savegram.c
Normal file
@@ -0,0 +1,385 @@
|
||||
/* Copyright (c) 1991 by the Vrije Universiteit, Amsterdam, the Netherlands.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
#ifdef NON_CORRECTING
|
||||
|
||||
/*
|
||||
* L L G E N
|
||||
*
|
||||
* An Extended LL(1) Parser Generator
|
||||
*
|
||||
* Author : Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/*
|
||||
* savegram.c
|
||||
* Save the input grammar for non-correcting error recovery
|
||||
*
|
||||
* Grammar rules are `flattened' by introducing anonymous nonterminals.
|
||||
* [B]? becomes X; X: B | {empty}
|
||||
* [B]+ becomes X: B Y; Y: X | {empty}
|
||||
* [B]* becomes X; X: B X | {empty}
|
||||
* [B | C] becomes X; X: B | C
|
||||
* [B | C]* becomes X; X: B X | C X | {empty} etc.
|
||||
*/
|
||||
|
||||
|
||||
# include "types.h"
|
||||
# include "extern.h"
|
||||
# include "io.h"
|
||||
# include "assert.h"
|
||||
# include "sets.h"
|
||||
|
||||
#define LLALT 9999
|
||||
|
||||
static int nt_highest;
|
||||
extern int nbytes;
|
||||
extern p_mem alloc();
|
||||
extern p_set start_firsts;
|
||||
extern p_set setalloc();
|
||||
extern p_gram search();
|
||||
|
||||
STATIC save_rule();
|
||||
STATIC save_set();
|
||||
|
||||
/* t_list will contain terms to be `flattened' */
|
||||
static struct t_list {
|
||||
p_term term;
|
||||
int t_nt_num;
|
||||
} *t_list;
|
||||
|
||||
/* Subparse list will contain symbols in %substart */
|
||||
static struct subparse_list {
|
||||
p_gram sub_action;
|
||||
int sub_nt_num;
|
||||
} *sub_list;
|
||||
|
||||
/* Index in t_list */
|
||||
static int t_list_index;
|
||||
|
||||
/* Index in subparse_list */;
|
||||
static int sub_list_index;
|
||||
|
||||
/* File to save grammar to */
|
||||
static FILE *fgram;
|
||||
|
||||
/* Nonterminal number to simulate parsers that get called in actions
|
||||
used when LLgen called with -n -s options */
|
||||
int act_nt;
|
||||
|
||||
save_grammar(f) FILE *f; {
|
||||
/*
|
||||
* Save the grammar
|
||||
*/
|
||||
register p_nont p;
|
||||
register p_start st;
|
||||
register int nt_nr;
|
||||
|
||||
fgram = f;
|
||||
|
||||
/* Compute highest nonterminal nr. */
|
||||
nt_highest = nnonterms + assval - 1;
|
||||
|
||||
|
||||
/* Generate some constants in the grammar file */
|
||||
|
||||
/* Allocate terms list */
|
||||
t_list = (struct t_list *) alloc((unsigned) nterms * sizeof(struct t_list));
|
||||
t_list_index = 0;
|
||||
|
||||
sub_list = (struct subparse_list *) alloc(nsubstarts * sizeof(struct subparse_list));
|
||||
|
||||
fputs("static ", fgram);
|
||||
fputs((prefix ? prefix : "LL"), fgram);
|
||||
fputs("grammar[] = {\n", fgram);
|
||||
|
||||
/* Check if -n -s option is on */
|
||||
if (subpars_sim) {
|
||||
|
||||
/* Allocate action simulation nt */
|
||||
|
||||
act_nt = ++nt_highest;
|
||||
|
||||
/* write simualtion rule */
|
||||
fprintf(fgram, "/* Simulation rule */\n");
|
||||
fprintf(fgram, "%d,\n", act_nt);
|
||||
|
||||
/* Put a firstset and a fake followset */
|
||||
/* Followset optimization is not implemented for
|
||||
-s because it would be hard, and does not
|
||||
bring enough improvement to jutify the effort
|
||||
*/
|
||||
save_set(start_firsts);
|
||||
save_set(start_firsts);
|
||||
/* Simulation rule procudes empty */
|
||||
fprintf(fgram, "%d,\n", 1);
|
||||
for (st = start; st; st = st->ff_next)
|
||||
{
|
||||
fprintf(fgram, "%d, %d, %d, \n", st->ff_nont + assval,
|
||||
act_nt, LLALT);
|
||||
}
|
||||
fprintf(fgram, "%d, \n", 0);
|
||||
|
||||
}
|
||||
|
||||
/* Now process all rules */
|
||||
for (p = nonterms, nt_nr = assval; p < maxnt; p++, nt_nr++) {
|
||||
fprintf(fgram, "/* nr. %d %s */\n", nt_nr, p->n_name);
|
||||
fprintf(fgram, "%d, ",nt_nr);
|
||||
if (! p->n_rule) { /* undefined */
|
||||
f_input = p->n_string;
|
||||
error(p->n_lineno,"Nonterminal %s not defined",
|
||||
p->n_name);
|
||||
}
|
||||
|
||||
/* Save the first_set and follow set */
|
||||
save_set(p->n_nc_first);
|
||||
save_set(p->n_nc_follow);
|
||||
|
||||
if (p->n_flags & EMPTY)
|
||||
fprintf(fgram, "%d,\n", 1);
|
||||
else
|
||||
fprintf(fgram, "%d,\n", 0);
|
||||
|
||||
save_rule(p->n_rule, 0);
|
||||
|
||||
fprintf(fgram, "%d,\n", 0);
|
||||
}
|
||||
|
||||
/* Resolve terms, they are on t_list */
|
||||
|
||||
fprintf(fgram, "/* Fresh nonterminals */\n");
|
||||
|
||||
{ int i;
|
||||
for (i = 0; i < t_list_index; i++)
|
||||
{
|
||||
|
||||
/* Terms of the form [] without + ? * or number produce
|
||||
a NIL pointer in the term-list */
|
||||
if ((t_list + i)->term == (struct term *) 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
fprintf(fgram, "%d, ", (t_list + i)->t_nt_num);
|
||||
|
||||
/* Save the first and follow sets */
|
||||
|
||||
save_set((t_list + i)->term->t_nc_first);
|
||||
save_set((t_list + i)->term->t_nc_follow);
|
||||
|
||||
/* NOTE: A VARIABLE REPETITION COUNT TERMS RULE IS NOT
|
||||
ALLOWED TO PRODUCE EMPTY IN LLGEN
|
||||
*/
|
||||
|
||||
switch(r_getkind((t_list + i)->term)) {
|
||||
case FIXED:
|
||||
/* Already done by repeating new nonterminal */
|
||||
|
||||
/* FIXED term-rule may produce empty */
|
||||
if (empty((t_list +i)->term->t_rule))
|
||||
fprintf(fgram, "%d,\n", 1);
|
||||
else
|
||||
fprintf(fgram, "%d,\n", 0);
|
||||
|
||||
save_rule((t_list + i)->term->t_rule, 0);
|
||||
fprintf(fgram, "%d,\n", 0);
|
||||
break;
|
||||
case STAR:
|
||||
/* Save the rule, appending the new lhs for this rule */
|
||||
|
||||
/* Star rules always produce empty */
|
||||
fprintf(fgram, "1,\n");
|
||||
|
||||
save_rule((t_list + i)->term->t_rule,
|
||||
(t_list + i)->t_nt_num);
|
||||
fprintf(fgram, "%d,\n%d,\n", LLALT, 0);
|
||||
/* ALT EMPTY*/
|
||||
break;
|
||||
case PLUS:
|
||||
/* Save the rule appending a fresh nonterminal */
|
||||
|
||||
fprintf(fgram, "%d,\n", 0);
|
||||
|
||||
save_rule((t_list + i)->term->t_rule, ++nt_highest);
|
||||
fprintf(fgram, "%d,\n", 0); /* EOR */
|
||||
fprintf(fgram, "%d, ", nt_highest);
|
||||
/* First set of the extra nonterm is same as
|
||||
for the term */
|
||||
/* Except that the new nonterm also produces empty ! */
|
||||
save_set((t_list + i)->term->t_nc_first);
|
||||
save_set((t_list + i)->term->t_nc_follow);
|
||||
fprintf(fgram, "1,\n");
|
||||
fprintf(fgram, "%d, ", (t_list+i)->t_nt_num);
|
||||
fprintf(fgram, "%d,\n%d,\n", LLALT, 0); /* ALT EMPTY */
|
||||
break;
|
||||
case OPT:
|
||||
fprintf(fgram, "1,\n");
|
||||
save_rule((t_list + i)->term->t_rule, 0);
|
||||
fprintf(fgram, "%d,\n%d,\n", LLALT, 0); /* ALT EMPTY */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Resolve %substarts */
|
||||
if (!subpars_sim) {
|
||||
int i,s,check;
|
||||
p_start ff, gg;
|
||||
p_set temp_set;
|
||||
|
||||
for (i = 0; i < sub_list_index; i++) {
|
||||
fprintf(fgram, "%d, ", (sub_list + i)->sub_nt_num);
|
||||
/* Compute the first set */
|
||||
temp_set = setalloc();
|
||||
for (ff = g_getsubparse((sub_list + i)->sub_action);
|
||||
ff; ff = ff->ff_next){
|
||||
s = setunion(temp_set,
|
||||
(&nonterms[ff->ff_nont])->n_first);
|
||||
check = 0;
|
||||
for (gg =start; gg; gg = gg->ff_next)
|
||||
if (ff->ff_nont == gg->ff_nont)
|
||||
check = 1;
|
||||
if (check == 0)
|
||||
warning((sub_list + i)->sub_action->g_lineno,
|
||||
"\"%s\" is not a startsymbol",
|
||||
(&nonterms[ff->ff_nont])->n_name);
|
||||
}
|
||||
save_set(temp_set);
|
||||
save_set(temp_set);
|
||||
free(temp_set);
|
||||
|
||||
/* Produces empty */
|
||||
fprintf(fgram, "1,\n");
|
||||
|
||||
ff = g_getsubparse((sub_list + i)->sub_action);
|
||||
|
||||
for (; ff; ff = ff->ff_next)
|
||||
fprintf(fgram, "%d, %d, %d, \n", ff->ff_nont + assval,
|
||||
(sub_list + i)->sub_nt_num,
|
||||
LLALT);
|
||||
fprintf(fgram, "%d, \n", 0);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(fgram, "%d\n};\n", 0);
|
||||
fprintf(fgram, "#define LLNNONTERMINALS %d\n", nt_highest - assval + 1);
|
||||
}
|
||||
|
||||
STATIC
|
||||
save_rule(p, tail) register p_gram p; int tail; {
|
||||
/*
|
||||
Walk through rule p, saving it. The non-terminal tail is
|
||||
appended to the rule. It needs to be appended in this function
|
||||
to process alt-rules correctly. Tail == 0 means don't append.
|
||||
*/
|
||||
|
||||
int in_alt;
|
||||
int illegal_num;
|
||||
/* Processing an alt needs some special care. When processing the
|
||||
first alternative, we don't want to write the alt-code;
|
||||
When appending something to the alt, it needs to be appended to
|
||||
every alternative and not at the end of the rule.
|
||||
*/
|
||||
|
||||
/* Look up the ILLEGAL token number */
|
||||
illegal_num = tokens[g_getcont(illegal_gram)].t_tokno;
|
||||
|
||||
in_alt = 0;
|
||||
for (;;) {
|
||||
switch(g_gettype(p)) {
|
||||
case ALTERNATION :
|
||||
if (in_alt)
|
||||
fprintf(fgram, "%d,\n", LLALT);
|
||||
else
|
||||
in_alt = 1;
|
||||
save_rule(g_getlink(p)->l_rule, tail);
|
||||
break;
|
||||
case TERM :
|
||||
/* Make entry in term list */
|
||||
(t_list + t_list_index)->term = g_getterm(p);
|
||||
/* Test for [] without specifier */
|
||||
if (g_getterm(p) == (struct term *) 0) {
|
||||
t_list_index++;
|
||||
break;
|
||||
}
|
||||
(t_list + t_list_index++)->t_nt_num = ++nt_highest;
|
||||
fprintf(fgram, "%d, ", nt_highest);
|
||||
/* Check if repetition, if so handle here */
|
||||
if (r_getkind(g_getterm(p)) == FIXED)
|
||||
{
|
||||
int k;
|
||||
for (k = 1; k < r_getnum(g_getterm(p)); k++)
|
||||
fprintf(fgram, "%d, ", nt_highest);
|
||||
}
|
||||
break;
|
||||
case NONTERM :
|
||||
fprintf(fgram, "%d, ", g_getcont(p) + assval);
|
||||
break;
|
||||
case TERMINAL:
|
||||
if (g_getcont(p) == g_getcont(illegal_gram)) {
|
||||
/* %illegal. Ignore. */
|
||||
break;
|
||||
}
|
||||
if (p->g_erroneous)
|
||||
fprintf(fgram, "%d, ", illegal_num);
|
||||
else
|
||||
fprintf(fgram, "%d, ",
|
||||
tokens[g_getcont(p)].t_tokno);
|
||||
break;
|
||||
case LITERAL:
|
||||
if (p->g_erroneous)
|
||||
fprintf(fgram, "%d, ", illegal_num);
|
||||
else
|
||||
fprintf(fgram, "%d, ",
|
||||
tokens[g_getcont(p)].t_tokno);
|
||||
break;
|
||||
case ACTION:
|
||||
if (subpars_sim) {
|
||||
fprintf(fgram, "%d, ", act_nt);
|
||||
}
|
||||
else if (g_getsubparse(p)) {
|
||||
/* Allocate nonterminal that will simulate
|
||||
subparser
|
||||
*/
|
||||
(sub_list + sub_list_index)->sub_nt_num =
|
||||
++nt_highest;
|
||||
(sub_list + sub_list_index++)->sub_action = p;
|
||||
|
||||
fprintf(fgram, "%d, ", nt_highest);
|
||||
}
|
||||
break;
|
||||
case EORULE :
|
||||
if ((! in_alt) && tail )
|
||||
/* If this rule is not an alt, append tail now.
|
||||
If it is an alt, the recursive call of this function
|
||||
has appended tail to each alternative
|
||||
*/
|
||||
fprintf(fgram, "%d, ", tail);
|
||||
return;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC
|
||||
save_set(p) p_set p; {
|
||||
register int k;
|
||||
register unsigned i;
|
||||
int j;
|
||||
|
||||
j = nbytes;
|
||||
for (;;) {
|
||||
i = (unsigned) *p++;
|
||||
for (k = 0; k < sizeof(int); k++) {
|
||||
fprintf(fgram,"0%o,",(int)(i & 0377));
|
||||
i >>= 8;
|
||||
if (--j == 0) {
|
||||
fputs("\n",fgram);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user