From ca4cc6fe804bfb12599aea5c48317c8ae3ae5e96 Mon Sep 17 00:00:00 2001 From: ceriel Date: Thu, 3 Oct 1985 10:35:55 +0000 Subject: [PATCH] Initial revision --- util/LLgen/src/LLgen.g | 548 +++++++++++++++++++++++++++++++++++++++++ util/LLgen/src/check.c | 476 +++++++++++++++++++++++++++++++++++ 2 files changed, 1024 insertions(+) create mode 100644 util/LLgen/src/LLgen.g create mode 100644 util/LLgen/src/check.c diff --git a/util/LLgen/src/LLgen.g b/util/LLgen/src/LLgen.g new file mode 100644 index 000000000..5519a4ecb --- /dev/null +++ b/util/LLgen/src/LLgen.g @@ -0,0 +1,548 @@ +/* + * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands. + * + * This product is part of the Amsterdam Compiler Kit. + * + * Permission to use, sell, duplicate or disclose this software must be + * obtained in writing. Requests for such permissions may be sent to + * + * Dr. Andrew S. Tanenbaum + * Wiskundig Seminarium + * Vrije Universiteit + * Postbox 7161 + * 1007 MC Amsterdam + * The Netherlands + * + */ + +/* + * L L G E N + * + * An Extended LL(1) Parser Generator + * + * Author : Ceriel J.H. Jacobs + */ + +/* + * LLgen.g + * Defines the grammar of LLgen. + * Some routines that are included build the internal structure + */ + +{ +# include "types.h" +# include "io.h" +# include "tunable.h" +# include "extern.h" +# include "assert.h" + +# ifndef NORCSID +static string rcsidb = "$Header$"; +# endif +p_mem alloc(); +string store(); +t_gram search(); + +static int nparams; /* parameter count for nonterminals */ +static t_gram elem; /* temporary space */ +static int acount; /* count #of global actions */ + +/* Here are defined : */ +STATIC copyact(); +STATIC unsigned get(); +STATIC t_gram mkalt(); +STATIC t_gram mkterm(); +STATIC p_gram copyrule(); +} + +%start LLparse, spec; + +spec : { acount = 0; } + [ %persistent def ]* + { /* + * Put an endmarker in temporary file + */ + putc('\0',fact); putc('\0',fact); + } + ; + +def { register string p; } + : rule + /* + * A grammar rule + */ + | C_TOKEN listel [ ',' listel ]* ';' + /* + * A token declaration + */ + | C_START C_IDENT + { p = store(lextoken.t_string); } + ',' C_IDENT ';' + /* + * A start symbol declaration + */ + { /* + * Put the declaration in the list + * of start symbols + */ + t_gram temp; + register p_start ff; + + temp = search(NONTERM,lextoken.t_string,BOTH); + ff = (p_start) alloc(sizeof(t_start)); + ff->ff_nont = &nonterms[g_getnont(&temp)]; + ff->ff_name = p; + ff->ff_next = start; + start = ff; + } + | C_LEXICAL C_IDENT + { if (!lexical) { + lexical = store(lextoken.t_string); + } else error(linecount,"Duplicate %%lexical"); + } + ';' + /* + * Declaration of a name for the lexical analyser. + * May appear only once + */ + | action(0) { acount++; } + /* + * A global C-declaration + */ + | firsts + /* + * declarations for macros + */ + ; + +listel : C_IDENT { search(TERMINAL,lextoken.t_string,ENTERING); } + ; + +rule { register p_nont p;} + : /* + * grammar for a production rule + */ + C_IDENT { t_gram temp; + + temp = search(NONTERM,lextoken.t_string,BOTH); + p = &nonterms[g_getnont(&temp)]; + if (p->n_rule) { + error(linecount, + "nonterminal already defined"); + } + /* + * Remember the order in which the nonterminals + * were defined. Code must be generated in that + * order to keep track with the actions on the + * temporary file + */ + *maxorder++ = p - nonterms; + p->n_count = acount; + acount = 0; + p->n_lineno = linecount; + } + [ params(2) { p->n_flags |= PARAMS; + if (nparams > 7) { + error(linecount,"Too many parameters"); + } else p->n_flags |= (nparams << 3); + } + ]? + [ action(0) { p->n_flags |= LOCALS; } + ]? + ':' productions(&(p->n_rule)) ';' + ; + +action(int n;) + /* + * The parameter n is non-zero when the opening and closing + * bracket must be copied along with the action + */ + : '{' { copyact('{','}',n,0); } + '}' + ; + +productions(p_gram *p;) + /* + * One or more alternatives + */ + { p_gram prod; + int conflres = 0; + int t = 0; + int haddefault = 0; + t_gram alts[100]; + register p_gram p_alts = alts; + int o_lc, n_lc; + } : + { n_lc = o_lc = linecount; } + simpleproduction(p,&conflres) + [ '|' { n_lc = linecount; } + [ C_DEFAULT { if (haddefault) { + error(linecount, + "multiple %%default"); + } + haddefault = 1; + t |= DEF; + } + ]? + simpleproduction(&prod,&t) + { if (p_alts - alts >= 97) { + error(n_lc,"Too many alternatives"); + p_alts = alts; + } + *p_alts++ = mkalt(*p,conflres,o_lc); + o_lc = n_lc; + conflres = t; + t = 0; + *p = prod; + } + ]* { if (conflres & ~DEF) { + error(n_lc, + "Resolver on last alternative"); + } + if (p_alts > alts) { + *p_alts++ = mkalt(*p,conflres,n_lc); + g_settype(p_alts,EORULE); + *p = copyrule(alts,p_alts+1-alts); + if (!haddefault) { + ((p_link) pentry[g_getcont(*p)]) + ->l_flag |= DEF; + } + } + } + ; +{ + +STATIC t_gram +mkalt(prod,condition,lc) p_gram prod; { + /* + * Create an alternation, initialise it and return + * a grammar element containing it + */ + register unsigned hulp; + register p_link l; + t_gram r; + + g_init(&r); + hulp = get(sizeof(*l)); + l = (p_link) pentry[hulp]; + l->l_rule = prod; + l->l_flag = condition; + g_setcont(&r,hulp); + g_settype(&r,ALTERNATION); + r.g_lineno = lc; + return r; +} +} + +simpleproduction(p_gram *p; register int *conflres;) + { t_gram rule[100]; + register p_gram p_rule = rule; + t_reps reps; + } : + { r_init(&reps); } + [ + /* + * Optional conflict reslover + */ + C_IF expr { *conflres |= COND; } + | C_PREFER { *conflres |= PREFERING; } + | C_AVOID { *conflres |= AVOIDING; } + ]? + [ %persistent elem + { if (p_rule - rule >= 98) { + error(linecount,"Production too long"); + p_rule = rule; + } + r_setkind(&reps,FIXED); + r_setnum(&reps,0); + } + [ repeats(&reps) + { if (g_gettype(&elem) != TERM) { + *p_rule = elem; + g_settype(p_rule+1,EORULE); + elem = mkterm(copyrule(p_rule,2), + 0, + &reps, + p_rule->g_lineno); + } + } + ]? { if (g_gettype(&elem) == TERM) { + register p_term q; + + q = (p_term) pentry[g_getcont(&elem)]; + q->t_reps = reps; + if (q->t_flags & RESOLVER && + (r_getkind(&reps) == PLUS || + r_getkind(&reps) == FIXED)) { + error(linecount, + "illegal %%while"); + } + if (q->t_flags & PERSISTENT && + r_getkind(&reps) == FIXED) { + error(linecount, + "illegal %%persistent"); + } + } + *p_rule++ = elem; + } + ]* { register p_term q; + + g_settype(p_rule,EORULE); + if (g_gettype(&rule[0]) == TERM && + p_rule-rule == 1) { + q=(p_term)pentry[g_getcont(&rule[0])]; + if (r_getkind(&(q->t_reps))==FIXED && + r_getnum(&(q->t_reps)) == 0) { + *p = q->t_rule; + } + else *p = copyrule(rule,2); + } + else *p = copyrule(rule,p_rule-rule+1); + } + ; +{ + +STATIC t_gram +mkterm(prod,flags,reps,lc) p_gram prod; register p_reps reps; { + /* + * Create a term, initialise it and return + * a grammar element contianing it + */ + register p_term q; + register unsigned hulp; + t_gram r; + + g_init(&r); + hulp = get(sizeof(*q)); + q = (p_term) pentry[hulp]; + q->t_rule = prod; + q->t_contains = 0; + /* "*1" = "?" */ + if (r_getnum(reps) == 1 && r_getkind(reps) == STAR) { + r_setkind(reps,OPT); + } + q->t_reps = *reps; + q->t_flags = flags; + g_settype(&r,TERM); + g_setcont(&r,hulp); + r.g_lineno = lc; + return r; +} +} + +elem { register short t = 0; + p_gram p1; + t_reps reps; + int ln; + } : + '[' { ln = linecount; } + [ C_WHILE expr { t |= RESOLVER; } + ]? + [ C_PERSISTENT { t |= PERSISTENT; } + ]? + productions(&p1) + ']' { r_init(&reps); + elem = mkterm(p1,t,&reps,ln); + } + | %default + C_IDENT { elem = search(UNKNOWN,lextoken.t_string,BOTH); } + [ params(0) { if (nparams > 6) { + error(linecount,"Too many parameters"); + } else g_setnpar(&elem,nparams+1); + if (g_gettype(&elem) == TERMINAL) { + error(linecount, + "Terminal with parameters"); + } + } + ]? + | C_LITERAL { elem = search(LITERAL,lextoken.t_string,BOTH); } + | { g_settype(&elem,ACTION); + elem.g_lineno = linecount; + } + action(1) + ; + +params(int n;) + : '(' { copyact('(',')',n,0); } + ')' + ; + +expr : '(' { copyact('(',')',1,0); } + ')' + ; + +repeats(t_reps *t;) { int t1 = 0; } : + [ + '?' { r_setkind(t,OPT); } + | [ '*' { r_setkind(t,STAR); } + | '+' { r_setkind(t,PLUS); } + ] + number(&t1)? + { if (t1 == 1 && r_getkind(t) == PLUS) { + error(linecount, + "Illegal repetition specifier"); + } + } + | number(&t1) + ] { r_setnum(t,t1); } + ; + +number(int *t;) + : C_NUMBER + { *t = lextoken.t_num; + if (*t <= 0 || *t >= 8192) { + error(linecount,"Illegal number"); + } + } + ; + +firsts { register string p; } + : C_FIRST C_IDENT + { p = store(lextoken.t_string); } + ',' C_IDENT ';' + { /* + * Store this %first in the list belonging + * to this input file + */ + t_gram temp; + register p_first ff; + + temp = search(NONTERM,lextoken.t_string,BOTH); + ff = (p_first) alloc(sizeof(t_first)); + ff->ff_nont = &nonterms[g_getnont(&temp)]; + ff->ff_name = p; + ff->ff_next = pfile->f_firsts; + pfile->f_firsts = ff; + } + ; +{ + +STATIC +copyact(ch1,ch2,flag,level) char ch1,ch2; { + /* + * Copy an action to file f. Opening bracket is ch1, closing bracket + * is ch2. + * If flag = 1, copy opening and closing parameters too. + * If flag = 2, the copy is a parameter declaration copy. + * Give an error message if not ending on a ';' + */ + register FILE *f; + register ch; /* Current char */ + register match; /* used to read strings */ + int saved; /* save linecount */ + int semicolon = 0; + + f = fact; + if (!level) { + saved = linecount; + nparams = 0; /* count comma's */ + putc('\0',f); + fprintf(f,"# line %d \"%s\"\n", linecount,f_input); + if (flag == 1) putc(ch1,f); + } + else putc(ch1,f); + for (;;) { + ch = input(); + if (ch == ch2) { + if (!level) unput(ch); + if (level || flag == 1) putc(ch,f); + if ((!level) && flag == 2 && !semicolon) { + error(linecount,"missing ';'"); + } + return; + } + if (! isspace(ch)) semicolon = 0; + switch(ch) { + case ')': + case '}': + case ']': + error(linecount,"Parentheses mismatch"); + break; + case '(': + copyact('(',')',flag,level+1); + continue; + case '{': + copyact('{','}',flag,level+1); + continue; + case '[': + copyact('[',']',flag,level+1); + continue; + case '/': + ch = input(); + unput(ch); + if (ch == '*') { + skipcomment(1); + continue; + } + break; + case ';': + semicolon = 1; + /* Fall through */ + case ',': + if (!level) { /* + * Only ','s and ';'s on the + * outer level are counted + */ + nparams++; + } + break; + case '\'': + case '"' : + /* + * watch out for brackets in strings, they do not + * count ! + */ + match = ch; + putc(ch,f); + while((ch = input())) { + if (ch == match) break; + if (ch == '\\') { + putc(ch,f); + ch = input(); + } + if (ch == '\n') { + error(linecount,"newline in string"); + unput(match); + } + putc(ch,f); + } + if (ch == match) break; + /* Fall through */ + case EOF : + if (!level) error(saved,"Action does not terminate"); + return; + } + putc(ch,f); + } +} + +static int ecount; /* Index in "pentry" array */ +STATIC unsigned +get(size) unsigned size; { + /* + * Get some core, save a pointer to it in "pentry", + * return index in pentry + */ + + if (ecount >= ENTSIZ) fatal(linecount,"Entry table overflow"); + pentry[ecount] = alloc(size); + return ecount++; +} + +STATIC p_gram +copyrule(p,length) register p_gram p; register length; { + /* + * Returns a pointer to a grammar rule that was created in + * p. The space pointed to by p can now be reused + */ + register p_gram t; + p_gram rule; + + t = (p_gram) alloc((unsigned) length * sizeof(t_gram)); + rule = t; + while (length--) { + *t++ = *p++; + } + return rule; +} +} diff --git a/util/LLgen/src/check.c b/util/LLgen/src/check.c new file mode 100644 index 000000000..9d3a5b95a --- /dev/null +++ b/util/LLgen/src/check.c @@ -0,0 +1,476 @@ +/* + * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands. + * + * This product is part of the Amsterdam Compiler Kit. + * + * Permission to use, sell, duplicate or disclose this software must be + * obtained in writing. Requests for such permissions may be sent to + * + * Dr. Andrew S. Tanenbaum + * Wiskundig Seminarium + * Vrije Universiteit + * Postbox 7161 + * 1007 MC Amsterdam + * The Netherlands + * + */ + +/* + * L L G E N + * + * An Extended LL(1) Parser Generator + * + * Author : Ceriel J.H. Jacobs + */ + +/* + * check.c + * Several routines to perform checks and printouts + */ + +# include "types.h" +# include "extern.h" +# include "tunable.h" +# include "io.h" +# include "sets.h" +# include "assert.h" + +# ifndef NORCSID +static string rcsid1 = "$Header$"; +# endif + +# define PTERM(p) fprintf(fout,(p)->h_num < 0400 ? "'%s' " : "%s ",(p)->h_name); + +static string c_first = "> firstset "; +static string c_contains = "> containset "; +static string c_follow = "> followset "; +p_set setalloc(); +static string ntname; /* nonterminal that is currently checked */ +static p_nont nt; /* pointer to its struct */ +static int level; + +/* In this file are defined : */ +extern conflchecks(); +STATIC newline(); +STATIC printset(); +STATIC check(); +STATIC moreverbose(); +STATIC prrule(); +STATIC cfcheck(); +STATIC resolve(); +STATIC propagate(); +STATIC spaces(); + +conflchecks() { + /* + * Check for conflicts, that is, + * in a repeating term, the FIRST and FOLLOW must be disjunct, + * unless there is a disambiguating condition. + * in an alternation, the sets that determine the direction to take, + * must be disjunct. + */ + register p_nont p; + register FILE *f; + register short *s; + p_file x = files; + + f_input = x->f_name; + if (verbose >= 3) { + for (p = nonterms; p < maxnt; p++) p->n_flags |= VERBOSE; + } + if (verbose) { + if ((f = fopen(f_out,"w")) == NULL) fatal(1,e_noopen,f_out); + fout = f; + } + /* + * Check the rules in the order in which they are declared, + * and input file by input file, to give proper error messages + */ + for (; x->f_end < maxorder; x++) { + f_input = x->f_name; +# ifndef NDEBUG + if (debug) fprintf(stderr, "CHECK: file %s\n", f_input); +# endif + for (s = x->f_start; s <= x->f_end; s++) { + nt = p = &nonterms[*s]; + ntname = (min_nt_ent + *s)->h_name; +# ifndef NDEBUG + if (debug) fprintf(stderr,"CHECK: nonterminal %s\n", ntname); +# endif + if (p->n_flags & RECURSIVE) { + error(p->n_lineno, + "Recursion in default for nonterminal %s", + ntname); + } + check(p->n_rule); + /* + * If a printout is needed for this rule in + * LL.output, just do it + */ + if (verbose && (p->n_flags & VERBOSE)) { + fprintf(f,"\n%s :\n",ntname); + printset(p->n_first,c_first); + printset(p->n_contains,c_contains); + printset(p->n_follow,c_follow); + fputs("> rule\n\t",f); + level = 8; + prrule(p->n_rule); + level = 0; + newline(); + } + /* + * Now, the conflicts may be resolved + */ + resolve(p->n_rule); + } + } + if (verbose) fclose(f); +} + +STATIC +newline() { + /* + * Newline and "level" spaces indentation + */ + if (level > 0) fprintf(fout,"\n%*c",level,' '); + else putc('\n',fout); +} + +STATIC +printset(p,s) register p_set p; string s; { + /* + * Print the elements of a set + */ + register FILE *f; + register i; + register j; + int k; + int hulp; + + k = strlen(s)+1; + /* + * k contains relative level of indentation + */ + f = fout; + fprintf(f,"%s{ ",s); + j = level+1+k; + /* + * j will gather the total length of the line + */ + if (p == (p_set) 0) fputs(">non existent (yet?)< ",f); + else { + for (i = 0; i < nterminals; i++) { + if (IN(p,i)) { + hulp = strlen(h_entry[i].h_name)+1; + if (h_entry[i].h_num < 0400) hulp += 2; + if ((j += hulp) >= 78) { + /* + * Line becoming too long + */ + j = level+k+1+hulp; + newline(); + fprintf(f,">%*c",k,' '); + } + PTERM(&h_entry[i]); + } + } + if (ntprint) for (i = 0; i < nnonterms; i++) { + /* + * Nonterminals in the set must also be printed + */ + if (NTIN(p,i)) { + hulp = strlen((min_nt_ent+i)->h_name)+3; + if ((j += hulp) >= 78) { + j = level + k + 1 + hulp; + newline(); + fprintf(f,">%*c",k,' '); + } + fprintf(f,"<%s> ",(min_nt_ent+i)->h_name); + } + } + } + putc('}',f); + newline(); +} + +STATIC +check(p) register p_gram p; { + /* + * Search for conflicts in a grammar rule. + */ + p_set temp; + + for (;;) { + switch (g_gettype(p)) { + case EORULE : + return; + case NONTERM : + if (g_getnpar(p)!=((nonterms[g_getnont(p)].n_flags&077) >> 3)){ + error(p->g_lineno, + "Call of %s : parameter count mismatch", + (min_nt_ent+g_getnont(p))->h_name); + } + break; + case TERM : { + register p_term q; + + q = (p_term) pentry[g_getcont(p)]; + check(q->t_rule); + if (r_getkind(&(q->t_reps)) == FIXED) break; + if (setempty(q->t_first)) { + q->t_flags |= EMPTYFIRST; + nt->n_flags |= VERBOSE; + error(p->g_lineno, "No symbols in term"); + } + if (empty(q->t_rule)) { + q->t_flags |= EMPTYTERM; + nt->n_flags |= VERBOSE; + error(p->g_lineno, "Term produces empty"); + } + temp = setalloc(setsize); + setunion(temp,q->t_first,setsize); + if (!setintersect(temp,q->t_follow,setsize)) { + /* + * q->t_first * q->t_follow != EMPTY + */ + if (!(q->t_flags & RESOLVER)) { + /* + * No conflict resolver + */ + error(p->g_lineno, + "Repitition conflict"); + nt->n_flags |= VERBOSE; + if (verbose == 2) moreverbose(temp); + } + } else { + if (q->t_flags & RESOLVER) { + q->t_flags |= NOCONF; + error(p->g_lineno, + "%%while, no conflict"); + nt->n_flags |= VERBOSE; + } + } + free((p_mem) temp); + break; } + case ALTERNATION : { + register p_link l; + + l = (p_link) pentry[g_getcont(p)]; + temp = setalloc(setsize); + setunion(temp,l->l_symbs,setsize); + if(!setintersect(temp,l->l_others,setsize)) { + /* + * temp now contains the conflicting + * symbols + */ + if (!(l->l_flag & (COND|PREFERING|AVOIDING))) { + error(p->g_lineno, + "Alternation conflict"); + nt->n_flags |= VERBOSE; + if (verbose == 2) moreverbose(temp); + } + } else { + if (l->l_flag & (COND|PREFERING|AVOIDING)) { + l->l_flag |= NOCONF; + error(p->g_lineno,"No conflict"); + nt->n_flags |= VERBOSE; + } + } + free( (p_mem) temp); + check(l->l_rule); + break; } + } + p++; + } +} + +STATIC +moreverbose(t) register p_set t; { + /* + * t points to a set containing conflicting symbols and pssibly + * also containing nonterminals. + * Take care that a printout will be prepared for these nonterminals + */ + register i; + + if (verbose) for (i = 0; i < nnonterms; i++) { + if (NTIN(t,i)) nonterms[i].n_flags |= VERBOSE; + } +} + +STATIC +prrule(p) register p_gram p; { + /* + * Create a verbose printout of grammar rule p + */ + register FILE *f; + int present = 0; + + f = fout; + for (;;) { + switch (g_gettype(p)) { + case EORULE : + putc('\n',f); + return; + case TERM : { + register p_term q; + register c; + + q = (p_term) pentry[g_getcont(p)]; + if (present) newline(); + if (r_getkind(&(q->t_reps)) != FIXED || + r_getnum(&(q->t_reps)) != 0) { + fputs("[ ",f); + level += 4; + if (q->t_flags & RESOLVER) { + fputs("%%while (..)",f); + newline(); + } + if (r_getkind(&(q->t_reps)) != FIXED) { + printset(q->t_first, c_first); + printset(q->t_contains, c_contains); + printset(q->t_follow,c_follow); + if (q->t_flags & EMPTYFIRST) { + fputs(">>> empty first",f); + newline(); + } + if (q->t_flags & EMPTYTERM) { + fputs(">>> term produces empty",f); + newline(); + } + cfcheck(q->t_first,q->t_follow, + q->t_flags & RESOLVER); + } + prrule(q->t_rule); + level -= 4; + spaces(); + c = r_getkind(&(q->t_reps)); + putc(']',f); + if (c != FIXED) { + c = (c==STAR)?'*':(c==PLUS)?'+':'?'; + putc(c,f); + } + if (c = r_getnum(&(q->t_reps))) { + fprintf(f,"%d",c); + } + newline(); + } else { + prrule(q->t_rule); + spaces(); + } + break; } + case ACTION : + fputs("{..} ",f); + break; + case ALTERNATION : { + register p_link l; + + l = (p_link) pentry[g_getcont(p)]; + if (l->l_flag & (COND|PREFERING|AVOIDING)) { + printset(l->l_symbs,"> alt with resolver on "); + } else printset(l->l_symbs,"> alternative on "); + cfcheck(l->l_symbs, + l->l_others, + (int)(l->l_flag&(COND|PREFERING|AVOIDING))); + fputs(" ",f); + level += 4; + prrule(l->l_rule); + level -= 4; + spaces(); + if (g_gettype(p+1) == EORULE) { + fputs("> end alternatives\n",f); + return; + } + p++; continue; } + case TERMINAL : + PTERM(&h_entry[g_getcont(p)]); + break; + case NONTERM : + fprintf(f,"%s ",(g_getnont(p)+min_nt_ent)->h_name); + break; + } + p++; + present = 1; + } +} + +STATIC +cfcheck(s1,s2,flag) p_set s1,s2; { + /* + * Check if s1 and s2 have elements in common. + * If so, flag must be non-zero, indicating that there is a + * conflict resolver, otherwise, flag must be zero, indicating + * that there is not. + */ + register p_set temp; + + temp = setalloc(setsize); + setunion(temp,s1,setsize); + if (!setintersect(temp,s2,setsize)) { + if (! flag) { + printset(temp,">>> conflict on "); + newline(); + } + } else { + if (flag) { + fputs(">>> %if/%while, no conflict",fout); + newline(); + } + } + free((p_mem) temp); +} + +STATIC +resolve(p) register p_gram p; { + /* + * resolve conflicts, as specified by the user + */ + for (;;) { + switch (g_gettype(p)) { + case EORULE : + return; + case TERM : + resolve(((p_term) pentry[g_getcont(p)])->t_rule); + break; + case ALTERNATION : { + register p_link l; + + l = (p_link) pentry[g_getcont(p)]; + if (l->l_flag & AVOIDING) { + /* + * On conflicting symbols, this rule + * is never chosen + */ + setminus(l->l_symbs,l->l_others,setsize); + } + if (setempty(l->l_symbs)) { + /* + * This may be caused by the statement above + */ + error(p->g_lineno,"Alternative never chosen"); + } + resolve(l->l_rule); + if (l->l_flag & PREFERING) propagate(l->l_symbs,p+1); + break; } + } + p++; + } +} + +STATIC +propagate(set,p) p_set set; register p_gram p; { + /* + * Propagate the fact that on the elements of set the grammar rule + * p will not be chosen. + */ + while (g_gettype(p) != EORULE) { + setminus(((p_link) pentry[g_getcont(p)])->l_symbs,set,setsize); + p++; + } +} + +STATIC +spaces() { + + if (level > 0) fprintf(fout,"%*c",level,' '); +} -- 2.34.1