BSD 1 development
authorCharles B. Haley <cbh@research.uucp>
Wed, 23 Nov 1977 20:45:18 +0000 (12:45 -0800)
committerCharles B. Haley <cbh@research.uucp>
Wed, 23 Nov 1977 20:45:18 +0000 (12:45 -0800)
Work on file eyacc/ey0.c
Work on file eyacc/ey3.c
Work on file eyacc/ey1.c
Work on file eyacc/ey2.c
Work on file eyacc/READ_ME
Work on file eyacc/ey.h
Work on file eyacc/ey5.c

Co-Authored-By: Bill Joy <wnj@ucbvax.Berkeley.EDU>
Synthesized-from: 1bsd

eyacc/READ_ME [new file with mode: 0644]
eyacc/ey.h [new file with mode: 0644]
eyacc/ey0.c [new file with mode: 0644]
eyacc/ey1.c [new file with mode: 0644]
eyacc/ey2.c [new file with mode: 0644]
eyacc/ey3.c [new file with mode: 0644]
eyacc/ey5.c [new file with mode: 0644]

diff --git a/eyacc/READ_ME b/eyacc/READ_ME
new file mode 100644 (file)
index 0000000..4d953a6
--- /dev/null
@@ -0,0 +1,27 @@
+August 28, 1977
+
+This directory contains source for a version of yacc needed by the Pascal
+parser.  The differences between this yacc and a stadard version 6 yacc
+are indicated in a comment in y1.c.
+
+Note that the standard yacc parser will not work on the tables produced
+by "eyacc" and also that these changes are really useful only with
+a fairly large set of error recovery routines which are part of both
+"pi" and "pxp".  The routines are language independent, but the method
+will only work on languages which have some redundancy in them... it is
+probably ill suited for C, but would work fine in ALGOL-60, ALGOL-W,
+EUCLID, LIS, SP/K, PL/1, ALPHARD, CLU, ...
+
+I am working on a short document describing the internals of the error
+recovery technique used in "pi"... It is a simple modification of the
+Graham/Rhodes technique described in a recent article in the CACM.
+
+
+                               Bill Joy
+                               Computer Science Division
+                               EECS Department
+                               University of California, Berkeley
+                               Berkeley, California  94704
+
+                               Office: (415) 642-4948
+                               Home:   (415) 524-4510
diff --git a/eyacc/ey.h b/eyacc/ey.h
new file mode 100644 (file)
index 0000000..6905b7d
--- /dev/null
@@ -0,0 +1,124 @@
+#
+/*  MANIFEST CONSTANT DEFINITIONS */
+
+# define NTBASE 010000
+
+  /* internal codes for error and accept actions */
+
+# define ERRCODE  8190
+# define ACCEPTCODE 8191
+
+# define errfileno 1      /* file number for erros and reduction message */
+# define _tbitset 6  /* 16*_tbitset - 1 >= _nterms */
+
+extern int tbitset;  /* number of wds of lookahead vector */
+extern int nolook;  /* flag to turn off lookahed computations */
+struct looksets { int lset[ _tbitset ]; } ;
+struct item { int *pitem; struct looksets *look; } ;
+
+  /* output actions */
+
+# define ERRACT 4096
+# define SHIFTACT 8192
+# define REDUCACT 12288
+# define ACCEPTACT 16384
+
+# define _REGISTER register
+
+extern int nstate ;            /* number of states */
+extern struct item *pstate[];  /* pointers to the descriptions of the states */
+extern int apstate[];          /* index to actions in amem by state */
+extern int actsiz;     /* size of the action table array */
+extern int tystate[];  /* contains type information about the states */
+  /* 0 = simple state, completely generated
+     1 = state awaiting generation
+     2 = state with an empty production in closure 
+     */
+extern int stsize ;    /* maximum number of states, at present */
+extern int memsiz ;    /* maximum size for productions and states */
+extern int mem0[] ; /* added production */
+extern int *mem ;
+extern int amem[];  /* action table storage */
+extern int actsiz;  /* action table size */
+extern int memact ;            /* next free action table position */
+extern int nprod ;     /* number of productions */
+extern int *prdptr[];  /* pointers to descriptions of productions */
+extern int prdlim; /* the number of productions allowed */
+extern int levprd[] ;  /* contains production levels to break conflicts */
+  /* last two bits code associativity:
+       0 = no definition
+       1 = left associative
+       2 = binary
+       3 = right associative
+     bit 04 is 1 if the production has an action
+     the high 13 bits have the production level
+     */
+extern int nterms ;    /* number of terminals */
+extern int nerrors;    /* number of errors */
+extern int fatfl;      /* if on, error is fatal */
+  /*   the ascii representations of the terminals      */
+extern int extval;  /* start of output values */
+extern struct sxxx1 {char *name; int value;} trmset[];
+extern char cnames[];
+extern int cnamsz;
+extern char *cnamp;
+extern int maxtmp ;    /* the size of the temp arrays */
+ /* temporary vectors, indexable by states, terms, or nterms */
+extern int temp1[];
+extern int temp2[];
+extern int trmlev[];   /* vector with the precedence of the terminals */
+  /* The levels are the same as for levprd, but bit 04 is always 0 */
+  /* the ascii representations of the nonterminals */
+extern struct sxxx2 { char *name; } nontrst[];
+extern int indgo[];            /* index to the stored goto table */
+extern int ***pres; /* vector of pointers to the productions yielding each nonterminal */
+extern struct looksets **pfirst; /* vector of pointers to first sets for each nonterminal */
+extern int *pempty ; /* table of nonterminals nontrivially deriving e */
+extern int nnonter ;   /* the number of nonterminals */
+extern int lastred ;   /* the number of the last reduction of a state */
+extern int ftable;             /* y.tab.c file */
+extern int foutput;            /* y.output file */
+extern int cin;                /* current input file */
+extern int cout;               /* current output file */
+extern int arrndx;
+extern int zzcwset;
+extern int zzpairs ;
+extern int zzgoent ;
+extern int zzgobest ;
+extern int zzacent ;
+extern int zzacsave ;
+extern int zznsave ;
+extern int zzclose ;
+extern int zzrrconf ;
+extern int zzsrconf ;
+extern char *ctokn;
+struct {int **ppi;} ;
+extern int ntlim ;     /* maximum number of nonterminals */
+extern int tlim ;      /* maximum number of terminals */
+extern int lineno; /* current line number */
+extern int peekc; /* look-ahead character */
+extern int tstates[];
+extern int ntstates[];
+extern int mstates[];
+
+extern struct looksets clset;
+extern struct looksets lkst[];
+extern int nlset;  /* next lookahead set index */
+extern int lsetsz; /* number of lookahead sets */
+
+extern struct wset { int *pitem, flag, ws[ _tbitset ]; } wsets[];
+extern int cwset;
+extern int wssize;
+
+extern int numbval;  /* the value of an input number */
+extern int rflag;  /* ratfor flag */
+extern int oflag;  /* optimization flag */
+extern int ndefout;  /* number of defined symbols output */
+
+extern int machine;
+
+# define UNIX 1
+# define GCOS 2
+# define IBM 3
+
+struct looksets *flset();
diff --git a/eyacc/ey0.c b/eyacc/ey0.c
new file mode 100644 (file)
index 0000000..b260717
--- /dev/null
@@ -0,0 +1,103 @@
+# define _actsize 2500
+# define _memsize 3000
+# define _nstates 700
+# define _nterms 95
+# define _nprod 300
+# define _nnonterm 150
+# define _tempsize 700
+# define _cnamsz 3500
+# define _lsetsize 600
+# define _wsetsize 400
+
+# define _tbitset 6
+
+int tbitset;  /* size of lookahed sets */
+int nolook 0; /* flag to suppress lookahead computations */
+struct looksets { int lset[ _tbitset ]; } ;
+struct item { int *pitem; } ;
+
+/* this file contains the definitions for most externally known data */
+
+int nstate 0;          /* number of states */
+struct item *pstate[_nstates]; /* pointers to the descriptions of the states */
+int apstate[_nstates]; /* index to the actions for the states */
+int tystate[_nstates]; /* contains type information about the states */
+int stsize _nstates;   /* maximum number of states, at present */
+int memsiz _memsize;   /* maximum size for productions and states */
+int mem0[_memsize] ; /* production storage */
+int *mem mem0;
+int amem[_actsize];  /* action table storage */
+int actsiz _actsize; /* action table size */
+int memact 0;          /* next free action table position */
+int nprod 1;   /* number of productions */
+int *prdptr[_nprod];   /* pointers to descriptions of productions */
+int prdlim _nprod ;  /* the maximum number of productions */
+       /* levprd - productions levels to break conflicts */
+int levprd[_nprod] {0,0};
+  /* last two bits code associativity:
+       0 = no definition
+       1 = left associative
+       2 = binary
+       3 = right associative
+     bit 04 is 1 if the production has an action
+     the high 13 bits have the production level
+     */
+int nterms 0;  /* number of terminals */
+int tlim _nterms ; /* the maximum number of terminals */
+/*     the ascii representations of the terminals      */
+int extval 0;  /* start of output values */
+struct sxxx1 {char *name; int value;} trmset[_nterms];
+char cnames[_cnamsz];
+int cnamsz _cnamsz;
+char *cnamp;
+int maxtmp _tempsize;  /* the size of the temp1 array */
+int temp1[_tempsize]; /* temporary storage, indexed by terms + nterms or states */
+int temp2[_nnonterm]; /* temporary storage indexed by nonterminals */
+int trmlev[_nterms];   /* vector with the precedence of the terminals */
+  /* The levels are the same as for levprd, but bit 04 is always 0 */
+/* the ascii representations of the nonterminals */
+struct sxxx2 { char *name; } nontrst[_nnonterm];
+int ntlim _nnonterm ; /* limit to the number of nonterminals */
+int indgo[_nstates];           /* index to the stored goto table */
+int ***pres; /* vector of pointers to the productions yielding each nonterminal */
+struct looksets **pfirst; /* vector of pointers to first sets for each nonterminal */
+int *pempty 0 ; /* table of nonterminals nontrivially deriving e */
+int nnonter -1;        /* the number of nonterminals */
+int lastred 0; /* the number of the last reduction of a state */
+int ftable;            /* y.tab.c file */
+int foutput;           /* y.output file */
+int arrndx; /* used in the output of arrays on y.tab.c */
+int zzcwset 0;
+int zzpairs 0;
+int zzgoent 0;
+int zzgobest 0;
+int zzacent 0;
+int zzacsave 0;
+int zznsave 0;
+int zzclose 0;
+int zzsrconf 0;
+int zzrrconf 0;
+char *ctokn;
+int lineno 1; /* current input line number */
+int peekc -1; /* look-ahead character */
+int tstates[ _nterms ]; /* states generated by terminal gotos */
+int ntstates[ _nnonterm ]; /* states generated by nonterminal gotos */
+int mstates[ _nstates ]; /* chain of overflows of term/nonterm generation lists  */
+
+struct looksets clset;
+struct looksets lkst [ _lsetsize ];
+int nlset 0; /* next lookahead set index */
+int lsetsz _lsetsize; /* number of lookahead sets */
+
+struct wset { int *pitem, flag, ws[_tbitset]; } wsets[ _wsetsize ];
+int cwset;
+int wssize _wsetsize;
+
+int numbval;  /* the value of an input number */
+int rflag 0;  /* ratfor flag */
+int oflag 0;  /* optimization flag */
+
+int ndefout 3;  /* number of defined symbols output */
+int nerrors 0; /* number of errors */
+int fatfl 1;   /* if on, error is fatal */
+int machine;   /* has a number describing the machine */
diff --git a/eyacc/ey1.c b/eyacc/ey1.c
new file mode 100644 (file)
index 0000000..e8fb2bc
--- /dev/null
@@ -0,0 +1,321 @@
+# include "ey.h"
+  /*     * * * *    e y a c c     * * * *     */
+
+  /**** NB -----
+   *
+   * This version of yacc, known as "eyacc" has been slightly but
+   * importantly modified to allow error recovery in the UNIX Pascal
+   * translator "pi" and also in "pix".
+   *
+   * Changes here include:
+   *
+   * 1) Enumeration of test actions when "error" is an input token.
+   *
+   * 2) Change to the encoding of the action entries.  Test entries
+   *    are encoded as the arithmetic inverse of the symbol being tested
+   *   for.  This is an optimization that makes the parser run at the
+   *   same speed even though, with error productions and enumerated
+   *   lookaheads, it would normally be much slower.  Of course the
+   *   same thing could be done to the regular yacc...
+   *
+   * 3) Different table sizes
+   *
+   * 4) Recognizes form feeds
+   *
+   * 5) Also most of the numbers for the sizes of the tables have been
+   *   increased, to an extent to allow for "eyacc"ing of the Pascal grammar
+   *   and of a grammar which I have for "EUCLID".
+   *
+   *   There seem to be subtle dependencies between the various magic
+   *   numbers... I found some of them but to be safe most of the limits
+   *   are very generous... for this reason "eyacc" will most likely
+   *   have to run separate i/d... no matter.
+   *
+   *                                   Bill Joy
+   *                                   Computer Science Division
+   *                                   EECS Department
+   *                                   University of California, Berkeley
+   *                                   Berkeley, California  94704
+   *   
+   *                                   Office: (415) 642-4948
+   *                                   Home:   (415) 524-4510
+   ****/
+
+  /*      features to be fixed up ...
+
+  ***  Print estimate of total space needed for parser
+  ***  Either list inputs on y.output, or list empty prdn's in states
+  ***  Mention nonterms not used (or, rules. not reduced) as nonfatal error
+  ***  Output states where conflicts were found by default on y.output
+  ***  Engage in newspeak: production=>grammar rules, term=>token, etc.
+  ***  handle # define, #ifdef, etc., in yacc actions, %{ %}
+  */
+
+  /*      new features to be added
+
+  ***  reductions by single productions ( by request )
+  ***  follow sets for start symbol
+  ***  option to only do slr(1)
+  ***  easily changed array names on output
+  ***  allocate core, rather than predefined
+  ***  input controlled by a grammar
+  ***  support multiple choices for  conflicts
+  ***  better conflict diagnostics
+  */
+
+
+
+main(argc,argv) int argc; char *argv[]; {
+  auto int n;
+
+  whereami();
+  setup(argc,argv); /* initialize and read productions */
+  tbitset = (nterms+16)/16;
+  cpres(); /* make table of which productions yield a given nonterminal */
+  cempty(); /* make a table of which nonterminals can match the empty string */
+  cpfir(); /* make a table of e free first lists */
+  stagen(); /* generate the states */
+  output();  /* write the states and the tables */
+  go2out();
+  summary();
+  windup();
+  }
+
+whereami(){ /* sets the variable machine to UNIX, GCOS, or IBM */
+
+  int i;
+
+  i = 1;
+  i = i << 30;
+  if( i == 0 ) {
+    machine = UNIX;
+    return;
+    }
+  i = i << 4;
+  if( i == 0 ){
+    machine = IBM;
+    return;
+    }
+  machine = GCOS;
+  }
+
+windup(){
+  /* no errors, do the optimization if appropriate */
+  char *cp;
+  int i;
+
+  cflush(1);
+  if( !oflag ) cexit(0);
+
+  for( i=3; i<10; ++i ) cclose(i);
+  switch( machine ){
+
+  case GCOS:
+    if( rflag ){
+      if( foutput<0 ) system( "./yopt -r" );
+      else system( "./yopt -rv" );
+      }
+    else {
+      if( foutput<0 ) system( "./yopt" );
+      else system( "./yopt -v" );
+      }
+    cexit(0);  /* terminate */
+
+  case UNIX:
+    cp = "/usr/nlib/yaccopt";
+    if( rflag ) execl( cp, cp, (foutput<0)?"-r":"-rv", 0 );
+    else if( foutput<0 ) execl( cp, cp, 0 );
+    else execl( cp, cp, "-v", 0 );
+    error( "optimization execl call fails" );
+
+  case IBM:
+    if( rflag ){
+      if( foutput<0 ) system( "MH2019.yaccopt -r" );
+      else system( "MH2019.yaccopt -rv" );
+      }
+    else {
+      if( foutput<0 ) system( "MH2019.yaccopt" );
+      else system( "MH2019.yaccopt -v" );
+      }
+    cexit(0);
+
+    }
+
+  }
+
+settty()
+/*     sets the output file to y.output */
+{      
+       cflush( foutput );  /* a bit of a cheat */
+       cout = foutput;
+       }
+
+settab(){ /* sets the output file to y.tab.c */
+       
+       cflush( ftable );
+       cout = ftable;
+       }
+
+char *chcopy( p, q )  char *p, *q; {
+       /* copies string q into p, returning next free char ptr */
+       while( *p = *q++ ) ++p;
+       return( p );
+       }
+
+char *writem(pp) struct item *pp; { /* creates output string for item pointed to by pp */
+       int i,*p;
+       static char sarr[100];
+       char *q;
+
+       for( p=pp->pitem; *p>0 ; ++p ) ;
+       p = prdptr[-*p];
+       q = chcopy( sarr, nontrst[*p-NTBASE].name );
+       q = chcopy( q, " : " );
+
+       for(;;){
+               *q++ = ++p==(pp->pitem) ? '_' : ' ';
+               if((i = *p) <= 0) break;
+               q = chcopy( q, symnam(i) );
+               }
+
+       *q = '\0' ;
+       return( sarr );
+       }
+
+char *symnam(i){ /* return a pointer to the name of symbol i */
+       char *cp;
+
+       cp = (i>=NTBASE) ? nontrst[i-NTBASE].name : trmset[i].name ;
+       if( *cp == ' ' ) ++cp;
+       return( cp );
+       }
+
+summary(){ /* output the summary on the tty */
+
+  int i, s, *pn;
+  
+
+       if( !rflag ){
+               settab();
+               printf("\nint nterms %d;",nterms);
+               printf("\nint nnonter %d;", nnonter);
+               printf("\nint nstate %d;", nstate);
+               printf("\nchar *yysterm[] {");
+               for (i=1;i<=nterms;i++) if( trmset[i].value >= 0400 ) printf("\n\"%s\",",symnam(i));
+               printf( "\n0 };\n" );
+               printf("\nchar *yysnter[] {");
+               for (i=0;i<nnonter;i++) printf("\n\"%s\",",nontrst[i].name);
+               printf("\n\"%s\" };\n",nontrst[nnonter].name);
+               }
+
+  settty();
+  printf("\n%d/%d terminals, %d/%d nonterminals\n", nterms, tlim,
+      nnonter, ntlim );
+  printf("%d/%d grammar rules, %d/%d states\n", nprod, prdlim, nstate, stsize );
+  printf("%d shift/reduce, %d reduce/reduce conflicts reported\n", zzsrconf, zzrrconf );
+  pn = pstate[nstate+1];
+  printf("%d/%d working sets used\n", zzcwset,  wssize );
+  printf("memory: states,etc. %d/%d, parser %d/%d\n", pn-mem0, memsiz,
+      memact, actsiz );
+  printf("%d/%d distinct lookahead sets\n", nlset, lsetsz );
+  printf("%d extra closures\n", zzclose - 2*nstate );
+  printf("%d action entries\n", zzacent );
+  printf("%d action entries saved through merging %d states\n",zzacsave,zznsave);
+  printf("%d goto entries\n", zzgoent );
+  printf("%d entries saved by goto default\n", zzgobest );
+  if( zzsrconf!=0 || zzrrconf!=0 ){
+    cflush( errfileno );
+    cout = errfileno;
+    printf("\nconflicts: ");
+    if( zzsrconf )printf( "%d shift/reduce" , zzsrconf );
+    if( zzsrconf && zzrrconf )printf( ", " );
+    if( zzrrconf )printf( "%d reduce/reduce" , zzrrconf );
+    printf( "\n" );
+    }
+  }
+
+error(s,a1){ /* write out error comment */
+       
+       int c;
+       ++nerrors;
+       cflush( errfileno );
+       cout = errfileno;   /* set output to tty */
+       printf("\n fatal error: ");
+       printf(s,a1);
+        printf(", line %d\n", lineno );
+       if( !fatfl ) return;
+       summary();
+       cexit(1);
+       }
+
+arrset(s) char s[]; {
+       printf("\nint %s[] {0", s );
+       arrndx = 1;
+       }
+
+arrval(n){
+       printf(",%d",n);
+       if( (++arrndx%10) == 0 ) printf("\n");
+       }
+
+arrdone(){
+       printf(",-1};\n");
+       }
+
+copy(v) char *v; {     /* copy ctokn to v */
+       char *p;
+
+       p=ctokn;
+       while( *v++ = *p++ );
+       }
+
+compare(v) char *v; {  /* compare ctokn with v */
+       char *p;
+
+       for( p=ctokn; ; ++p ){
+               if( *p != *v++ ) return( 0 );
+               if( *p == 0 ) return(1);
+               }
+       }
+
+int *yalloc(n){ /* allocate n+1 words from vector mem */
+       int *omem;
+       omem = mem;
+       mem =+ n+1;
+       if(mem-mem0 >= memsiz) error("memory overflow");
+       return(omem);
+       }
+
+aryfil( v, n, c ) int *v,n,c; { /* set elements 0 through n-1 to c */
+  int i;
+  for( i=0; i<n; ++i ) v[i] = c;
+  }
+
+union( a, b, c ) int *a, *b, *c; {
+  /* set a to the union of b and c */
+  /* a may equal b */
+  /* return 1 if c is not a subset of b, 0 otherwise */
+
+  _REGISTER int i, x, sub;
+
+  sub = 0;
+  for( i=0; i<tbitset; ++i ){
+    x = b[i] | c[i];
+    if( x != b[i] ) sub=1;
+    a[i] = x;
+    }
+  return( sub );
+  }
+
+prlook( pp ) int *pp;{
+       int j;
+       pp = pp->lset;
+       if( pp == 0 ) printf("\tNULL");
+       else {
+               printf(" { " );
+               for( j=1; j<=nterms; ++j ){
+                       if( (pp[j>>4]>>(j&017) )&01 != 0 ) printf( "%s ", symnam(j) );
+                       }
+               printf( "}" );
+               }
+       }
diff --git a/eyacc/ey2.c b/eyacc/ey2.c
new file mode 100644 (file)
index 0000000..482be73
--- /dev/null
@@ -0,0 +1,534 @@
+# include "ey.h"
+# define IDENTIFIER 257
+# define MARK 258
+# define TERM 259
+# define LEFT 260
+# define BINARY 261
+# define RIGHT 262
+# define PREC 263
+# define LCURLY 264
+# define C_IDENTIFIER 265  /* name followed by colon */
+# define NUMBER 266
+
+setup(argc,argv) int argc; char *argv[];
+{      int i,j,lev,t;
+       int c;
+
+       foutput = -2;
+       i = 1;
+       while( argc >= 2  && argv[1][0] == '-' ) {
+               while( *++(argv[1]) ){
+                       switch( *argv[1] ){
+                       case 'v':
+                       case 'V':
+                               foutput = copen("y.output", 'w' );
+                               if( foutput < 0 ) error( "cannot open y.output");
+                               continue;
+                       case 'o':
+                       case 'O':
+                               oflag = 1;
+                               continue;
+                       case 'r':
+                       case 'R':
+                               oflag = 1;
+                               rflag = 1;
+                               continue;
+                       default:  error( "illegal option: %c", *argv[1]);
+                               }
+                       }
+               argv++;
+               argc--;
+               }
+
+       ftable = copen( oflag ? "yacc.tmp" : "y.tab.c" , 'w' );
+       if( ftable<0 ) error( "cannot open table file" );
+       if( argc > 1 ) cin = copen( argv[1], 'r' );
+       if( cin < 0 ) error( "cannot open input" );
+       settab();
+       printf("#\n");
+       ctokn = "$end";
+       defin(0);  /* eof */
+       extval = 0400;  /* beginning of assigned values */
+       ctokn = "error";
+       defin(0);
+       ctokn = "$accept";
+       defin(1);
+       mem=mem0;
+       cnamp = cnames;
+       lev=0;
+       i=0;
+
+       while( t = gettok() ){
+               switch( t ){
+                       case IDENTIFIER:        j = chfind(0);
+                                       trmlev[j] = lev;
+                                       continue;
+                       case ',':
+                       case ';':               continue;
+                       case TERM:              lev=0; continue;
+                       case LEFT:              lev=(++i<<3)|01; continue;
+                       case BINARY:    lev=(++i<<3)|02; continue;
+                       case RIGHT:     lev=(++i<<3)|03; continue;
+                       case MARK:
+                                       defout();
+                                       if( rflag ){ /* RATFOR */
+                                               printf( "define yyerrok yyerrf = 0\n" );
+                                               printf( "define yyclearin yychar = -1\n" );
+                                               printf( "subroutine yyactr(yyprdn)\n");
+                                               printf( "common/yycomn/yylval,yyval,yypv,yyvalv(150)\n" );
+                                               printf( "common/yylcom/yychar,yyerrf,yydebu\n" );
+                                               printf( "integer yychar, yyerrf, yydebu\n" );
+                                               printf( "integer yyprdn,yyval,yylval,yypv,yyvalv\n" );
+                                               }
+                                       else {
+                                               printf( "#define yyclearin yychar = -1\n" );
+                                               printf( "#define yyerrok yyerrflag = 0\n" );
+                                               printf( "extern int yychar, yyerrflag;\n" );
+                                               printf("\nint yyval 0;\nint *yypv;\nint yylval 0;");
+                                               printf("\nyyactr(__np__){\n");
+                                               }
+                                       break;
+                       case LCURLY:    defout();
+                                       cpycode();
+                                       continue;
+                       case NUMBER:
+                               trmset[j].value = numbval;
+                               if( j < ndefout && j>2 ) 
+                                       error("please define type # of %s earlier", trmset[j].name );
+                               continue;
+                       default:        error("bad precedence syntax, input %d", t );
+                       }
+               break;
+               }
+       prdptr[0]=mem;
+       /* added production */
+       *mem++ = NTBASE;
+       *mem++ = NTBASE+1;
+       *mem++ = 1;
+       *mem++ = 0;
+       prdptr[1]=mem;
+       i=0;
+
+       /* i is 0 when a rule can begin, 1 otherwise */
+
+       for(;;) switch( t=gettok() ) {
+       case C_IDENTIFIER:              if( mem == prdptr[1] ) {  /* first time */
+                                               if( rflag ){
+                                                       printf( "goto 1000\n" );
+                                                       }
+                                               else printf("\nswitch(__np__){\n");
+                                               }
+                               if( i != 0 ) error( "previous rule not terminated" );
+                               *mem = chfind(1);
+                               if( *mem < NTBASE )error( "token illegal on lhs of grammar rule" );
+                               i=1;
+                               ++mem;
+                               continue;
+       case IDENTIFIER:
+                       *mem=chfind(1);
+                       if(*mem < NTBASE)levprd[nprod]=trmlev[*mem];
+                       mem++;
+                       if(i==0) error("missing :");
+                       continue;
+       case '=':               levprd[nprod] =| 04;
+                               if( i==0 ) error("semicolon preceeds action");
+                       printf( rflag?"\n%d ":"\ncase %d:", nprod );
+                       cpyact();
+                       printf( rflag ? " return" : " break;" );
+       case '|':
+       case ';':               if(i){
+                               *mem++ = -nprod;
+                               prdptr[++nprod] = mem;
+                               levprd[nprod]=0;
+                               i=0;}
+                       if (t=='|'){i=1;*mem++ = *prdptr[nprod-1];}
+                       continue;
+       case 0:         /* End Of File */
+       case MARK:      if( i != 0 ) error( "rule not terminated before %%%% or EOF" );
+                       settab();
+                       finact();
+                       /* copy the programs which follow the rules */
+                       if( t == MARK ){
+                               while (c=getchar()) putchar(c);
+                               }
+                       return;
+       case PREC:      
+               if( i==0 ) error( "%%prec must appear inside rule" );
+               if( gettok()!=IDENTIFIER)error("illegal %%prec syntax" );
+               j=chfind(2);
+               if(j>=NTBASE)error("nonterminal %s illegal after %%prec", nontrst[j-NTBASE].name);
+               levprd[nprod]=trmlev[j];
+               continue;
+       case LCURLY:    
+               if( i!=0 ) error( "%%{ appears within a rule" );
+               cpycode();
+               continue;
+       default: error( "syntax error, input %d", t  );
+       }
+}
+
+finact(){
+       /* finish action routine */
+       register i;
+
+       if( rflag ){
+
+               printf( "\n1000 goto(" );
+               for( i=1; i<nprod; ++i ){
+                       printf( "%d,", (levprd[i]&04)==0?999:i );
+                       }
+               printf( "999),yyprdn\n" );
+               printf( "999 return\nend\n" );
+               printf( "define YYERRCODE %d\n", trmset[2].value );
+               }
+       else {
+               printf( "\n}\n}\n" );
+               printf( "int yyerrval %d;\n", trmset[2].value );
+               }
+       }
+defin(t) {
+/*     define ctokn to be a terminal if t=0
+       or a nonterminal if t=1         */
+       char *cp,*p;
+       int c;
+
+
+        if (t) {
+          if( ++nnonter >= ntlim ) error("too many nonterminals, limit %d",ntlim);
+         nontrst[nnonter].name = ctokn;
+         return( NTBASE + nnonter );
+          }
+        else {
+          if( ++nterms >= tlim ) error("too many terminals, limit %d",tlim );
+          trmset[nterms].name = ctokn;
+       if( ctokn[0]==' ' && ctokn[2]=='\0' ) /* single character literal */
+               trmset[nterms].value = ctokn[1];
+       else if ( ctokn[0]==' ' && ctokn[1]=='\\' ) { /* escape sequence */
+               if( ctokn[3] == '\0' ){ /* single character escape sequence */
+                       switch ( ctokn[2] ){
+                                /* character which is escaped */
+                       case 'n': trmset[nterms].value = '\n'; break;
+                       case 'r': trmset[nterms].value = '\r'; break;
+                       case 'b': trmset[nterms].value = '\b'; break;
+                       case 't': trmset[nterms].value = '\t'; break;
+                       case '\'': trmset[nterms].value = '\''; break;
+                       case '"': trmset[nterms].value = '"'; break;
+                       case '\\': trmset[nterms].value = '\\'; break;
+                       default: error( "invalid escape" );
+                               }
+                       }
+               else if( ctokn[2] <= '7' && ctokn[2]>='0' ){ /* \nnn sequence */
+                       if( ctokn[3]<'0' || ctokn[3] > '7' || ctokn[4]<'0' ||
+                               ctokn[4]>'7' || ctokn[5] != '\0' ) error("illegal \\nnn construction" );
+                       trmset[nterms].value = 64*(ctokn[2]-'0')+8*(ctokn[3]-'0')+ctokn[4]-'0';
+                       if( trmset[nterms].value == 0 ) error( "'\\000' is illegal" );
+                       }
+               }
+       else {
+               trmset[nterms].value = extval++;
+
+               }
+       trmlev[nterms] = 0;
+       return( nterms );
+          }
+}
+
+defout(){ /* write out the defines (at the end of the declaration section) */
+
+       _REGISTER int i, c;
+       _REGISTER char *cp;
+
+       for( i=ndefout; i<=nterms; ++i ){
+
+               cp = trmset[i].name;
+               if( *cp == ' ' ) ++cp;  /* literals */
+
+               for( ; (c= *cp)!='\0'; ++cp ){
+
+                       if( c>='a' && c<='z' ||
+                           c>='A' && c<='Z' ||
+                           c>='0' && c<='9' ||
+                           c=='_' )  ; /* VOID */
+                       else goto nodef;
+                       }
+
+               /* define it */
+
+               printf( "%c define %s %d\n", rflag?' ':'#', trmset[i].name, trmset[i].value );
+
+       nodef:  ;
+               }
+
+       ndefout = nterms+1;
+
+       }
+
+chstash( c ){
+  /* put character away into cnames */
+  if( cnamp >= &cnames[cnamsz] ) error("too many characters in id's and literals" );
+  else *cnamp++ = c;
+  }
+
+int gettok() {
+       int j, base;
+       static int peekline; /* number of '\n' seen in lookahead */
+       auto int c, match, reserve;
+
+begin:
+       reserve = 0;
+        if( peekc>=0 ) {
+               c = peekc;
+               lineno =+ peekline;
+               peekc = -1;
+               peekline = 0;
+               }
+        else c = getchar();
+        while( c==' ' || c=='\n' || c=='\t' || c == '\014'){
+          if( c == '\n' ) ++lineno;
+          c=getchar();
+          }
+       if (c=='/')
+               {if (getchar()!='*')error("illegal /");
+               c=getchar();
+               while(c) {
+                       if( c == '\n' ) ++lineno;
+                       if (c=='*')
+                               {if((c=getchar())=='/')break;}
+                       else c=getchar();}
+               if (!c) return(0);
+               goto begin;}
+       j=0;
+       switch(c){
+       case '"':       
+       case '\'':      match = c;
+                       ctokn = cnamp;
+                       chstash( ' ' );
+                       while(1){
+                               c = getchar();
+                               if( c == '\n' || c == '\0' )
+                                       error("illegal or missing ' or \"");
+                               if( c == '\\' ){
+                                       c = getchar();
+                                       chstash( '\\' );
+                                       }
+                               else if( c == match ) break;
+                               chstash( c );
+                               }
+                       break;
+       case '%':
+       case '\\':      switch(c=getchar())
+               {case '0':      return(TERM);
+               case '<':       return(LEFT);
+               case '2':       return(BINARY);
+               case '>':       return(RIGHT);
+               case '%':
+               case '\\':      return(MARK);
+               case '=':       return(PREC);
+               case '{':       return(LCURLY);
+               default:        reserve = 1;
+               }
+       default:        if( c >= '0' && c <= '9' ){ /* number */
+                               numbval = c-'0' ;
+                               base = (c=='0') ? 8 : 10 ;
+                               for( c=getchar(); c>='0' && c<='9'; c=getchar() ){
+                                       numbval = numbval*base + c - '0';
+                                       }
+                               peekc = c;
+                               return(NUMBER);
+                               }
+                       else if( (c>='a'&&c<='z')||(c>='A'&&c<='Z')||c=='_'||c=='.'||c=='$'){
+                               ctokn = cnamp;
+                               while(  (c>='a'&&c<='z') ||
+                                       (c>='A'&&c<='Z') ||
+                                       (c>='0'&&c<='9') ||
+                                       c=='_' || c=='.' || c=='$' ) {
+                                       chstash( c );
+                                       if( peekc>=0 ) { c = peekc; peekc = -1; }
+                                       else c = getchar();
+                                       }
+                               }
+                       else return(c);
+
+                       peekc=c;
+                       }
+       chstash( '\0' );
+
+       if( reserve ){ /* find a reserved word */
+               if( compare("term")) return( TERM );
+               if( compare("TERM")) return( TERM );
+               if( compare("token")) return( TERM );
+               if( compare("TOKEN")) return( TERM );
+               if( compare("left")) return( LEFT );
+               if( compare("LEFT")) return( LEFT );
+               if( compare("nonassoc")) return( BINARY );
+               if( compare("NONASSOC")) return( BINARY );
+               if( compare("binary")) return( BINARY );
+               if( compare("BINARY")) return( BINARY );
+               if( compare("right")) return( RIGHT );
+               if( compare("RIGHT")) return( RIGHT );
+               if( compare("prec")) return( PREC );
+               if( compare("PREC")) return( PREC );
+               error("invalid escape, or illegal reserved word: %s", ctokn );
+               }
+
+       /* look ahead to distinguish IDENTIFIER from C_IDENTIFIER */
+
+  look:
+       while( peekc==' ' || peekc=='\t' || peekc == '\n' || peekc == '\014' )
+       {
+               if( peekc == '\n' ) ++peekline;
+               peekc = getchar();
+       }
+
+       if( peekc != ':' ) return( IDENTIFIER );
+       peekc = -1;
+       lineno =+ peekline;
+       peekline = 0;
+       return( C_IDENTIFIER );
+}
+chfind(t)
+
+{      int i,j;
+
+       if (ctokn[0]==' ')t=0;
+       for(i=1;i<=nterms;i++)
+               if(compare(trmset[i].name)){
+                       cnamp = ctokn;
+                       return( i );
+                       }
+       for(i=1;i<=nnonter;i++)
+               if(compare(nontrst[i].name)) {
+                       cnamp = ctokn;
+                       return( i+NTBASE );
+                       }
+       /* cannot find name */
+       if( t>1 && ctokn[0] != ' ' )
+               error( "%s should have been defined earlier", ctokn );
+       return( defin( t ) );
+       }
+
+cpycode(){ /* copies code between \{ and \} */
+
+       int c;
+       c = getchar();
+       if( c == '\n' ) {
+               c = getchar();
+               lineno++;
+               }
+       while( c ){
+               if( c=='\\' )
+                       if( (c=getchar()) == '}' ) return;
+                       else putchar('\\');
+               if( c=='%' )
+                       if( (c=getchar()) == '}' ) return;
+                       else putchar('%');
+               putchar( c );
+               if( c == '\n' ) ++lineno;
+               c = getchar();
+               }
+       error("eof before %%}");
+       }
+
+cpyact(){ /* copy C action to the next ; or closing } */
+       int brac, c, match, *i, j, s;
+
+       brac = 0;
+
+loop:
+       c = getchar();
+swt:
+       switch( c ){
+
+case ';':
+               if( brac == 0 ){
+                       putchar( c );
+                       return;
+                       }
+               goto lcopy;
+
+case '{':
+               brac++;
+               goto lcopy;
+
+case '$':
+               s = 1;
+               c = getchar();
+               if( c == '$' ){
+                       printf("yyval");
+                       goto loop;
+                       }
+               if( c == '-' ){
+                       s = -s;
+                       c = getchar();
+                       }
+               if( c>='0' && c <= '9' ){
+                       j=0;
+                       while( c>='0' && c<= '9' ){
+                               j= j*10+c-'0';
+                               c = getchar();
+                               }
+                       if( rflag ) printf( "yyvalv(yypv%c%d)", s==1?'+':'-', j );
+                       else printf("yypv[%d]", s*j );
+                       goto swt;
+                       }
+               putchar( '$' );
+               if( s<0 ) putchar('-');
+               goto swt;
+
+case '}':
+               brac--;
+               if( brac == 0 ){
+                       putchar( c );
+                       return;
+                       }
+               goto lcopy;
+
+case '/':      /* look for comments */
+               putchar( c );
+               c = getchar();
+               if( c != '*' ) goto swt;
+
+               /* it really is a comment */
+
+               putchar( c );
+               while( c=getchar() ){
+                       if( c=='*' ){
+                               putchar( c );
+                               if( (c=getchar()) == '/' ) goto lcopy;
+                               }
+                       putchar( c );
+                       }
+               error( "EOF inside comment" );
+
+case '\'':     /* character constant */
+               match = '\'';
+               goto string;
+
+case '"':      /* character string */
+               match = '"';
+
+       string:
+
+               putchar( c );
+               while( c=getchar() ){
+
+                       if( c=='\\' ){
+                               putchar( c );
+                               c=getchar();
+                               }
+                       else if( c==match ) goto lcopy;
+                       putchar( c );
+                       }
+               error( "EOF in string or character constant" );
+
+case '\0':
+               error("action does not terminate");
+case '\n':     ++lineno;
+               goto lcopy;
+
+               }
+
+lcopy:
+       putchar( c );
+       goto loop;
+       }
diff --git a/eyacc/ey3.c b/eyacc/ey3.c
new file mode 100644 (file)
index 0000000..5048305
--- /dev/null
@@ -0,0 +1,378 @@
+# include "ey.h"
+
+cpres(){ /* conpute an array with the beginnings of  productions yielding given nonterminals
+       The array pres points to these lists */
+       int i,j,c;
+       pres = yalloc(nnonter+1);
+       for(i=0;i<=nnonter;i++){
+               c = i+NTBASE;
+               pres[i] = mem;
+               fatfl = 0;  /* make undefined  symbols  nonfatal */
+               for(j=0;j<nprod;j++)
+               if (*prdptr[j] == c) *mem++ =  prdptr[j]+1;
+               if(pres[i] == mem){
+                       error("nonterminal %s not defined!", nontrst[i].name);
+                       }
+               }
+       pres[i] = mem;
+       fatfl = 1;
+       if( nerrors ){
+               summary();
+               cexit(1);
+               }
+       }
+
+int indebug 0;
+cpfir() {
+  /* compute an array with the first of nonterminals */
+  int i, ch, **s, **t, changes, *p;
+
+  pfirst = yalloc(nnonter+1);
+  for (i=0;i<=nnonter;i++) {
+    aryfil( wsets[i].ws, tbitset, 0 );
+    t = pres[i+1];
+    for( s=pres[i]; s<t; ++s ){ /* initially fill the sets */
+      for( p = *s; (ch = *p) > 0 ; ++p ) {
+        if( ch < NTBASE ) {
+          wsets[i].ws[ch>>4] =| (1 << (ch&017) );
+          break;
+          }
+        else if( !pempty[ch-NTBASE] ) break;
+        }
+      }
+    }
+
+  /* now, reflect transitivity */
+
+  changes = 1;
+  while( changes ){
+    changes = 0;
+    for( i=0; i<=nnonter; ++i ){
+      t = pres[i+1];
+      for( s=pres[i]; s<t; ++s ){
+        for( p = *s; ( ch = (*p-NTBASE) ) >= 0; ++p ) {
+          changes =| union( wsets[i].ws, wsets[i].ws, wsets[ch].ws );
+          if( !pempty[ch] ) break;
+          }
+        }
+      }
+    }
+
+  for( i=0; i<=nnonter; i++ ) pfirst[i] = flset( wsets[i].ws );
+  if( !indebug ) return;
+  settty();
+  for( i=0; i<=nnonter; i++ ){
+    printf( "\n%s: ", nontrst[i].name );
+    prlook( pfirst[i] );
+    printf( " %d\n", pempty[i] );
+    }
+  }
+
+state(c){ /* sorts last state,and sees if it equals earlier ones. returns state number */
+       int s,size1,size2;
+       _REGISTER i;
+       struct item *p1, *p2, *k, *l, *q1, *q2;
+       p1 = pstate[nstate];
+       p2 = pstate[nstate+1];
+       if(p1==p2) return(0); /* null state */
+       /* sort the items */
+       for(k=p2-1;k>p1;k--) {  /* make k the biggest */
+               for(l=k-1;l>=p1;--l)if( l->pitem > k->pitem ){
+                       s = k->pitem;
+                       k->pitem = l->pitem;
+                       l->pitem = s;
+                       s = k->look;
+                       k->look = l->look;
+                       l->look = s;
+                       }
+               }
+       size1 = p2 - p1; /* size of state */
+
+       for( i= (c>=NTBASE)?ntstates[c-NTBASE]:tstates[c]; i != 0; i = mstates[i] ) {
+               /* get ith state */
+               q1 = pstate[i];
+               q2 = pstate[i+1];
+               size2 = q2 - q1;
+               if (size1 != size2) continue;
+               k=p1;
+               for(l=q1;l<q2;l++) {
+                       if( l->pitem != k->pitem ) break;
+                       ++k;
+                       }
+               if (l != q2) continue;
+               /* found it */
+               pstate[nstate+1] = pstate[nstate]; /* delete last state */
+               /* fix up lookaheads */
+               k=p1;
+               for( l=q1; l<q2; ++l ){
+                       if( union( clset.lset, l->look->lset, k->look->lset ) ) {
+                               tystate[i] = 1;
+                               /* register the new set */
+                               l->look = flset( &clset );
+                               }
+                       ++k;
+                       }
+               return (i);
+               }
+/* state is new */
+       pstate[nstate+2] = p2;
+       if(nstate+1 >= stsize) error("too many states");
+       if( c >= NTBASE ){
+               mstates[ nstate ] = ntstates[ c-NTBASE ];
+               ntstates[ c-NTBASE ] = nstate;
+               }
+       else {
+               mstates[ nstate ] = tstates[ c ];
+               tstates[ c ] = nstate;
+               }
+       tystate[nstate]=1;
+       return(nstate++);
+       }
+
+int pidebug 0; /* debugging flag for putitem */
+putitem ( ptr, lptr )          int *ptr; struct looksets *lptr;{
+       int *jip, k;
+       struct item *i, *j;
+
+        if( pidebug ) {
+          settty();
+         printf("putitem(%s), state %d\n", writem(&ptr), nstate );
+          }
+       /* see if it's there */
+       j = pstate[nstate+1];
+        for( i=pstate[nstate]; i<j; ++i )
+               if(i->pitem == ptr) { 
+                       error("yacc error--duplicate item");
+                       }
+       /* not there */
+       j->pitem = ptr;
+       j->look = flset( lptr );
+       pstate[nstate+1] = ++j;
+       jip = j;
+       if(jip-mem0 >= memsiz) error("out of state space");
+       }
+
+cempty(){ /* mark nonterminals which derive the empty string */
+
+  int i, *p;
+
+  /* set pempty to 0 */
+  pempty = yalloc( nnonter );
+  aryfil( pempty, nnonter+1, 0 );
+  for( i=1; i<nprod; ++i ) /* loop over productions */
+    if( prdptr[i][1] <= 0 ) /* i is empty production */
+      pempty[ *prdptr[i]-NTBASE ] = 1;
+
+  /* now, all explicitly empty nonterminals marked with pempty = 1 */
+
+  /* loop as long as we keep finding nontrivial empty nonterminals */
+
+again:
+  for( i=1; i<nprod; ++i ){
+    if( pempty[ *prdptr[i]-NTBASE ]==0 ){ /* not known to be empty */
+      for( p=prdptr[i]+1; *p>=NTBASE && pempty[*p-NTBASE]!=0 ; ++p ) ;
+      if( *p < 0 ){ /* we have a nontrivially empty nonterminal */
+        pempty[*prdptr[i]-NTBASE] = 1;
+        goto again; /* got one ... try for another */
+        }
+      }
+    }
+  }
+
+int gsdebug 0;
+stagen(){ /* generate the states */
+
+  int i, j, k, c;
+
+  /* initialize */
+
+  nstate = 0;
+  pstate[0] = pstate[1] = mem;
+  aryfil( clset.lset, tbitset, 0 );
+  putitem( prdptr[0]+1, &clset );
+  tystate[0] = 1;
+  nstate = 1;
+  pstate[2] = pstate[1];
+
+  memact = 0;
+  aryfil( amem, actsiz, 0 );
+
+  /* now, the main state generation loop */
+
+  more:
+  for( i=0; i<nstate; ++i ){
+    if( tystate[i] != 1 ) continue;
+    tystate[i] = 0;
+    aryfil( temp1, nterms+nnonter+1, 0 );
+    /* take state i, close it, and do gotos */
+    closure(i);
+    for( j=0; j<cwset; ++j ){ /* generate gotos */
+      if( wsets[j].flag ) continue;
+      wsets[j].flag = 1;
+      c = *(wsets[j].pitem);
+      if( c <= 1 ) {
+               if( pstate[i+1]-pstate[i] <= j ) tystate[i] = (tystate[i]==1)?1:2;
+               continue;
+               }
+      /* do a goto on c */
+      for( k=j; k<cwset; ++k ){
+        if( c == *(wsets[k].pitem) ){ /* this item contributes to the goto */
+          putitem( wsets[k].pitem + 1, wsets[k].ws );
+          wsets[k].flag = 1;
+          }
+        }
+      if( c < NTBASE ) temp1[c] = state(c);
+      else temp1[c-NTBASE+nterms] = state(c);
+      }
+    if( gsdebug ){
+      settty();
+      printf( "%d: ", i );
+      for( j=1; j<=nterms; ++j ){
+        if( temp1[j] != 0 ) printf( "%s %d, ", symnam(j), temp1[j]);
+        }
+      for( j=1; j<=nnonter; ++j ){
+        if( temp1[j+nterms] ) printf( "%s %d, ", nontrst[j].name, temp1[j+nterms] );
+        }
+      printf("\n");
+      }
+    apstate[i] = apack( &temp1[0], nterms );
+    indgo[i] = apack( &temp1[nterms+1], nnonter-1 ) - 1;
+    goto more; /* we have done one goto; do some more */
+    }
+  /* no more to do... stop */
+  }
+
+int cldebug 0; /* debugging flag for closure */
+closure(i){ /* generate the closure of state i */
+
+  int c, ch, work;
+  _REGISTER j, k;
+  int *pi;
+  int **s, **t;
+  struct item *q;
+  _REGISTER struct item *p;
+
+  ++zzclose;
+
+  /* first, copy kernel of state i to wsets */
+
+  cwset = 0;
+  q = pstate[i+1];
+  for( p=pstate[i]; p<q; ++p ){
+    wsets[cwset].pitem = p->pitem;
+    wsets[cwset].flag = 1;    /* this item must get closed */
+    for( k=0; k<tbitset; ++k ) wsets[cwset].ws[k] = p->look->lset[k];
+    ++cwset;
+    }
+
+  /* now, go through the loop, closing each item */
+
+  work = 1;
+  while( work ){
+    work = 0;
+    for( j=0; j<cwset; ++j ){
+  
+      if( wsets[j].flag == 0 ) continue;
+      c = *(wsets[j].pitem);  /* dot is before c */
+  
+      if( c < NTBASE ){
+        wsets[j].flag = 0;
+        continue;  /* only interesting case is where . is before nonterminal */
+        }
+  
+      /* compute the lookahead */
+      aryfil( clset.lset, tbitset, 0 );
+
+      /* find items involving c */
+
+      for( k=j; k<cwset; ++k ){
+        if( wsets[k].flag == 1 && *(pi=wsets[k].pitem) == c ){
+          wsets[k].flag = 0;
+          if( nolook ) continue;
+          while( (ch= *++pi)>0 ){
+            if( ch < NTBASE ){ /* terminal symbol */
+              clset.lset[ch>>4] =| (1<<(ch&017));
+              break;
+              }
+            /* nonterminal symbol */
+            union( clset.lset, clset.lset, pfirst[ch-NTBASE] );
+            if( !pempty[ch-NTBASE] ) break;
+            }
+          if( ch<=0 ) union( clset.lset, clset.lset, wsets[k].ws );
+          }
+        }
+  
+      /*  now loop over productions derived from c */
+  
+      c =- NTBASE; /* c is now nonterminal number */
+  
+      t = pres[c+1];
+      for( s=pres[c]; s<t; ++s ){
+        /* put these items into the closure */
+        for( k=0; k<cwset; ++k ){ /* is the item there */
+          if( wsets[k].pitem == *s ){ /* yes, it is there */
+            if( nolook ) goto nexts;
+            if( union( wsets[k].ws, wsets[k].ws, clset.lset ) ) wsets[k].flag = work = 1;
+            goto nexts;
+            }
+          }
+  
+        /*  not there; make a new entry */
+        if( cwset+1 >= wssize ) error( "working set overflow" );
+        wsets[cwset].pitem = *s;
+        wsets[cwset].flag = 1;
+        if( nolook ){
+          cwset++;
+          goto nexts;
+          }
+        work = 1;
+        for( k=0; k<tbitset; ++k ) wsets[cwset].ws[k] = clset.lset[k];
+        cwset++;
+  
+      nexts: ;
+        }
+  
+      }
+    }
+
+  /* have computed closure; flags are reset; return */
+
+  if( cwset > zzcwset ) zzcwset = cwset;
+  if( !cldebug ) return;
+  settty();
+  printf("\nState %d, nolook = %d\n", i, nolook );
+  for( j=0; j<cwset; ++j ){
+    if( wsets[j].flag ) printf("flag set!\n");
+    wsets[j].flag = 0;
+    printf("\t%s", writem(&wsets[j].pitem));
+    prlook( wsets[j].ws );
+    printf( "\n" );
+    }
+
+  }
+
+struct looksets *flset( p ) 
+       struct looksets *p;
+       {
+       /* decide if the lookahead set pointed to by p is known */
+       /* return pointer to a perminent location for the set */
+
+       int j, *w;
+       _REGISTER *u, *v, i;
+
+       for( i=0; i<nlset; ++i ){
+               u = p->lset;
+               v = lkst[i].lset;
+               w = & v[tbitset];
+               while( v<w) if( *u++ != *v++ ) goto more;
+               /* we have matched */
+               return( & lkst[i] );
+               more: ;
+               }
+       /* add a new one */
+       if( nlset+1 >= lsetsz )error("too many lookahead sets");
+       for( j=0; j<tbitset; ++j ){
+               lkst[nlset].lset[j] = p->lset[j];
+               }
+       return( & lkst[nlset++]);
+       }
diff --git a/eyacc/ey5.c b/eyacc/ey5.c
new file mode 100644 (file)
index 0000000..56e2995
--- /dev/null
@@ -0,0 +1,43 @@
+/* fake portable I/O routines, for those
+    sites so backward as to not have the
+     port. library */
+
+int cin, cout;
+extern int fin, fout;
+
+copen( s, c ) char *s; {
+  int f;
+
+  if( c == 'r' ){
+    fin = f = open( s, 0 );
+    }
+
+  else if( c == 'a' ){
+    f = open( s, 1 );
+    seek( f, 0, 2 );
+    }
+
+  else {  /* c == w */
+    f = creat( s, 0666 );
+    }
+
+  return( f );
+  }
+
+cflush(x){ /* fake! sets file to x */
+  flush();
+  fout = x;
+  }
+
+system(){
+  error( "The function \"system\" is called" );
+  }
+
+cclose(i){
+  close(i);
+  }
+
+cexit(i){
+  flush();
+  exit(i);
+  }