+# include "dextern"
+
+ /* variables used locally */
+
+ /* lookahead computations */
+
+int tbitset; /* size of lookahead sets */
+struct looksets lkst [ LSETSIZE ];
+int nlset = 0; /* next lookahead set index */
+int nolook = 0; /* flag to suppress lookahead computations */
+struct looksets clset; /* temporary storage for lookahead computations */
+
+ /* working set computations */
+
+struct wset wsets[ WSETSIZE ];
+struct wset *cwp;
+
+ /* state information */
+
+int nstate = 0; /* number of states */
+struct item *pstate[NSTATES+2]; /* pointers to the descriptions of the states */
+int tystate[NSTATES]; /* contains type information about the states */
+int indgo[NSTATES]; /* index to the stored goto table */
+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 */
+
+ /* storage for the actions in the parser */
+
+int amem[ACTSIZE]; /* action table storage */
+int *memp = amem; /* next free action table position */
+
+ /* other storage areas */
+
+int temp1[TEMPSIZE]; /* temporary storage, indexed by terms + ntokens or states */
+int lineno= 1; /* current input line number */
+int fatfl = 1; /* if on, error is fatal */
+int nerrors = 0; /* number of errors */
+
+ /* storage for information about the nonterminals */
+
+int **pres[NNONTERM+2]; /* vector of pointers to productions yielding each nonterminal */
+struct looksets *pfirst[NNONTERM+2]; /* vector of pointers to first sets for each nonterminal */
+int pempty[NNONTERM+1]; /* vector of nonterminals nontrivially deriving e */
+
+main(argc,argv) int argc; char *argv[]; {
+
+ setup(argc,argv); /* initialize and read productions */
+ tbitset = NWORDS(ntokens);
+ 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 firsts of nonterminals */
+ stagen(); /* generate the states */
+ output(); /* write the states and the tables */
+ go2out();
+ hideprod();
+ summary();
+ callopt();
+ others();
+ exit(0);
+ }
+
+others(){ /* put out other arrays, copy the parsers */
+ register c, i, j;
+
+ finput = fopen( PARSER, "r" );
+ if( finput == NULL ) error( "cannot find parser %s", PARSER );
+
+ warray( "yyr1", levprd, nprod );
+
+ aryfil( temp1, nprod, 0 );
+ PLOOP(1,i)temp1[i] = prdptr[i+1]-prdptr[i]-2;
+ warray( "yyr2", temp1, nprod );
+
+ aryfil( temp1, nstate, -1000 );
+ TLOOP(i){
+ for( j=tstates[i]; j!=0; j=mstates[j] ){
+ temp1[j] = tokset[i].value;
+ }
+ }
+ NTLOOP(i){
+ for( j=ntstates[i]; j!=0; j=mstates[j] ){
+ temp1[j] = -i;
+ }
+ }
+ warray( "yychk", temp1, nstate );
+
+ warray( "yydef", defact, nstate );
+
+ /* copy parser text */
+
+ while( (c=getc(finput) ) != EOF ){
+ if( c == '$' ){
+ if( (c=getc(finput)) != 'A' ) putc( '$', ftable );
+ else { /* copy actions */
+ faction = fopen( ACTNAME, "r" );
+ if( faction == NULL ) error( "cannot reopen action tempfile" );
+ while( (c=getc(faction) ) != EOF ) putc( c, ftable );
+ fclose(faction);
+ ZAPFILE(ACTNAME);
+ c = getc(finput);
+ }
+ }
+ putc( c, ftable );
+ }
+
+ fclose( ftable );
+ }
+
+char *chcopy( p, q ) char *p, *q; {
+ /* copies string q into p, returning next free char ptr */
+ while( *p = *q++ ) ++p;
+ return( p );
+ }
+
+# define ISIZE 400
+char *writem(pp) int *pp; { /* creates output string for item pointed to by pp */
+ int i,*p;
+ static char sarr[ISIZE];
+ char *q;
+
+ for( p=pp; *p>0 ; ++p ) ;
+ p = prdptr[-*p];
+ q = chcopy( sarr, nontrst[*p-NTBASE].name );
+ q = chcopy( q, " : " );
+
+ for(;;){
+ *q++ = ++p==pp ? '_' : ' ';
+ *q = '\0';
+ if((i = *p) <= 0) break;
+ q = chcopy( q, symnam(i) );
+ if( q> &sarr[ISIZE-30] ) error( "item too big" );
+ }
+
+ if( (i = *pp) < 0 ){ /* an item calling for a reduction */
+ q = chcopy( q, " (" );
+ sprintf( q, "%d)", -i );
+ }
+
+ return( sarr );
+ }
+
+char *symnam(i){ /* return a pointer to the name of symbol i */
+ char *cp;
+
+ cp = (i>=NTBASE) ? nontrst[i-NTBASE].name : tokset[i].name ;
+ if( *cp == ' ' ) ++cp;
+ return( cp );
+ }
+
+struct wset *zzcwp = wsets;
+int zzgoent = 0;
+int zzgobest = 0;
+int zzacent = 0;
+int zzexcp = 0;
+int zzclose = 0;
+int zzsrconf = 0;
+int * zzmemsz = mem0;
+int zzrrconf = 0;
+
+summary(){ /* output the summary on the tty */
+
+ if( foutput!=NULL ){
+ fprintf( foutput, "\n%d/%d terminals, %d/%d nonterminals\n", ntokens, NTERMS,
+ nnonter, NNONTERM );
+ fprintf( foutput, "%d/%d grammar rules, %d/%d states\n", nprod, NPROD, nstate, NSTATES );
+ fprintf( foutput, "%d shift/reduce, %d reduce/reduce conflicts reported\n", zzsrconf, zzrrconf );
+ fprintf( foutput, "%d/%d working sets used\n", zzcwp-wsets, WSETSIZE );
+ fprintf( foutput, "memory: states,etc. %d/%d, parser %d/%d\n", zzmemsz-mem0, MEMSIZE,
+ memp-amem, ACTSIZE );
+ fprintf( foutput, "%d/%d distinct lookahead sets\n", nlset, LSETSIZE );
+ fprintf( foutput, "%d extra closures\n", zzclose - 2*nstate );
+ fprintf( foutput, "%d shift entries, %d exceptions\n", zzacent, zzexcp );
+ fprintf( foutput, "%d goto entries\n", zzgoent );
+ fprintf( foutput, "%d entries saved by goto default\n", zzgobest );
+ }
+ if( zzsrconf!=0 || zzrrconf!=0 ){
+ fprintf( stdout,"\nconflicts: ");
+ if( zzsrconf )fprintf( stdout, "%d shift/reduce" , zzsrconf );
+ if( zzsrconf && zzrrconf )fprintf( stdout, ", " );
+ if( zzrrconf )fprintf( stdout, "%d reduce/reduce" , zzrrconf );
+ fprintf( stdout, "\n" );
+ }
+
+ fclose( ftemp );
+ if( fdefine != NULL ) fclose( fdefine );
+ }
+
+/* VARARGS1 */
+error(s,a1) char *s; { /* write out error comment */
+
+ ++nerrors;
+ fprintf( stderr, "\n fatal error: ");
+ fprintf( stderr, s,a1);
+ fprintf( stderr, ", line %d\n", lineno );
+ if( !fatfl ) return;
+ summary();
+ exit(1);
+ }
+
+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;
+ }
+
+setunion( a, b ) register *a, *b; {
+ /* set a to the union of a and b */
+ /* return 1 if b is not a subset of a, 0 otherwise */
+ register i, x, sub;
+
+ sub = 0;
+ SETLOOP(i){
+ *a = (x = *a)|*b++;
+ if( *a++ != x ) sub = 1;
+ }
+ return( sub );
+ }
+
+prlook( p ) struct looksets *p;{
+ register j, *pp;
+ pp = p->lset;
+ if( pp == 0 ) fprintf( foutput, "\tNULL");
+ else {
+ fprintf( foutput, " { " );
+ TLOOP(j) {
+ if( BIT(pp,j) ) fprintf( foutput, "%s ", symnam(j) );
+ }
+ fprintf( foutput, "}" );
+ }
+ }
+
+cpres(){ /* compute an array with the beginnings of productions yielding given nonterminals
+ The array pres points to these lists */
+ /* the array pyield has the lists: the total size is only NPROD+1 */
+ register **pmem;
+ register c, j, i;
+ static int * pyield[NPROD];
+
+ pmem = pyield;
+
+ NTLOOP(i){
+ c = i+NTBASE;
+ pres[i] = pmem;
+ fatfl = 0; /* make undefined symbols nonfatal */
+ PLOOP(0,j){
+ if (*prdptr[j] == c) *pmem++ = prdptr[j]+1;
+ }
+ if(pres[i] == pmem){
+ error("nonterminal %s not defined!", nontrst[i].name);
+ }
+ }
+ pres[i] = pmem;
+ fatfl = 1;
+ if( nerrors ){
+ summary();
+ exit(1);
+ }
+ if( pmem != &pyield[nprod] ) error( "internal Yacc error: pyield %d", pmem-&pyield[nprod] );
+ }
+
+int indebug = 0;
+cpfir() {
+ /* compute an array with the first of nonterminals */
+ register *p, **s, i, **t, ch, changes;
+
+ zzcwp = &wsets[nnonter];
+ NTLOOP(i){
+ aryfil( wsets[i].ws.lset, 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 ) {
+ SETBIT( wsets[i].ws.lset, ch );
+ break;
+ }
+ else if( !pempty[ch-NTBASE] ) break;
+ }
+ }
+ }
+
+ /* now, reflect transitivity */
+
+ changes = 1;
+ while( changes ){
+ changes = 0;
+ NTLOOP(i){
+ t = pres[i+1];
+ for( s=pres[i]; s<t; ++s ){
+ for( p = *s; ( ch = (*p-NTBASE) ) >= 0; ++p ) {
+ changes |= setunion( wsets[i].ws.lset, wsets[ch].ws.lset );
+ if( !pempty[ch] ) break;
+ }
+ }
+ }
+ }
+
+ NTLOOP(i) pfirst[i] = flset( &wsets[i].ws );
+ if( !indebug ) return;
+ if( (foutput!=NULL) ){
+ NTLOOP(i) {
+ fprintf( foutput, "\n%s: ", nontrst[i].name );
+ prlook( pfirst[i] );
+ fprintf( foutput, " %d\n", pempty[i] );
+ }
+ }
+ }
+
+state(c){ /* sorts last state,and sees if it equals earlier ones. returns state number */
+ int 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 ){
+ int *s;
+ struct looksets *ss;
+ s = k->pitem;
+ k->pitem = l->pitem;
+ l->pitem = s;
+ ss = k->look;
+ k->look = l->look;
+ l->look = ss;
+ }
+ }
+ 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 */
+ if( nolook ) return(i);
+ for( l=q1,k=p1; l<q2; ++l,++k ){
+ int s;
+ SETLOOP(s) clset.lset[s] = l->look->lset[s];
+ if( setunion( clset.lset, k->look->lset ) ) {
+ tystate[i] = MUSTDO;
+ /* register the new set */
+ l->look = flset( &clset );
+ }
+ }
+ return (i);
+ }
+ /* state is new */
+ if( nolook ) error( "yacc state/nolook error" );
+ pstate[nstate+2] = p2;
+ if(nstate+1 >= NSTATES) 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]=MUSTDO;
+ return(nstate++);
+ }
+
+int pidebug = 0; /* debugging flag for putitem */
+putitem( ptr, lptr ) int *ptr; struct looksets *lptr; {
+ register struct item *j;
+
+ if( pidebug && (foutput!=NULL) ) {
+ fprintf( foutput, "putitem(%s), state %d\n", writem(ptr), nstate );
+ }
+ j = pstate[nstate+1];
+ j->pitem = ptr;
+ if( !nolook ) j->look = flset( lptr );
+ pstate[nstate+1] = ++j;
+ if( (int *)j > zzmemsz ){
+ zzmemsz = (int *)j;
+ if( zzmemsz >= &mem0[MEMSIZE] ) error( "out of state space" );
+ }
+ }
+
+cempty(){ /* mark nonterminals which derive the empty string */
+ /* also, look for nonterminals which don't derive any token strings */
+
+# define EMPTY 1
+# define WHOKNOWS 0
+# define OK 1
+
+ register i, *p;
+
+ /* first, use the array pempty to detect productions that can never be reduced */
+ /* set pempty to WHONOWS */
+ aryfil( pempty, nnonter+1, WHOKNOWS );
+
+ /* now, look at productions, marking nonterminals which derive something */
+
+ more:
+ PLOOP(0,i){
+ if( pempty[ *prdptr[i] - NTBASE ] ) continue;
+ for( p=prdptr[i]+1; *p>=0; ++p ){
+ if( *p>=NTBASE && pempty[ *p-NTBASE ] == WHOKNOWS ) break;
+ }
+ if( *p < 0 ){ /* production can be derived */
+ pempty[ *prdptr[i]-NTBASE ] = OK;
+ goto more;
+ }
+ }
+
+ /* now, look at the nonterminals, to see if they are all OK */
+
+ NTLOOP(i){
+ /* the added production rises or falls as the start symbol ... */
+ if( i == 0 ) continue;
+ if( pempty[ i ] != OK ) {
+ fatfl = 0;
+ error( "nonterminal %s never derives any token string", nontrst[i].name );
+ }
+ }
+
+ if( nerrors ){
+ summary();
+ exit(1);
+ }
+
+ /* now, compute the pempty array, to see which nonterminals derive the empty string */
+
+ /* set pempty to WHOKNOWS */
+
+ aryfil( pempty, nnonter+1, WHOKNOWS );
+
+ /* loop as long as we keep finding empty nonterminals */
+
+again:
+ PLOOP(1,i){
+ if( pempty[ *prdptr[i]-NTBASE ]==WHOKNOWS ){ /* not known to be empty */
+ for( p=prdptr[i]+1; *p>=NTBASE && pempty[*p-NTBASE]==EMPTY ; ++p ) ;
+ if( *p < 0 ){ /* we have a nontrivially empty nonterminal */
+ pempty[*prdptr[i]-NTBASE] = EMPTY;
+ goto again; /* got one ... try for another */
+ }
+ }
+ }
+
+ }
+
+int gsdebug = 0;
+stagen(){ /* generate the states */
+
+ int i, j;
+ register c;
+ register struct wset *p, *q;
+
+ /* initialize */
+
+ nstate = 0;
+ /* THIS IS FUNNY from the standpoint of portability */
+ /* it represents the magic moment when the mem0 array, which has
+ /* been holding the productions, starts to hold item pointers, of a
+ /* different type... */
+ /* someday, alloc should be used to allocate all this stuff... for now, we
+ /* accept that if pointers don't fit in integers, there is a problem... */
+
+ pstate[0] = pstate[1] = (struct item *)mem;
+ aryfil( clset.lset, tbitset, 0 );
+ putitem( prdptr[0]+1, &clset );
+ tystate[0] = MUSTDO;
+ nstate = 1;
+ pstate[2] = pstate[1];
+
+ aryfil( amem, ACTSIZE, 0 );
+
+ /* now, the main state generation loop */
+
+ more:
+ SLOOP(i){
+ if( tystate[i] != MUSTDO ) continue;
+ tystate[i] = DONE;
+ aryfil( temp1, nnonter+1, 0 );
+ /* take state i, close it, and do gotos */
+ closure(i);
+ WSLOOP(wsets,p){ /* generate goto's */
+ if( p->flag ) continue;
+ p->flag = 1;
+ c = *(p->pitem);
+ if( c <= 1 ) {
+ if( pstate[i+1]-pstate[i] <= p-wsets ) tystate[i] = MUSTLOOKAHEAD;
+ continue;
+ }
+ /* do a goto on c */
+ WSLOOP(p,q){
+ if( c == *(q->pitem) ){ /* this item contributes to the goto */
+ putitem( q->pitem + 1, &q->ws );
+ q->flag = 1;
+ }
+ }
+ if( c < NTBASE ) {
+ state(c); /* register new state */
+ }
+ else {
+ temp1[c-NTBASE] = state(c);
+ }
+ }
+ if( gsdebug && (foutput!=NULL) ){
+ fprintf( foutput, "%d: ", i );
+ NTLOOP(j) {
+ if( temp1[j] ) fprintf( foutput, "%s %d, ", nontrst[j].name, temp1[j] );
+ }
+ fprintf( foutput, "\n");
+ }
+ indgo[i] = apack( &temp1[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, k;
+ register struct wset *u, *v;
+ int *pi;
+ int **s, **t;
+ struct item *q;
+ register struct item *p;
+
+ ++zzclose;
+
+ /* first, copy kernel of state i to wsets */
+
+ cwp = wsets;
+ ITMLOOP(i,p,q){
+ cwp->pitem = p->pitem;
+ cwp->flag = 1; /* this item must get closed */
+ SETLOOP(k) cwp->ws.lset[k] = p->look->lset[k];
+ WSBUMP(cwp);
+ }
+
+ /* now, go through the loop, closing each item */
+
+ work = 1;
+ while( work ){
+ work = 0;
+ WSLOOP(wsets,u){
+
+ if( u->flag == 0 ) continue;
+ c = *(u->pitem); /* dot is before c */
+
+ if( c < NTBASE ){
+ u->flag = 0;
+ continue; /* only interesting case is where . is before nonterminal */
+ }
+
+ /* compute the lookahead */
+ aryfil( clset.lset, tbitset, 0 );
+
+ /* find items involving c */
+
+ WSLOOP(u,v){
+ if( v->flag == 1 && *(pi=v->pitem) == c ){
+ v->flag = 0;
+ if( nolook ) continue;
+ while( (ch= *++pi)>0 ){
+ if( ch < NTBASE ){ /* terminal symbol */
+ SETBIT( clset.lset, ch );
+ break;
+ }
+ /* nonterminal symbol */
+ setunion( clset.lset, pfirst[ch-NTBASE]->lset );
+ if( !pempty[ch-NTBASE] ) break;
+ }
+ if( ch<=0 ) setunion( clset.lset, v->ws.lset );
+ }
+ }
+
+ /* 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 */
+ WSLOOP(wsets,v){ /* is the item there */
+ if( v->pitem == *s ){ /* yes, it is there */
+ if( nolook ) goto nexts;
+ if( setunion( v->ws.lset, clset.lset ) ) v->flag = work = 1;
+ goto nexts;
+ }
+ }
+
+ /* not there; make a new entry */
+ if( cwp-wsets+1 >= WSETSIZE ) error( "working set overflow" );
+ cwp->pitem = *s;
+ cwp->flag = 1;
+ if( !nolook ){
+ work = 1;
+ SETLOOP(k) cwp->ws.lset[k] = clset.lset[k];
+ }
+ WSBUMP(cwp);
+
+ nexts: ;
+ }
+
+ }
+ }
+
+ /* have computed closure; flags are reset; return */
+
+ if( cwp > zzcwp ) zzcwp = cwp;
+ if( cldebug && (foutput!=NULL) ){
+ fprintf( foutput, "\nState %d, nolook = %d\n", i, nolook );
+ WSLOOP(wsets,u){
+ if( u->flag ) fprintf( foutput, "flag set!\n");
+ u->flag = 0;
+ fprintf( foutput, "\t%s", writem(u->pitem));
+ prlook( &u->ws );
+ fprintf( foutput, "\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 */
+
+ register struct looksets *q;
+ int j, *w;
+ register *u, *v;
+
+ for( q = &lkst[nlset]; q-- > lkst; ){
+ u = p->lset;
+ v = q->lset;
+ w = & v[tbitset];
+ while( v<w) if( *u++ != *v++ ) goto more;
+ /* we have matched */
+ return( q );
+ more: ;
+ }
+ /* add a new one */
+ q = &lkst[nlset++];
+ if( nlset >= LSETSIZE )error("too many lookahead sets" );
+ SETLOOP(j){
+ q->lset[j] = p->lset[j];
+ }
+ return( q );
+ }