Initial revision
authorceriel <none@none>
Thu, 3 Oct 1985 10:35:55 +0000 (10:35 +0000)
committerceriel <none@none>
Thu, 3 Oct 1985 10:35:55 +0000 (10:35 +0000)
util/LLgen/src/LLgen.g [new file with mode: 0644]
util/LLgen/src/check.c [new file with mode: 0644]

diff --git a/util/LLgen/src/LLgen.g b/util/LLgen/src/LLgen.g
new file mode 100644 (file)
index 0000000..5519a4e
--- /dev/null
@@ -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 (file)
index 0000000..9d3a5b9
--- /dev/null
@@ -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,' ');
+}