home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-11-17 | 46.3 KB | 1,379 lines |
- /************************************************************************/
- /* y1.c */
- /* YACC source file #1 (of 4). */
- /************************************************************************/
-
- /************************************************************************/
- /* contents */
- /* */
- /* y1ArrayFill Set elements 0 through n-1 to c. */
- /* * y1CharCopy Copy str q into p, returning next free char ptr.*/
- /* * y1CheckEmpty Mark nonterminals which derive the empty string.*/
- /* y1Closure Generate the closure of state i. */
- /* y1Error Write out fatal error comment. */
- /* * y1First Compute an array with the FIRSTS of nonterminals*/
- /* y1GetChar Get one input char. */
- /* * y1Lookahead Return lookahead set. */
- /* * y1MakeStates Generate the states. */
- /* main */
- /* * y1PrintLookahead Print lookahead. */
- /* y1PutItem */
- /* * y1PutRest Put out other arrays, copy the parsers. */
- /* * y1SetUnion A gets union of A and B. */
- /* y1State Sort last state, check it, return state #. */
- /* * y1Summary Write the summary on the terminal. */
- /* y1SymbolName Return a pointer to the name of symbol i. */
- /* y1UngetChar Unget one char. */
- /* y1WriteItem Creates output string for item pointed to by pp.*/
- /* * y1Yield List productions YIELDING each nonterminal. */
- /* */
- /* * Local to this file. */
- /* */
- /************************************************************************/
-
- /************************************************************************/
- /* history */
- /* */
- /* 85Nov14 CrT Global variable names decrypted. */
- /* 85Nov13 CrT Give plaintiff routine in error messages. */
- /* 85Nov11 CrT Function names decrypted. Still unique in first 6 chars.*/
- /* 85Nov10 CrT y1.c reconstructed from 18 (!) subfiles. Cosmetics. */
- /* 83Dec25 SG Questions and suggestions on the IBM PC version of YACC */
- /* can be directed to Scott Guthery, 11100 Leafwood Lane, */
- /* Austin, Texas, 78750. Telephone: 512 258-1342. */
- /* */
- /* 83Dec25 SG Added #ifdef UNION entries in yypars.c so that YACC */
- /* can be used with C compilers that do not support the */
- /* assignment of unions and structures. If you use */
- /* the %union construct (see LANDY.Y for example) and your */
- /* C compiler doesn't support union assignment, then */
- /* you have to write a routine */
- /* yyunion(to, from) */
- /* YYSTYPE *to, *from; */
- /* which achieves the assignment of the %union. If your */
- /* C compiler does support structure and union assignment */
- /* then undefine UNION in yypars.c. */
- /* */
- /* 83Dec25 SG Adapted YACC for IBM PC using the DeSmet C compiler. */
- /* */
- /* 83Apr12 RBD Add symbolic exit status. */
- /* 83Apr12 RBD Additions and minor changes for running YACC under */
- /* VAX-11 C. The newer versions of the files in this */
- /* UIC are the proper ones, and should run OK under */
- /* RSX & RT. I have not purged the old ones because */
- /* I have not tested the new ones. */
- /* */
- /* 82Mar22 RBD Minor changes to accommodate the new DECUS library and */
- /* compiler. Command file changed to take advantage of the */
- /* '-m' switch to disable the preprocessor phase of the */
- /* compiler, since MP is used. 'iovtoa()' changed to */
- /* 'fgetname()'. ODL slightly changed. Added header to */
- /* output file to tell the name of the input file and the */
- /* date and time of generation. */
- /* */
- /* 81Aug28 RBD Changed to make debug code conditionally compile. */
- /* */
- /* 81Aug28 RBD All of the debug stuff has been turned off. This makes */
- /* for a much easier to read YACC.OUT file. */
- /* */
- /* 81Aug28 RBD The options accepted by Yacc have been changed. The */
- /* changes were all in YSETUP.2C. See the docs. */
- /* */
- /* 81Aug28 RBD In using YACC with Forsythe's LEX, the variable */
- /* "yylval" was found to be declared in both YACC's */
- /* output c source (yypars()) and in LEX. Apparently, the */
- /* UNIX LEX assumes that yylval is in YACC. Because LEX */
- /* sees so much use with other than YACC, we chose to */
- /* leave yylval declared in LEX. So the YACC module */
- /* YSETUP.2C was modified to emit "extern YYSTYPE yylval" */
- /* when compiled by the Decus compiler or MP processor. */
- /* */
- /* 81Aug28 RBD Much has happened since the last entry. Yacc has been */
- /* brought up on RSX-11M, along with changes in the */
- /* command string outlined below. */
- /* */
- /* 80Dec18 RBD Add conditional code for Decus for tempfile deletion. */
- /* 80Dec06 RBD Original code broken out of y1.c. */
- /* 80Dec05 RBD MP has been fixed. Note the 'beauty' prettyprinter */
- /* was distributed in this UIC, but it's been deleted. */
- /* */
- /* 80Dec04 RBD Include files and their names need looking at. */
- /* 80Dec04 RBD MP preprocessor inserts a ' ' at the beginning of */
- /* a text substitution. Otherwise, it looks like it */
- /* does the right stuff! */
- /* 80Dec04 RBD Variable declarations inside statements exist. */
- /* */
- /* 7?????? SCJ Created. */
- /* */
- /* */
- /* credits */
- /* CrT=CrT */
- /* RBD=Bob Denny */
- /* SCJ=Steven C Johnson. */
- /* SG =Scott Guthery */
- /* */
- /************************************************************************/
-
-
-
- #include <stdio.h>
- #include "system.h"
- #include "dtxtrn.h"
-
-
-
- # define EMPTY 1
- # define WHOKNOWS 0
- # define OK 1
-
-
- /* The default actions of states. */
- extern int y3DefaultAction[ MAXsTATES ];
-
- /* Character stack shared by y1GetChar and y1UngetChar: */
- static char y1GetStack[ 30 ], *y1TopStack = y1GetStack;
-
-
-
-
- /* Lookahead computations: */
-
- /********************************************************/
- /* Size of lookahead sets in words. Lookahead sets are */
- /* represented by bit vectors with one bit for each */
- /* terminal in the grammar -- this makes set unions a */
- /* simple matter of ORing two bit vectors together. On */
- /* large grammars, YACC spends most of its time doing */
- /* set unions. */
- /********************************************************/
- int y1MaxLookaheadSet;
-
- struct looksets y1LookaheadSet [ MAXy1lOOKAHEADsETS ];
-
- /* Next lookahead set to allocate: */
- static int y1NextLookaheadSet = 0;
-
- /* Flag to suppress lookahead computations: */
- int y1NoLookahead = FALSE;
-
- /* Temporary storage for lookahead computations: */
- static struct looksets y1ClosureSet;
-
-
-
- /* Working set computations: */
-
- struct wset y1WorkingSet[ MAXy1wORKINGsET];
- struct wset *y1ThisWorkingSet;
-
-
-
- /* State information: */
-
- /* Number of states so far: */
- int y1NextState = 0;
-
- /* States generated by terminal gotos: */
- int y1TerminalState[ MAXtERMINALsTATES ];
-
- /* States generated by nonterminal gotos: */
- int y1NonterminalState[ MAXnONTERMINALsTATES ];
-
- /* Type information about the states: */
- int y1StateType[ MAXsTATES ];
-
- /* Index to the stored goto table: */
- int y1GotoIndex[ MAXsTATES ];
-
- /* [Non/]term generation lists overflow chain: */
- static int y1Link[ MAXsTATES ];
-
- /* State-description pointers: */
- struct item *y1StateItem[ MAXsTATES +2 ];
-
-
-
- /* Storage for the actions in the parser: */
-
- /* Action table storage: */
- int y1Action[ MAXaCTIONS ];
-
- /* Next free action table position: */
- int *y1NextAction = y1Action;
-
-
-
- /* Other storage areas: */
-
- /* Scratch area andexed variously by terms+y2NextTerminal or states: */
- int y1Temp[ MAXy1TEMP ];
-
- /* Current input line number: */
- int y1LineNumber = 1;
-
- /* Signal to y1Error(): If y1ErrorsFatal, errors are fatal: */
- static int y1ErrorsFatal = TRUE;
-
- /* Number of errors: */
- int y1Errors = 0;
-
-
-
- /* Storage for information about the nonterminals: */
-
- /* Productions yielding each nonterminal (Ptrs):*/
- static int **y1YieldedBy[ MAXnONTERMINALsTATES +2 ];
-
- /* FIRST sets for nonterminals: */
- static struct looksets *y1FirstOf[ MAXnONTERMINALsTATES +2 ];
-
- /* Nonterminals nontrivially deriving <empty>: */
- static int y1YieldsEmpty[ MAXnONTERMINALsTATES +1 ];
-
-
-
- /* Storage for statistics: */
-
- static struct wset * y1LastWorkingSet = y1WorkingSet;
- int y1GotoEntries = 0;
- int y1GotosSavedByDefault = 0;
-
- int y1ShiftEntries = 0;
- int y1Exceptions = 0;
- static int y1ClosuresDone = 0;
-
- int y1ShiftReduceConflicts = 0;
- int y1ReduceReduceConflicts = 0;
- static * y1Nexty2PoolLoc = y2Pool;
-
-
-
-
-
- /************************************************************************/
- /* y1ArrayFill Set elements 0 through n-1 to c */
- /************************************************************************/
- y1ArrayFill( v, n, c )
- int *v,n,c;
- {
- register int i;
- for( i = n; i--; ) v[i] = c;
- }
-
- /************************************************************************/
- /* y1CharCopy Copy string q into p, returning next free char ptr. */
- /************************************************************************/
- static char *y1CharCopy( p, q )
- char *p, *q;
- {
- while (*p++ = *q++);
-
- return( --p );
- }
-
-
- /************************************************************************/
- /* y1CheckEmpty Mark nonterminals which derive the empty string.*/
- /************************************************************************/
- static y1CheckEmpty() {
-
- /****************************************************************/
- /* Mark nonterminals which derive the empty string. */
- /* Look for nonterminals which don't derive any token strings. */
- /****************************************************************/
-
- register i, *p;
-
-
-
- /************************************************************/
- /* First, use the array y1YieldsEmpty to detect productions */
- /* that can NEVER be reduced: */
- /************************************************************/
-
-
-
- y1ArrayFill( y1YieldsEmpty, y2LastNonterminal+1, WHOKNOWS );
-
- /* Now, look at productions, marking */
- /* nonterminals which derive something: */
-
- more:
- FORaLLpRODUCTIONS(0,i) {
-
- /***********************************************************/
- /* Check nonterminal defined by this production. If we */
- /* already know that nonterminal derives the empty string, */
- /* skip to next production: */
- /***********************************************************/
- if( y1YieldsEmpty[ *y2Production[i] - FIRSTnONTERMINAL ] ) continue;
-
- /************************************************/
- /* Scan RHSide of production. Stop if we reach */
- /* a nonterminal not known to derive something: */
- /************************************************/
- for (p = y2Production[i] +1; *p >= 0; ++p) {
- if (
- *p >= FIRSTnONTERMINAL
- &&
- y1YieldsEmpty[ *p-FIRSTnONTERMINAL ] == WHOKNOWS
- ) {
- break;
- }
- }
-
- /* See if we reached end of production: */
- if (*p < 0) {
-
- /*********************************************************/
- /* Reached end of rule without finding any problematical */
- /* entries, so production can be derived. Mark as safe: */
- /*********************************************************/
- y1YieldsEmpty[ *y2Production[i]-FIRSTnONTERMINAL ] = OK;
-
- /* This may make something else safe, so start over: */
- goto more;
- }
- }
-
- /********************************************************************/
- /* We have now marked all nonterminals known to generate something. */
- /* If any do NOT generate something, issue a warning message: */
- /********************************************************************/
-
- /* Make the useless-nonterminal errors nonfatal so we get all of them: */
- y1ErrorsFatal = FALSE;
-
- FORaLLnONTERMINALS(i) {
-
- /* Ignore the %start nonterminal, which is special: */
- if (!i) continue;
-
- /* All the rest should derive something: */
- if ( y1YieldsEmpty[ i ] != OK ) {
-
- y1Error(
- "y1CheckEmpty: nonterminal %s never derives any token string",
- y2NonterminalState[i].name
- );
- }
- }
- y1ErrorsFatal = TRUE;
-
- /* Quit if there are any useless nonterminals: */
- if (y1Errors) {
- y1Summary();
- exit(EX_ERR);
- }
-
-
-
- /******************************************************************/
- /* Now figure out which nonterminals can derive the empty string: */
- /******************************************************************/
-
-
-
- /* Set y1YieldsEmpty to WHOKNOWS: */
- y1ArrayFill( y1YieldsEmpty, y2LastNonterminal+1, WHOKNOWS );
-
- /* Loop as long as we keep finding empty nonterminals: */
-
- again:
- FORaLLpRODUCTIONS(1,i) {
-
- if (y1YieldsEmpty[ *y2Production[i]-FIRSTnONTERMINAL ] == WHOKNOWS) {
-
- /*****************************************************/
- /* Found a production not known to be empty. */
- /* See if all items on RHSide are known to be empty: */
- /*****************************************************/
-
- for (p = y2Production[ i ] +1; *p >= FIRSTnONTERMINAL; ++p) {
-
- if (y1YieldsEmpty[ *p - FIRSTnONTERMINAL ] != EMPTY) break;
-
- }
-
- if (*p < 0) {
-
- /* We have a nontrivially empty nonterminal: */
- y1YieldsEmpty[ *y2Production[ i ] - FIRSTnONTERMINAL ] = EMPTY;
-
- /* This rule may make another empty, so start over: */
- goto again;
- }
- }
- }
- }
-
- /************************************************************************/
- /* y1Closure Generate the closure of state i */
- /************************************************************************/
- y1Closure( i ) /* Called from y1StateGen and y3Output. */
- int i;
- {
- /************************************************************************/
- /* An "item" of a grammar G is a production of G with a dot at */
- /* some position of the right side. The the production */
- /* */
- /* a : x y z */
- /* */
- /* generates the items */
- /* */
- /* a :.x y z */
- /* a : x.y z */
- /* a : x y.z */
- /* a : x y z. */
- /* */
- /* ... */
- /* */
- /* If i is a set of items for a grammar G, then the set of items */
- /* CLOSURE(i) is constructed from i by the rules */
- /* 1. Every item in i is in CLOSURE(i) */
- /* 2. If "a : x.y z" is in CLOSURE(i) and "b : w" is a production, */
- /* add "b : .w" to i. */
- /* */
- /* (Following Aho & Ullman PRIMCIPLES OF COMPILER DESIGN p205-206.) CrT*/
- /************************************************************************/
-
- int c, ch, work, k;
- register struct wset *u, *v;
- int *pi;
- int **s, **t;
- struct item *q;
- register struct item *p;
- int num;
-
-
- ++y1ClosuresDone;
-
- /* First, copy kernel of state i to y1WorkingSet: */
-
- y1ThisWorkingSet = y1WorkingSet;
- FORaLLiTEMS(i,p,q) {
-
- y1ThisWorkingSet->pitem = p->pitem;
-
- /* This item must get closed. */
- y1ThisWorkingSet->flag = TRUE;
-
- /* Copy the set over: */
- FORaLLlOOKAHEADwORDS(k) {
- y1ThisWorkingSet->ws.lset[k] = p->look->lset[k];
- }
-
- NEXTwORKINGsET( y1ThisWorkingSet );
- }
-
- /* Loop until no items remain to be closed: */
- for (work = TRUE; work; ) {
-
- work = FALSE;
-
- FORaLLwORKINGsETS( y1WorkingSet, u ) {
-
- /* Find an item with the close flag set: */
- if (!u->flag) continue;
-
- /* Found one. Dot is before c: */
- c = *(u->pitem);
-
- /* Only interesting case is where dot is before a nonterminal: */
- if (c < FIRSTnONTERMINAL) {
-
- /* Dot is before a terminal in this item: */
- u->flag = FALSE;
- continue;
- }
-
- /* Compute the lookahead: */
-
- y1ArrayFill( y1ClosureSet.lset, y1MaxLookaheadSet, 0 );
-
- /* Find items involving c: */
- FORaLLwORKINGsETS(u,v) {
-
- if (v->flag && *(pi=v->pitem) == c) {
- v->flag = FALSE;
-
- if (y1NoLookahead) continue;
-
- while ((ch = *++pi) > 0) {
-
- if (ch < FIRSTnONTERMINAL) {
- /* Terminal symbol: */
- SETBIT( y1ClosureSet.lset, ch );
- break;
- }
-
- /* Nonterminal symbol: */
- num = ch-FIRSTnONTERMINAL;
- y1SetUnion( y1ClosureSet.lset, y1FirstOf[num]->lset );
- if (!y1YieldsEmpty[ num ]) break;
- }
- if (ch <= 0) y1SetUnion( y1ClosureSet.lset, v->ws.lset );
- }
- }
-
- /* Now loop over productions derived from c: */
-
- c -= FIRSTnONTERMINAL; /* c is now nonterminal number */
-
- t = y1YieldedBy[ c+1 ];
- for (s = y1YieldedBy[ c ]; s < t; ++s) {
-
- /* Put these items into the closure: */
- FORaLLwORKINGsETS(y1WorkingSet,v) {
-
- /* Is the item there? */
- if (v->pitem == *s) {
-
- /* Yes, it is there: */
- if (y1NoLookahead) goto nexts;
- if (y1SetUnion( v->ws.lset, y1ClosureSet.lset )) {
- v->flag = work = TRUE;
- }
- goto nexts;
- }
- }
-
- /* Not there; make a new entry: */
- if (y1ThisWorkingSet-y1WorkingSet+1 >= MAXy1wORKINGsET) {
- y1Error( "y1Closure: Working set overflow" );
- }
- y1ThisWorkingSet->pitem = *s;
- y1ThisWorkingSet->flag = TRUE;
- if (!y1NoLookahead) {
- work = TRUE;
- FORaLLlOOKAHEADwORDS(k) {
- y1ThisWorkingSet->ws.lset[k] = y1ClosureSet.lset[k];
- }
- }
- NEXTwORKINGsET( y1ThisWorkingSet );
- nexts: ;
- }
-
- }
- }
-
- /* We have computed closure. Flags are reset. Return: */
- if (y1LastWorkingSet < y1ThisWorkingSet) {
- y1LastWorkingSet = y1ThisWorkingSet;
- }
-
- #ifdef debug
- if (y2OutputFD != NULL) {
- fprintf(
- y2OutputFD,
- "\nState %d, y1NoLookahead = %d\n",
- i,
- y1NoLookahead
- );
- FORaLLwORKINGsETS(y1WorkingSet,u) {
- if (u->flag) fprintf( y2OutputFD, "flag set!\n");
- u->flag = FALSE;
- fprintf( y2OutputFD, "\t%s", y1WriteItem(u->pitem));
- y1PrintLookahead( &u->ws );
- fprintf( y2OutputFD, "\n" );
- }
- }
- #endif
- }
-
-
- /************************************************************************/
- /* y1Error Write out fatal error comment. */
- /************************************************************************/
- y1Error( s, a1 ) /* Called from everywhere. */
- char *s;
- {
- ++y1Errors;
- fprintf( stderr, "\nFATAL ERROR: " );
- fprintf( stderr, s, a1 );
- fprintf( stderr, ", line %d\n", y1LineNumber );
-
- if (!y1ErrorsFatal) return;
-
- y1Summary();
-
- exit(EX_ERR);
- }
-
- /************************************************************************/
- /* y1First Compute an array with the FIRST of nonterminals */
- /************************************************************************/
- y1First() { /* Called only from main. */
-
- register *p, **s, i, **t, ch, changes;
-
- /**************************************************************/
- /* For each nonterminal NT defined by the grammar, we want to */
- /* figure out which terminals can occur first in a string */
- /* defined by NT. This is a simple matter of enumerating */
- /* all terminals which occur at the start of a production */
- /* defining NT, and then adding in the recursively computed */
- /* FIRSTs of all nonterminals starting NT productions: */
- /**************************************************************/
-
- y1LastWorkingSet = &y1WorkingSet[ y2LastNonterminal ];
-
- /********************************************************************/
- /* Do the first pass, finding for each nonterminal NT all terminals */
- /* occurring at the start of a production defining NT: */
- /********************************************************************/
-
- FORaLLnONTERMINALS(i) {
-
- /* Allocate a set to hold FIRST of this nonterminal: */
- y1ArrayFill( y1WorkingSet[i].ws.lset, y1MaxLookaheadSet, 0 );
-
- /* Iterate over the list of productions defining our nonterminal: */
- t = y1YieldedBy[ i+1 ];
- for (s = y1YieldedBy[i]; s < t; ++s ) {
-
- /*************************************************************/
- /* If this rule starts with a terminal, add it to our FIRST */
- /* set. If the rule starts with a nonterminal that can */
- /* derive the empty string, then look at the next entry: */
- /*************************************************************/
-
- for (p = *s; (ch = *p) > 0; ++p) {
-
- if (ch < FIRSTnONTERMINAL) {
-
- /* Found a terminal, add it to FIRST set: */
- SETBIT( y1WorkingSet[i].ws.lset, ch );
- break;
-
- } else {
-
- /* Found a nonterminal. Finished with this rule */
- /* unless the nonterminal can derive <empty>: */
- if (!y1YieldsEmpty[ ch-FIRSTnONTERMINAL ]) break;
- }
- }
- }
- }
-
- /****************************************************************/
- /* Do the second pass, adding to FIRST(NT) FIRST(NT') for all */
- /* nonterminals NT' which occur first in a rule defining NT: */
- /****************************************************************/
-
- for (changes = TRUE; changes; ) {
- changes = FALSE;
-
- FORaLLnONTERMINALS(i) {
-
- /* Iterate over the set of productions defining nonterminal i: */
- t = y1YieldedBy[i+1];
- for (s = y1YieldedBy[i]; s < t; ++s) {
-
- /************************************************************/
- /* If this production starts with a nonterminal NT, collect */
- /* its FIRST set. As before, if NT can derive the empty */
- /* string then we have to collect FIRST of the following */
- /* item also: */
- /************************************************************/
-
- for (p = *s; (ch = (*p-FIRSTnONTERMINAL)) >= 0; ++p) {
- changes |= y1SetUnion(
- y1WorkingSet[i].ws.lset,
- y1WorkingSet[ch].ws.lset
- );
- if (!y1YieldsEmpty[ ch ]) break;
- }
- }
- }
- }
-
- /********************************************************/
- /* Finished! Now index the results for later reference, */
- /* simultaneously merging identical lookahead sets: */
- /********************************************************/
-
- FORaLLnONTERMINALS(i) y1FirstOf[i] = y1Lookahead( &y1WorkingSet[i].ws );
- #ifdef debug
- if (y2OutputFD != NULL) {
- FORaLLnONTERMINALS(i) {
- fprintf( y2OutputFD, "\n%s: ", y2NonterminalState[i].name );
- y1PrintLookahead( y1FirstOf[i] );
- fprintf( y2OutputFD, " %d\n", y1YieldsEmpty[i] );
- }
- }
- #endif
- }
-
- /************************************************************************/
- /* y1GetChar Get one input char */
- /************************************************************************/
- y1GetChar( iop ) /* Called from everywhere */
- FILE *iop;
- {
- if (y1TopStack == y1GetStack) return getc(iop) ;
- else return *--y1TopStack;
- }
-
- /************************************************************************/
- /* y1Lookahead Return lookahead set */
- /************************************************************************/
- static struct looksets *y1Lookahead( p )
- struct looksets *p; /* Called from: y1First, y1PutItem, y1State */
- {
- /* Decide if the lookahead set pointed to by p is known. */
- /* Return pointer to a permanent location for the set. */
-
- register struct looksets *q;
- int j, *w;
- register *u, *v;
-
- /* Over all known lookahead sets q, see if q == p: */
- for( q = &y1LookaheadSet[ y1NextLookaheadSet ]; q-- > y1LookaheadSet; ) {
-
- u = p->lset;
- v = q->lset;
-
- w = &v[ y1MaxLookaheadSet ];
-
- /* Match all pair of corresponding words in p and q: */
- while (v < w) if (*u++ != *v++) goto more;
-
- /* P matches q -- return q */
- return( q );
- more: ;
- }
-
- /* P is different from all known lookahead sets -- enter it: */
- q = &y1LookaheadSet[ y1NextLookaheadSet++ ];
-
- /* Check for too many lookahead sets: */
- if (y1NextLookaheadSet >= MAXy1lOOKAHEADsETS) {
- y1Error("y1Lookahead: Too many lookahead sets");
- }
-
- /* Copy p to permanent storage location: */
- FORaLLlOOKAHEADwORDS(j) {
- q->lset[j] = p->lset[j];
- }
- return( q );
- }
-
- /************************************************************************/
- /* y1MakeStates Generate the states. */
- /************************************************************************/
- static y1MakeStates() { /* Called only from main. */
- int i, j;
- register c;
- register struct wset *p, *q;
-
- /********************************************************************/
- /* Running your eye over a yacc grammar, you can imagine the parser */
- /* proceeding methodically through the appropriate rules, looking */
- /* always for the next token in the current rule. In fact, however,*/
- /* one may have several rules which begin identically (say), so the */
- /* parser must keep track of where it is in all the grammar rules */
- /* which >might< turn out to be the right one. Thus, at any given */
- /* time, the parser is in effect in a set of states rather than a */
- /* single state. In this routine we precompute all valid sets of */
- /* states which the parser might wind up in. This is a simple */
- /* matter of starting at the root nonterminal of the grammar and */
- /* proceeding all possible directions simultaneously... :-) CrT*/
- /********************************************************************/
-
- /* Initialize */
-
- y1NextState = 0;
- /**************************************************************************/
- /* This is funny from the standpoint of portability. */
- /* It represents the magic moment when the y2Pool 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. SCJ.*/
- /**************************************************************************/
-
- y1StateItem[ 0 ] = y1StateItem[ 1 ] = (struct item *) y2FreePool;
-
- y1ArrayFill( y1ClosureSet.lset, y1MaxLookaheadSet, 0 );
-
- y1PutItem( y2Production[ 0 ]+1, &y1ClosureSet );
-
- /* Start state expansion at the root nonterminal: */
- y1StateType[ 0 ] = MUSTdOsTATE;
- y1NextState = 1;
- y1StateItem[ 2 ] = y1StateItem[ 1 ];
-
- y1ArrayFill( y1Action, MAXaCTIONS, 0 );
-
- /* Now, the main state generation loop: */
-
- more:
- FORaLLsTATES(i) {
-
- /* Find a state which needs expanding: */
- if (y1StateType[i] != MUSTdOsTATE) continue;
-
- /* Mark it as done: */
- y1StateType[ i ] = DONEsTATE;
-
- /* Erase our scratchpad set: */
- y1ArrayFill( y1Temp, y2LastNonterminal+1, 0 );
-
- /* Take state i, close it, and do gotos: */
- y1Closure(i);
-
- /*************************************************************/
- /*"For item set i and grammar symbol x, GOTO(i,x) is defined */
- /* to be the closure of the set of all items 'a : bx.c' such */
- /* that 'a : b.xc' is in i..." */
- /* Aho & Ullman PRINCIPLES OF COMPILER DESIGN p207. CrT*/
- /*************************************************************/
-
- FORaLLwORKINGsETS(y1WorkingSet,p) {
-
- /* Generate goto's: */
- if (p->flag) continue;
- p->flag = TRUE;
- c = *(p->pitem);
-
- if (c <= 1) {
- if (y1StateItem[i+1]-y1StateItem[i] <= p-y1WorkingSet) {
- y1StateType[i] = MUSTlOOKaHEADsTATE;
- }
- continue;
- }
-
- /* Do a goto on c: */
- FORaLLwORKINGsETS(p,q) {
- if (c == *(q->pitem)) {
-
- /* This item contributes to the goto: */
- y1PutItem( q->pitem + 1, &q->ws );
- q->flag = TRUE;
- }
- }
-
- if (c < FIRSTnONTERMINAL) {
- y1State(c); /* Register new state */
- } else {
- y1Temp[c-FIRSTnONTERMINAL] = y1State(c);
- }
- }
- #ifdef debug
- if (y2OutputFD != NULL) {
- fprintf( y2OutputFD, "%d: ", i );
- FORaLLnONTERMINALS(j) {
- if (y1Temp[j]) {
- fprintf(
- y2OutputFD,
- "%s %d, ",
- y2NonterminalState[j].name,
- y1Temp[j]
- );
- }
- }
- fprintf( y2OutputFD, "\n");
- }
- #endif
- y1GotoIndex[i] = y3PackState( &y1Temp[1], y2LastNonterminal-1 ) - 1;
-
- /* We have done one goto; Do some more: */
- goto more;
- }
- /* No more to do: Stop. */
- }
-
-
- /************************************************************************/
- /* main */
- /************************************************************************/
- main( argc, argv )
- int argc;
- char *argv[];
- {
- /* Initialize and read productions: */
- puts("\ry2Initialize... \r");
- y2Initialize(argc,argv);
-
- /* Process input file, stashing results in appropriate the tables: */
- puts("\ry2yyParse... \r");
- y2yyParse();
-
- /* Build yyActionIndex[] so parser can find user action chunks: */
- puts("\ry3ActionIndex... \r");
- y3ActionIndex();
-
- /* Figure how many words a set of terminals requires, taking */
- /* into account bits per word and number of terminals: */
- y1MaxLookaheadSet = NWORDS(y2NextTerminal);
-
- /* Find all productions defining each nonterminal: */
- puts("\ry1Yield... \r");
- y1Yield();
-
- /* Figure out which nonterminals can match the empty string: */
- puts("\ry1CheckEmpty... \r");
- y1CheckEmpty();
-
- /* Make a table of FIRSTs of nonterminals: */
- puts("\ry1First... \r");
- y1First();
-
- /* Generate the states: */
- puts("\ry1MakeStates... \r");
- y1MakeStates();
-
- /* Write the states and the tables: */
- puts("\ry3PutStates... \r");
- y3PutStates();
-
- puts("\ry3Gotos... \r");
- y3Gotos();
-
- puts("\ry3HideProductions... \r");
- y3HideProductions();
-
- puts("\ry1Summary... \r");
- y1Summary();
-
- puts("\ry4Optimize... \r");
- y4Optimize();
-
- puts("\ry1PutRest... \r");
- y1PutRest();
-
- puts("\rDone. \r");
- exit(EX_SUC);
- }
-
-
- /************************************************************************/
- /* y1PutRest Put out other arrays, copy the parsers. */
- /************************************************************************/
- static y1PutRest() { /* Called only from main. */
- register c, i, j;
-
- y2InputFD = fopen( PARSER, "r" );
- if (y2InputFD == NULL) {
- y1Error( "y1PutRest: Cannot find parser file '%s'", PARSER );
- }
-
- y3PutArray( "yyr1", y2ProductionProperties, y2ThisProduction );
-
- y1ArrayFill( y1Temp, y2ThisProduction, 0 );
- FORaLLpRODUCTIONS( 1,i ) y1Temp[i] = y2Production[i+1]-y2Production[i]-2;
- y3PutArray( "yyr2", y1Temp, y2ThisProduction );
-
- y1ArrayFill( y1Temp, y1NextState, -1000 );
- FORaLLtERMINALS(i) {
- for(j = y1TerminalState[i]; j != 0; j = y1Link[j]) {
- y1Temp[j] = y2Terminal[i].value;
- }
- }
- FORaLLnONTERMINALS(i) {
- for (j = y1NonterminalState[i]; j != 0; j = y1Link[j]) {
- y1Temp[j] = -i;
- }
- }
- y3PutArray( "yychk", y1Temp, y1NextState );
-
- y3PutArray( "yydef", y3DefaultAction, y1NextState );
-
- /* Copy parser text: */
- while ((c = y1GetChar(y2InputFD)) != EOF) {
- if (c == '$') {
- if ((c = y1GetChar(y2InputFD)) != 'A') putc( '$', y2ytabcFD );
- else {
- /* Copy actions: */
- y2ActionFD = fopen( ACTNAME, "r" );
- if (y2ActionFD == NULL) {
- y1Error( "y1PutRest: Cannot reopen action tempfile" );
- }
- while( (c=y1GetChar(y2ActionFD) ) != EOF ) putc( c, y2ytabcFD );
- fclose(y2ActionFD);
- ZAPFILE(ACTNAME);
- c = y1GetChar(y2InputFD);
- }
- }
- putc( c, y2ytabcFD );
- }
- fclose( y2ytabcFD );
- }
-
- /************************************************************************/
- /* y1PrintLookahead Print lookahead. */
- /************************************************************************/
- static y1PrintLookahead( p ) /* Called from y1Closure, y1First */
- struct looksets *p;
- {
- register j, *pp;
- pp = p->lset;
-
- if (pp == 0) fprintf( y2OutputFD, "\tNULL" );
- else {
- fprintf( y2OutputFD, " { " );
- FORaLLtERMINALS(j) {
- if (GETBIT(pp,j)) fprintf( y2OutputFD, "%s ", y1SymbolName(j) );
- }
- fprintf( y2OutputFD, "}" );
- }
- }
-
- /************************************************************************/
- /* y1PutItem */
- /************************************************************************/
- y1PutItem( ptr, lptr ) /* Called from y1MakeStates, y3Output */
- int *ptr;
- struct looksets *lptr;
- {
- register struct item *j;
-
- #ifdef debug
- if (y2OutputFD != NULL) {
- fprintf(
- y2OutputFD,
- "y1PutItem(%s), state %d\n",
- y1WriteItem(ptr),
- y1NextState
- );
- }
- #endif
- j = y1StateItem[ y1NextState+1 ];
- j->pitem = ptr;
- if (!y1NoLookahead) j->look = y1Lookahead( lptr );
- y1StateItem[ y1NextState+1 ] = ++j;
-
- if (((int *)j) > y1Nexty2PoolLoc) {
- y1Nexty2PoolLoc = (int *)j;
- if( y1Nexty2PoolLoc >= &y2Pool[MAXy2POOL] ) {
- y1Error( "y1PutItem: Out of state space" );
- }
- }
- }
-
-
- /************************************************************************/
- /* y1SetUnion A gets union of A and B. */
- /************************************************************************/
- static y1SetUnion( a, b ) /* Called by y1First, y1Closure, y1State. */
- 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;
- FORaLLlOOKAHEADwORDS(i) {
- *a = (x = *a)|*b++;
- if (*a++ != x) sub = 1;
- }
- return sub;
- }
-
-
- /************************************************************************/
- /* y1State Sort last state, check it, return state #. */
- /************************************************************************/
- y1State( c ) /* Called in y3Output, y1MakeStates */
- int c;
- {
- /* Sort last state, and see if it equals earlier ones. return state #: */
-
- int size1,size2;
- register i;
- int *s; /*01*/
- struct looksets *ss; /*01*/
- int s__; /*01*/
- struct item *p1, *p2, *k, *l, *q1, *q2;
-
- p1 = y1StateItem[y1NextState];
- p2 = y1StateItem[y1NextState+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;
- ss = k->look;
- k->look = l->look;
- l->look = ss;
- }
- }
- }
-
- /* Figure size of state: */
- size1 = p2 - p1;
-
- for (
- i = (c >= FIRSTnONTERMINAL) ? y1NonterminalState[ c-FIRSTnONTERMINAL ] : y1TerminalState[ c ]
- ;
- i != 0
- ;
- i = y1Link[i]
- ) {
- /* Get ith state */
- q1 = y1StateItem[ i ];
- q2 = y1StateItem[ 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: */
-
- /* Delete last state: */
- y1StateItem[y1NextState+1] = y1StateItem[y1NextState];
-
- /* Fix up lookaheads: */
- if (y1NoLookahead) return(i);
- for (l = q1 , k = p1; l < q2; ++l, ++k) {
- FORaLLlOOKAHEADwORDS(s__) y1ClosureSet.lset[s__] = l->look->lset[s__];
-
- if (y1SetUnion( y1ClosureSet.lset, k->look->lset )) {
- y1StateType[i] = MUSTdOsTATE;
-
- /* Register the new set: */
- l->look = y1Lookahead( &y1ClosureSet );
- }
- }
- return i;
- }
-
- /* State is new: */
- if (y1NoLookahead) y1Error( "y1State: Yacc state/y1NoLookahead error" );
- y1StateItem[ y1NextState+2 ] = p2;
- if (y1NextState+1 >= MAXsTATES) y1Error("y1State: Too many states" );
-
- if (c >= FIRSTnONTERMINAL) {
- y1Link[ y1NextState ] = y1NonterminalState[ c-FIRSTnONTERMINAL ];
- y1NonterminalState[ c-FIRSTnONTERMINAL ] = y1NextState;
- } else {
- y1Link[ y1NextState ] = y1TerminalState[ c ];
- y1TerminalState[ c ] = y1NextState;
- }
- y1StateType[y1NextState]=MUSTdOsTATE;
- return y1NextState++;
- }
-
-
- /************************************************************************/
- /* y1Summary Write the summary on the terminal. */
- /************************************************************************/
- static y1Summary() { /* Called in y1CheckEmpty, y1Yield, y1Error, main */
-
-
- if (y2OutputFD != NULL) {
- fprintf(
- y2OutputFD,
- "\n%d/%d terminals, %d/%d nonterminals\n",
- y2NextTerminal,
- MAXtERMINALsTATES,
- y2LastNonterminal,
- MAXnONTERMINALsTATES
- );
- fprintf(
- y2OutputFD,
- "%d/%d grammar rules, %d/%d states\n",
- y2ThisProduction,
- MAXpRODUCTIONS,
- y1NextState,
- MAXsTATES
- );
- fprintf(
- y2OutputFD,
- "%d shift/reduce, %d reduce/reduce conflicts reported\n",
- y1ShiftReduceConflicts,
- y1ReduceReduceConflicts
- );
- fprintf(
- y2OutputFD,
- "%d/%d working sets used\n", y1LastWorkingSet-y1WorkingSet,
- MAXy1wORKINGsET
- );
- fprintf(
- y2OutputFD,
- "memory: states,etc. %d/%d, parser %d/%d\n",
- y1Nexty2PoolLoc-y2Pool,
- MAXy2POOL,
- y1NextAction-y1Action,
- MAXaCTIONS
- );
- fprintf(
- y2OutputFD,
- "%d/%d distinct lookahead sets\n",
- y1NextLookaheadSet,
- MAXy1lOOKAHEADsETS
- );
- fprintf( y2OutputFD, "%d extra closures\n", y1ClosuresDone - 2*y1NextState );
- fprintf(
- y2OutputFD,
- "%d shift entries, %d exceptions\n",
- y1ShiftEntries,
- y1Exceptions
- );
- fprintf( y2OutputFD, "%d goto entries\n", y1GotoEntries );
- fprintf( y2OutputFD, "%d entries saved by goto default\n", y1GotosSavedByDefault );
- }
- if (y1ShiftReduceConflicts || y1ReduceReduceConflicts) {
- fprintf( stdout,"\nconflicts: ");
- if (y1ShiftReduceConflicts) fprintf( stdout, "%d shift/reduce" , y1ShiftReduceConflicts );
- if (y1ShiftReduceConflicts && y1ReduceReduceConflicts) fprintf( stdout, ", " );
- if (y1ReduceReduceConflicts) fprintf( stdout, "%d reduce/reduce" , y1ReduceReduceConflicts );
- fprintf( stdout, "\n" );
- }
-
- fclose( y2TempFileFD );
- if (y2DefineFD != NULL) fclose( y2DefineFD );
- }
-
-
- /************************************************************************/
- /* y1SymbolName Return a pointer to the name of symbol i. */
- /************************************************************************/
- char *y1SymbolName( i ) /* Called from all over */
- int i;
- {
- char *cp;
-
- cp = (i>=FIRSTnONTERMINAL) ? y2NonterminalState[i-FIRSTnONTERMINAL].name : y2Terminal[i].name ;
-
- if (*cp == ' ') ++cp;
-
- return cp;
- }
-
- /************************************************************************/
- /* y1UngetChar Unget one char. */
- /************************************************************************/
- y1UngetChar(c, iop) /* Called from all over. */
- char c;
- FILE iop; /* WARNING: iop ignored ... y1UngetChar's are multiplexed!!! */
- {
- *y1TopStack++ = c;
- }
-
- /************************************************************************/
- /* y1WriteItem Creates output string for item pointed to by pp.*/
- /************************************************************************/
- char *y1WriteItem(pp) /* Called from: y1Closure, y1PutItem, */
- int *pp; /* y3HideProductions, y3WriteState */
- {
- static char sarr[ISIZE];
- char *q;
- int i;
- int *p;
-
- for (p = pp; *p > 0; ++p);
- p = y2Production[-*p];
- q = y1CharCopy( sarr, y2NonterminalState[*p-FIRSTnONTERMINAL].name );
- q = y1CharCopy( q, " : " );
-
- loop {
- *q++ = ++p==pp ? '_' : ' ';
- *q = '\0';
- if ((i = *p) <= 0) break;
- q = y1CharCopy( q, y1SymbolName(i) );
- if (q > &sarr[ISIZE-30]) y1Error( "y1WriteItem: Item too big" );
- }
-
- if ((i = *pp) < 0) {
- /* An item calling for a reduction: */
- q = y1CharCopy( q, " (" );
- sprintf( q, "%d)", -i );
- }
- return( sarr );
- }
-
- /************************************************************************/
- /* y1Yield List productions yielding each nonterminal. */
- /************************************************************************/
- static y1Yield() { /* Called only by main. */
-
- /********************************************/
- /* First stage of grammar processing: */
- /* For each nonterminal NT, find all the */
- /* alternate rules defining NT. */
- /* y1YieldedBy[] points to these lists. */
- /* pyield[] has the lists: the */
- /* total size is only MAXpRODUCTIONS+1 */
- /********************************************/
-
- static int *pyield[ MAXpRODUCTIONS ];
- register **pmem;
- register c, j, i;
-
-
- pmem = pyield;
-
- /*****************************************************/
- /* Want to identify all undefined nonterminals, not */
- /* just first, so make errors nonfatal for now: */
- /*****************************************************/
- y1ErrorsFatal = FALSE;
-
- /* Tackle all nonterminals sequentially: */
- FORaLLnONTERMINALS(i) {
-
- /* Figure internal name for this nonterminal: */
- c = i + FIRSTnONTERMINAL;
-
- y1YieldedBy[ i ] = pmem;
-
- /* Check all productions in memory: */
- FORaLLpRODUCTIONS(0,j) {
-
- /********************************************************/
- /* The nonterminal defined by a rule is the first entry */
- /* in it. Remember this rule if it defines our current */
- /* nonterminal: */
- /********************************************************/
- if (*y2Production[j] == c) *pmem++ = y2Production[j]+1;
- }
-
- /* If we found no rules defining this nonterminal, complain: */
- if (y1YieldedBy[i] == pmem) {
- y1Error(
- "y1Yield: Nonterminal %s not defined!",
- y2NonterminalState[ i ].name
- );
- }
- }
-
- /* Leave pointer to remaining free memory: */
- y1YieldedBy[i] = pmem;
-
- /* Errors are again fatal until further notice: */
- y1ErrorsFatal = TRUE;
-
- /* Quit if there were any undefined nonterminals: */
- if (y1Errors) {
- y1Summary();
- exit(EX_ERR);
- }
-
- /* Just for fun, check that we found exactly as many rules as expected: */
- if (pmem != &pyield[ y2ThisProduction ]) {
- y1Error(
- "y1Yield: Internal Yacc error: pyield %d",
- pmem-&pyield[y2ThisProduction]
- );
- }
- }
-
-