ack/util/LLgen/src/savegram.c

387 lines
9 KiB
C

/* 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 <stdlib.h>
# 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 void save_rule();
STATIC void 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 void
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 void
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