# include "dextern"
# include "files"
	/*     * * * *    y a c c     * * * *     */

	/*      features to be fixed up ...

	***  provide the ability to change table sizes dynamically
	***  Make the output line numbers agree with the input line numbers
	***  Engage in newspeak: production=>grammar rules, term=>token, etc.
	***  handle # define, #ifdef, etc., in yacc actions, %{ %}
	***  say ACCEPT, not "shift 8191", in S/R message
	*/

	/*      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
	***  input controlled by a grammar
	***  support multiple choices for  conflicts
	***  better conflict diagnostics
	*/



main(argc,argv) int argc; char *argv[]; {

	setup(argc,argv); /* initialize and read productions */
	tbitset = NWORDS(nterms);
	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;

	/* this outputs the other arrays, after the
	/* size of the action array is known (this is needed for
	/* ratfor... */

	/* this routine uses
		prdptr,
		trmset,
		tstates,
		mstates,
		ntstates,
		defact,
		levprd,
		cnames

	/* the other space can have been clobbered for use of the optimizer */

	finput = fopen( parser[lflag], "r" );
	if( finput == NULL ) error( "cannot find parser %s", parser[lflag] );

	(*warray[lflag])( "yyr1", levprd, nprod );

	aryfil( temp1, nprod, 0 );
	PLOOP(1,i)temp1[i] = prdptr[i+1]-prdptr[i]-2;
	(*warray[lflag])( "yyr2", temp1, nprod );

	aryfil( temp1, nstate, -1000 );
	TLOOP(i){
		for( j=tstates[i]; j!=0; j=mstates[j] ){
			temp1[j] = trmset[i].value;
			}
		}
	NTLOOP(i){
		for( j=ntstates[i]; j!=0; j=mstates[j] ){
			temp1[j] = -i;
			}
		}
	(*warray[lflag])( "yychk", temp1, nstate );

	(*warray[lflag])( "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 : trmset[i].name ;
	if( *cp == ' ' ) ++cp;
	return( cp );
	}

summary(){ /* output the summary on the tty */

	if( foutput!=NULL ){
		fprintf( foutput, "\n%d/%d terminals, %d/%d nonterminals\n", nterms, tlim,
			    nnonter, ntlim );
		fprintf( foutput, "%d/%d grammar rules, %d/%d states\n", nprod, prdlim, nstate, stsize );
		fprintf( foutput, "%d shift/reduce, %d reduce/reduce conflicts reported\n", zzsrconf, zzrrconf );
		fprintf( foutput, "%d/%d working sets used\n", zzcwp-wsets,  wssize );
		fprintf( foutput, "memory: states,etc. %d/%d, parser %d/%d\n", zzmemsz, memsiz,
			    memp-amem, actsiz );
		fprintf( foutput, "%d/%d distinct lookahead sets\n", nlset, lsetsz );
		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 );
	}

/* VARARGS */
error(s,a1){ /* 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);
	}

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;
	}

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( pp ) int *pp;{
	int j;
	pp = pp->lset;
	if( pp == 0 ) fprintf( foutput, "\tNULL");
	else {
		fprintf( foutput, " { " );
		TLOOP(j) {
			if( BIT(pp,j) ) fprintf( foutput,  "%s ", symnam(j) );
			}
		fprintf( foutput,  "}" );
		}
	}

concat( s, t, u ) char *s, *t, *u; {
	/* copies the concatenation of t and u into s */
		 while( *t ) *s++ = *t++;
	while( *s++ = *u++ );
	}
