diff options
author | rsc <devnull@localhost> | 2004-04-21 22:49:15 +0000 |
---|---|---|
committer | rsc <devnull@localhost> | 2004-04-21 22:49:15 +0000 |
commit | a9df759c98d44d6c1c8c3f5665b19ac7c6d75060 (patch) | |
tree | ec402abae27ef03aee53e879a0bc6f455d6d84f6 /src/cmd/yacc.c | |
parent | fb36ed82ec7470efe4e334ddc054bcb4fa06ae9e (diff) | |
download | plan9port-a9df759c98d44d6c1c8c3f5665b19ac7c6d75060.tar.gz plan9port-a9df759c98d44d6c1c8c3f5665b19ac7c6d75060.tar.bz2 plan9port-a9df759c98d44d6c1c8c3f5665b19ac7c6d75060.zip |
new stuff.
Diffstat (limited to 'src/cmd/yacc.c')
-rw-r--r-- | src/cmd/yacc.c | 2939 |
1 files changed, 0 insertions, 2939 deletions
diff --git a/src/cmd/yacc.c b/src/cmd/yacc.c deleted file mode 100644 index 6614414d..00000000 --- a/src/cmd/yacc.c +++ /dev/null @@ -1,2939 +0,0 @@ -#include <u.h> -#include <libc.h> -#include <bio.h> -#include <ctype.h> - -#define Bungetrune Bungetc /* ok for now. */ - -/* - * all these are 32 bit - */ -#define TBITSET ((32+NTERMS)/32) /* BOTCH?? +31 */ -#define BIT(a,i) ((a)[(i)>>5] & (1<<((i)&037))) -#define SETBIT(a,i) ((a)[(i)>>5] |= (1<<((i)&037))) -#define NWORDS(n) (((n)+32)/32) - -#define PARSER "#9/lib/yaccpar" -#define PARSERS "#9/lib/yaccpars" -#define TEMPNAME "y.tmp.XXXXXX" -#define ACTNAME "y.acts.XXXXXX" -#define OFILE "tab.c" -#define FILEU "output" -#define FILED "tab.h" -#define FILEDEBUG "debug" - -enum -{ -/* - * the following are adjustable - * according to memory size - */ - ACTSIZE = 40000, - MEMSIZE = 40000, - NSTATES = 2000, - NTERMS = 511, - NPROD = 1600, - NNONTERM = 600, - TEMPSIZE = 2000, - CNAMSZ = 10000, - LSETSIZE = 2400, - WSETSIZE = 350, - - NAMESIZE = 50, - NTYPES = 63, - ISIZE = 400, - - PRIVATE = 0xE000, /* unicode private use */ - - /* relationships which must hold: - TBITSET ints must hold NTERMS+1 bits... - WSETSIZE >= NNONTERM - LSETSIZE >= NNONTERM - TEMPSIZE >= NTERMS + NNONTERM + 1 - TEMPSIZE >= NSTATES - */ - - NTBASE = 010000, - ERRCODE = 8190, - ACCEPTCODE = 8191, - - NOASC = 0, /* no assoc. */ - LASC = 1, /* left assoc. */ - RASC = 2, /* right assoc. */ - BASC = 3, /* binary assoc. */ - - /* flags for state generation */ - - DONE = 0, - MUSTDO = 1, - MUSTLOOKAHEAD = 2, - - /* flags for a rule having an action, and being reduced */ - - ACTFLAG = 04, - REDFLAG = 010, - - /* output parser flags */ - YYFLAG1 = -1000, - - /* parse tokens */ - IDENTIFIER = PRIVATE, - MARK, - TERM, - LEFT, - RIGHT, - BINARY, - PREC, - LCURLY, - IDENTCOLON, - NUMBER, - START, - TYPEDEF, - TYPENAME, - UNION, - - ENDFILE = 0, - - EMPTY = 1, - WHOKNOWS = 0, - OK = 1, - NOMORE = -1000, -}; - - /* macros for getting associativity and precedence levels */ - -#define ASSOC(i) ((i)&03) -#define PLEVEL(i) (((i)>>4)&077) -#define TYPE(i) (((i)>>10)&077) - - /* macros for setting associativity and precedence levels */ - -#define SETASC(i,j) i |= j -#define SETPLEV(i,j) i |= (j<<4) -#define SETTYPE(i,j) i |= (j<<10) - - /* looping macros */ - -#define TLOOP(i) for(i=1; i<=ntokens; i++) -#define NTLOOP(i) for(i=0; i<=nnonter; i++) -#define PLOOP(s,i) for(i=s; i<nprod; i++) -#define SLOOP(i) for(i=0; i<nstate; i++) -#define WSBUMP(x) x++ -#define WSLOOP(s,j) for(j=s; j<cwp; j++) -#define ITMLOOP(i,p,q) for(q=pstate[i+1], p=pstate[i]; p<q; p++) -#define SETLOOP(i) for(i=0; i<tbitset; i++) - - /* command to clobber tempfiles after use */ - -#define ZAPFILE(x) if(x) remove(x) - - /* I/O descriptors */ - -Biobuf* faction; /* file for saving actions */ -Biobuf* fdefine; /* file for #defines */ -Biobuf* fdebug; /* y.debug for strings for debugging */ -Biobuf* ftable; /* y.tab.c file */ -Biobuf* ftemp; /* tempfile to pass 2 */ -Biobuf* finput; /* input file */ -Biobuf* foutput; /* y.output file */ - - /* communication variables between various I/O routines */ - -char* infile; /* input file name */ -int numbval; /* value of an input number */ -char tokname[NAMESIZE+4]; /* input token name, slop for runes and 0 */ - - /* structure declarations */ - -typedef -struct -{ - int lset[TBITSET]; -} Lkset; - -typedef -struct -{ - int* pitem; - Lkset* look; -} Item; - -typedef -struct -{ - char* name; - int value; -} Symb; - -typedef -struct -{ - int* pitem; - int flag; - Lkset ws; -} Wset; - - /* storage of names */ - -char cnames[CNAMSZ]; /* place where token and nonterminal names are stored */ -int cnamsz = CNAMSZ; /* size of cnames */ -char* cnamp = cnames; /* place where next name is to be put in */ -int ndefout = 4; /* number of defined symbols output */ -char* tempname; -char* actname; -char ttempname[] = TEMPNAME; -char tactname[] = ACTNAME; -char* parser = PARSER; -char* yydebug; - - /* storage of types */ -int ntypes; /* number of types defined */ -char* typeset[NTYPES]; /* pointers to type tags */ - - /* token information */ - -int ntokens = 0 ; /* number of tokens */ -Symb tokset[NTERMS]; -int toklev[NTERMS]; /* vector with the precedence of the terminals */ - - /* nonterminal information */ - -int nnonter = -1; /* the number of nonterminals */ -Symb nontrst[NNONTERM]; -int start; /* start symbol */ - - /* assigned token type values */ -int extval = 0; - -char* ytabc = OFILE; /* name of y.tab.c */ - - /* grammar rule information */ - -int mem0[MEMSIZE] ; /* production storage */ -int* mem = mem0; -int nprod = 1; /* number of productions */ -int* prdptr[NPROD]; /* pointers to descriptions of productions */ -int levprd[NPROD]; /* precedence levels for the productions */ -int rlines[NPROD]; /* line number for this rule */ - - /* state information */ - -int nstate = 0; /* number of states */ -Item* pstate[NSTATES+2]; /* pointers to the descriptions of the states */ -int tystate[NSTATES]; /* contains type information about the states */ -int defact[NSTATES]; /* the default actions of states */ -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 */ -int lastred; /* the number of the last reduction of a state */ - - /* lookahead set information */ - -Lkset lkst[LSETSIZE]; -int nolook; /* flag to turn off lookahead computations */ -int tbitset; /* size of lookahead sets */ -int nlset = 0; /* next lookahead set index */ -int nolook = 0; /* flag to suppress lookahead computations */ -Lkset clset; /* temporary storage for lookahead computations */ - - /* working set information */ - -Wset wsets[WSETSIZE]; -Wset* cwp; - - /* storage for action table */ - -int amem[ACTSIZE]; /* action table storage */ -int* memp = amem; /* next free action table position */ -int indgo[NSTATES]; /* index to the stored goto table */ - - /* temporary vector, indexable by states, terms, or ntokens */ - -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 */ - - /* statistics collection variables */ - -int zzgoent; -int zzgobest; -int zzacent; -int zzexcp; -int zzclose; -int zzrrconf; -int zzsrconf; - -int* ggreed = lkst[0].lset; -int* pgo = wsets[0].ws.lset; -int* yypgo = &nontrst[0].value; - -int maxspr = 0; /* maximum spread of any entry */ -int maxoff = 0; /* maximum offset into a array */ -int* pmem = mem0; -int* maxa; -int nxdb = 0; -int adb = 0; - - - /* storage for information about the nonterminals */ - -int** pres[NNONTERM+2]; /* vector of pointers to productions yielding each nonterminal */ -Lkset* pfirst[NNONTERM+2]; /* vector of pointers to first sets for each nonterminal */ -int pempty[NNONTERM+1]; /* vector of nonterminals nontrivially deriving e */ - - /* random stuff picked out from between functions */ - -int indebug = 0; -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; -int pidebug = 0; /* debugging flag for putitem */ -int gsdebug = 0; -int cldebug = 0; /* debugging flag for closure */ -int pkdebug = 0; -int g2debug = 0; - -struct -{ - char* name; - long value; -} resrv[] = -{ - "binary", BINARY, - "left", LEFT, - "nonassoc", BINARY, - "prec", PREC, - "right", RIGHT, - "start", START, - "term", TERM, - "token", TERM, - "type", TYPEDEF, - "union", UNION, - 0, -}; - - /* define functions */ - -void main(int, char**); -void others(void); -char* chcopy(char*, char*); -char* writem(int*); -char* symnam(int); -void summary(void); -void error(char*, ...); -void aryfil(int*, int, int); -int setunion(int*, int*); -void prlook(Lkset*); -void cpres(void); -void cpfir(void); -int state(int); -void putitem(int*, Lkset*); -void cempty(void); -void stagen(void); -void closure(int); -Lkset* flset(Lkset*); -void cleantmp(void); -void intr(void); -void setup(int, char**); -void finact(void); -int defin(int, char*); -void defout(int); -char* cstash(char*); -long gettok(void); -int fdtype(int); -int chfind(int, char*); -void cpyunion(void); -void cpycode(void); -int skipcom(void); -void cpyact(int); -void openup(char*, int, int, int, char*); -void output(void); -int apack(int*, int); -void go2out(void); -void go2gen(int); -void precftn(int, int, int); -void wract(int); -void wrstate(int); -void warray(char*, int*, int); -void hideprod(void); -void callopt(void); -void gin(int); -void stin(int); -int nxti(void); -void osummary(void); -void aoutput(void); -void arout(char*, int*, int); -int gtnm(void); - -void -main(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(); - exits(0); -} - -/* - * put out other arrays, copy the parsers - */ -void -others(void) -{ - int c, i, j; - - finput = Bopen(unsharp(parser), OREAD); - if(finput == 0) - error("cannot open parser %s: %r", 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] = i; - NTLOOP(i) - for(j=ntstates[i]; j!=0; j=mstates[j]) - temp1[j] = -i; - warray("yychk", temp1, nstate); - warray("yydef", defact, nstate); - - /* put out token translation tables */ - /* table 1 has 0-256 */ - aryfil(temp1, 256, 0); - c = 0; - TLOOP(i) { - j = tokset[i].value; - if(j >= 0 && j < 256) { - if(temp1[j]) { - print("yacc bug -- cant have 2 different Ts with same value\n"); - print(" %s and %s\n", tokset[i].name, tokset[temp1[j]].name); - nerrors++; - } - temp1[j] = i; - if(j > c) - c = j; - } - } - warray("yytok1", temp1, c+1); - - /* table 2 has PRIVATE-PRIVATE+256 */ - aryfil(temp1, 256, 0); - c = 0; - TLOOP(i) { - j = tokset[i].value - PRIVATE; - if(j >= 0 && j < 256) { - if(temp1[j]) { - print("yacc bug -- cant have 2 different Ts with same value\n"); - print(" %s and %s\n", tokset[i].name, tokset[temp1[j]].name); - nerrors++; - } - temp1[j] = i; - if(j > c) - c = j; - } - } - warray("yytok2", temp1, c+1); - - /* table 3 has everything else */ - Bprint(ftable, "long yytok3[] =\n{\n"); - c = 0; - TLOOP(i) { - j = tokset[i].value; - if(j >= 0 && j < 256) - continue; - if(j >= PRIVATE && j < 256+PRIVATE) - continue; - - Bprint(ftable, "%4d,%4d,", j, i); - c++; - if(c%5 == 0) - Bprint(ftable, "\n"); - } - Bprint(ftable, "%4d\n};\n", 0); - - /* copy parser text */ - while((c=Bgetrune(finput)) != Beof) { - if(c == '$') { - if((c = Bgetrune(finput)) != 'A') - Bputrune(ftable, '$'); - else { /* copy actions */ - faction = Bopen(actname, OREAD); - if(faction == 0) - error("cannot reopen action tempfile"); - while((c=Bgetrune(faction)) != Beof) - Bputrune(ftable, c); - Bterm(faction); - ZAPFILE(actname); - c = Bgetrune(finput); - } - } - Bputrune(ftable, c); - } - Bterm(ftable); -} - -/* - * copies string q into p, returning next free char ptr - */ -char* -chcopy(char* p, char* q) -{ - int c; - - while(c = *q) { - if(c == '"') - *p++ = '\\'; - *p++ = c; - q++; - } - *p = 0; - return p; -} - -/* - * creates output string for item pointed to by pp - */ -char* -writem(int *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++; - if(p == pp) - *q = '.'; - q++; - *q = '\0'; - i = *p; - if(i <= 0) - break; - q = chcopy(q, symnam(i)); - if(q > &sarr[ISIZE-30]) - error("item too big"); - } - - /* an item calling for a reduction */ - i = *pp; - if(i < 0 ) { - q = chcopy(q, " ("); - sprint(q, "%d)", -i); - } - return sarr; -} - -/* - * return a pointer to the name of symbol i - */ -char* -symnam(int i) -{ - char* cp; - - cp = (i >= NTBASE)? nontrst[i-NTBASE].name: tokset[i].name; - if(*cp == ' ') - cp++; - return cp; -} - -/* - * output the summary on y.output - */ -void -summary(void) -{ - - if(foutput != 0) { - Bprint(foutput, "\n%d/%d terminals, %d/%d nonterminals\n", - ntokens, NTERMS, nnonter, NNONTERM); - Bprint(foutput, "%d/%d grammar rules, %d/%d states\n", - nprod, NPROD, nstate, NSTATES); - Bprint(foutput, "%d shift/reduce, %d reduce/reduce conflicts reported\n", - zzsrconf, zzrrconf); - Bprint(foutput, "%d/%d working sets used\n", - (int)(zzcwp-wsets), WSETSIZE); - Bprint(foutput, "memory: states,etc. %d/%d, parser %d/%d\n", - (int)(zzmemsz-mem0), MEMSIZE, (int)(memp-amem), ACTSIZE); - Bprint(foutput, "%d/%d distinct lookahead sets\n", nlset, LSETSIZE); - Bprint(foutput, "%d extra closures\n", zzclose - 2*nstate); - Bprint(foutput, "%d shift entries, %d exceptions\n", zzacent, zzexcp); - Bprint(foutput, "%d goto entries\n", zzgoent); - Bprint(foutput, "%d entries saved by goto default\n", zzgobest); - } - if(zzsrconf != 0 || zzrrconf != 0) { - print("\nconflicts: "); - if(zzsrconf) - print("%d shift/reduce", zzsrconf); - if(zzsrconf && zzrrconf) - print(", "); - if(zzrrconf) - print("%d reduce/reduce", zzrrconf); - print("\n"); - } - if(ftemp != 0) { - Bterm(ftemp); - ftemp = 0; - } - if(fdefine != 0) { - Bterm(fdefine); - fdefine = 0; - } -} - -/* - * write out error comment -- NEEDS WORK - */ -void -error(char *s, ...) -{ - - nerrors++; - fprint(2, "\n fatal error:"); - fprint(2, s, (&s)[1]); - fprint(2, ", %s:%d\n", infile, lineno); - if(!fatfl) - return; - summary(); - cleantmp(); - exits("error"); -} - -/* - * set elements 0 through n-1 to c - */ -void -aryfil(int *v, int n, int c) -{ - int i; - - for(i=0; i<n; i++) - v[i] = c; -} - -/* - * set a to the union of a and b - * return 1 if b is not a subset of a, 0 otherwise - */ -int -setunion(int *a, int *b) -{ - int i, x, sub; - - sub = 0; - SETLOOP(i) { - x = *a; - *a |= *b; - if(*a != x) - sub = 1; - a++; - b++; - } - return sub; -} - -void -prlook(Lkset* p) -{ - int j, *pp; - - pp = p->lset; - if(pp == 0) - Bprint(foutput, "\tNULL"); - else { - Bprint(foutput, " { "); - TLOOP(j) - if(BIT(pp,j)) - Bprint(foutput, "%s ", symnam(j)); - Bprint(foutput, "}"); - } -} - -/* - * 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 - */ -void -cpres(void) -{ - int c, j, i, **pmem; - 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(); - cleantmp(); - exits("error"); - } - if(pmem != &pyield[nprod]) - error("internal Yacc error: pyield %d", pmem-&pyield[nprod]); -} - -/* - * compute an array with the first of nonterminals - */ -void -cpfir(void) -{ - int *p, **s, i, **t, ch, changes; - - zzcwp = &wsets[nnonter]; - NTLOOP(i) { - aryfil(wsets[i].ws.lset, tbitset, 0); - t = pres[i+1]; - /* initially fill the sets */ - for(s=pres[i]; s<t; ++s) - for(p = *s; (ch = *p) > 0; ++p) { - if(ch < NTBASE) { - SETBIT(wsets[i].ws.lset, ch); - break; - } - 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 != 0) - NTLOOP(i) { - Bprint(foutput, "\n%s: ", nontrst[i].name); - prlook(pfirst[i]); - Bprint(foutput, " %d\n", pempty[i]); - } -} - -/* - * sorts last state,and sees if it equals earlier ones. returns state number - */ -int -state(int c) -{ - Item *p1, *p2, *k, *l, *q1, *q2; - int size1, size2, i; - - 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; - Lkset *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++; -} - -void -putitem(int *ptr, Lkset *lptr) -{ - Item *j; - - if(pidebug && foutput != 0) - Bprint(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"); - } -} - -/* - * mark nonterminals which derive the empty string - * also, look for nonterminals which don't derive any token strings - */ -void -cempty(void) -{ - - int 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; - /* production can be derived */ - if(*p < 0) { - 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(); - cleantmp(); - exits("error"); - } - - /* 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) { - /* not known to be empty */ - if(pempty[*prdptr[i]-NTBASE] == WHOKNOWS) { - for(p = prdptr[i]+1; *p >= NTBASE && pempty[*p-NTBASE] == EMPTY ; ++p) - ; - /* we have a nontrivially empty nonterminal */ - if(*p < 0) { - pempty[*prdptr[i]-NTBASE] = EMPTY; - /* got one ... try for another */ - goto again; - } - } - } -} - -/* - * generate the states - */ -void -stagen(void) -{ - - int c, i, j, more; - 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] = (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 */ - for(more=1; more;) { - more = 0; - 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); - /* generate goto's */ - WSLOOP(wsets, p) { - 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) - /* this item contributes to the goto */ - if(c == *(q->pitem)) { - 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 != 0) { - Bprint(foutput, "%d: ", i); - NTLOOP(j) - if(temp1[j]) - Bprint(foutput, "%s %d, ", - nontrst[j].name, temp1[j]); - Bprint(foutput, "\n"); - } - indgo[i] = apack(&temp1[1], nnonter-1) - 1; - /* do some more */ - more = 1; - } - } -} - -/* - * generate the closure of state i - */ -void -closure(int i) -{ - - Wset *u, *v; - Item *p, *q; - int c, ch, work, k, *pi, **s, **t; - - 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; - /* dot is before c */ - c = *(u->pitem); - if(c < NTBASE) { - u->flag = 0; - /* only interesting case is where . is before nonterminal */ - continue; - } - - /* 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) { - /* terminal symbol */ - if(ch < NTBASE) { - 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 is now nonterminal number - */ - c -= NTBASE; - t = pres[c+1]; - for(s = pres[c]; s < t; ++s) { - /* - * put these items into the closure - * is the item there - */ - WSLOOP(wsets, v) - /* yes, it is there */ - if(v->pitem == *s) { - 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 != 0) { - Bprint(foutput, "\nState %d, nolook = %d\n", i, nolook); - WSLOOP(wsets, u) { - if(u->flag) - Bprint(foutput, "flag set!\n"); - u->flag = 0; - Bprint(foutput, "\t%s", writem(u->pitem)); - prlook(&u->ws); - Bprint(foutput, "\n"); - } - } -} - -/* - * decide if the lookahead set pointed to by p is known - * return pointer to a perminent location for the set - */ -Lkset* -flset(Lkset *p) -{ - Lkset *q; - int *u, *v, *w, j; - - 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; -} - -void -cleantmp(void) -{ - ZAPFILE(actname); - ZAPFILE(tempname); -} - -void -intr(void) -{ - cleantmp(); - exits("interrupted"); -} - -void -setup(int argc, char *argv[]) -{ - long c, t; - int i, j, fd, lev, ty, ytab, *p; - int vflag, dflag, stem; - char actnm[8], *stemc, *s, dirbuf[128]; - - ytab = 0; - vflag = 0; - dflag = 0; - stem = 0; - stemc = "y"; - foutput = 0; - fdefine = 0; - fdebug = 0; - ARGBEGIN{ - case 'v': - case 'V': - vflag++; - break; - case 'D': - yydebug = ARGF(); - break; - case 'd': - dflag++; - break; - case 'o': - ytab++; - ytabc = ARGF(); - break; - case 's': - stem++; - stemc = ARGF(); - break; - case 'S': - parser = PARSERS; - break; - default: - error("illegal option: %c", ARGC()); - }ARGEND - openup(stemc, dflag, vflag, ytab, ytabc); - - if((fd = mkstemp(ttempname)) >= 0){ - tempname = ttempname; - ftemp = Bfdopen(fd, OWRITE); - } - if((fd = mkstemp(tactname)) >= 0){ - actname = tactname; - faction = Bfdopen(fd, OWRITE); - } - if(ftemp == 0 || faction == 0) - error("cannot open temp file"); - if(argc < 1) - error("no input file"); - infile = argv[0]; - if(infile[0] != '/' && getwd(dirbuf, sizeof dirbuf)!=nil){ - i = strlen(infile)+1+strlen(dirbuf)+1+10; - s = malloc(i); - if(s != nil){ - snprint(s, i, "%s/%s", dirbuf, infile); - cleanname(s); - infile = s; - } - } - finput = Bopen(infile, OREAD); - if(finput == 0) - error("cannot open '%s'", argv[0]); - cnamp = cnames; - - defin(0, "$end"); - extval = PRIVATE; /* tokens start in unicode 'private use' */ - defin(0, "error"); - defin(1, "$accept"); - defin(0, "$unk"); - mem = mem0; - i = 0; - - for(t = gettok(); t != MARK && t != ENDFILE;) - switch(t) { - case ';': - t = gettok(); - break; - - case START: - if(gettok() != IDENTIFIER) - error("bad %%start construction"); - start = chfind(1, tokname); - t = gettok(); - continue; - - case TYPEDEF: - if(gettok() != TYPENAME) - error("bad syntax in %%type"); - ty = numbval; - for(;;) { - t = gettok(); - switch(t) { - case IDENTIFIER: - if((t=chfind(1, tokname)) < NTBASE) { - j = TYPE(toklev[t]); - if(j != 0 && j != ty) - error("type redeclaration of token %s", - tokset[t].name); - else - SETTYPE(toklev[t], ty); - } else { - j = nontrst[t-NTBASE].value; - if(j != 0 && j != ty) - error("type redeclaration of nonterminal %s", - nontrst[t-NTBASE].name ); - else - nontrst[t-NTBASE].value = ty; - } - case ',': - continue; - case ';': - t = gettok(); - default: - break; - } - break; - } - continue; - - case UNION: - /* copy the union declaration to the output */ - cpyunion(); - t = gettok(); - continue; - - case LEFT: - case BINARY: - case RIGHT: - i++; - - case TERM: - /* nonzero means new prec. and assoc. */ - lev = t-TERM; - ty = 0; - - /* get identifiers so defined */ - t = gettok(); - - /* there is a type defined */ - if(t == TYPENAME) { - ty = numbval; - t = gettok(); - } - for(;;) { - switch(t) { - case ',': - t = gettok(); - continue; - - case ';': - break; - - case IDENTIFIER: - j = chfind(0, tokname); - if(j >= NTBASE) - error("%s defined earlier as nonterminal", tokname); - if(lev) { - if(ASSOC(toklev[j])) - error("redeclaration of precedence of %s", tokname); - SETASC(toklev[j], lev); - SETPLEV(toklev[j], i); - } - if(ty) { - if(TYPE(toklev[j])) - error("redeclaration of type of %s", tokname); - SETTYPE(toklev[j],ty); - } - t = gettok(); - if(t == NUMBER) { - tokset[j].value = numbval; - if(j < ndefout && j > 3) - error("please define type number of %s earlier", - tokset[j].name); - t = gettok(); - } - continue; - } - break; - } - continue; - - case LCURLY: - defout(0); - cpycode(); - t = gettok(); - continue; - - default: - error("syntax error"); - } - if(t == ENDFILE) - error("unexpected EOF before %%"); - - /* t is MARK */ - Bprint(ftable, "extern int yyerrflag;\n"); - Bprint(ftable, "#ifndef YYMAXDEPTH\n"); - Bprint(ftable, "#define YYMAXDEPTH 150\n"); - Bprint(ftable, "#endif\n" ); - if(!ntypes) { - Bprint(ftable, "#ifndef YYSTYPE\n"); - Bprint(ftable, "#define YYSTYPE int\n"); - Bprint(ftable, "#endif\n"); - } - Bprint(ftable, "YYSTYPE yylval;\n"); - Bprint(ftable, "YYSTYPE yyval;\n"); - - prdptr[0] = mem; - - /* added production */ - *mem++ = NTBASE; - - /* if start is 0, we will overwrite with the lhs of the first rule */ - *mem++ = start; - *mem++ = 1; - *mem++ = 0; - prdptr[1] = mem; - while((t=gettok()) == LCURLY) - cpycode(); - if(t != IDENTCOLON) - error("bad syntax on first rule"); - - if(!start) - prdptr[0][1] = chfind(1, tokname); - - /* read rules */ - while(t != MARK && t != ENDFILE) { - /* process a rule */ - rlines[nprod] = lineno; - if(t == '|') - *mem++ = *prdptr[nprod-1]; - else - if(t == IDENTCOLON) { - *mem = chfind(1, tokname); - if(*mem < NTBASE) - error("token illegal on LHS of grammar rule"); - mem++; - } else - error("illegal rule: missing semicolon or | ?"); - /* read rule body */ - t = gettok(); - - more_rule: - while(t == IDENTIFIER) { - *mem = chfind(1, tokname); - if(*mem < NTBASE) - levprd[nprod] = toklev[*mem]; - mem++; - t = gettok(); - } - if(t == PREC) { - if(gettok() != IDENTIFIER) - error("illegal %%prec syntax"); - j = chfind(2, tokname); - if(j >= NTBASE) - error("nonterminal %s illegal after %%prec", - nontrst[j-NTBASE].name); - levprd[nprod] = toklev[j]; - t = gettok(); - } - if(t == '=') { - levprd[nprod] |= ACTFLAG; - Bprint(faction, "\ncase %d:", nprod); - cpyact(mem-prdptr[nprod]-1); - Bprint(faction, " break;"); - if((t=gettok()) == IDENTIFIER) { - - /* action within rule... */ - sprint(actnm, "$$%d", nprod); - - /* make it a nonterminal */ - j = chfind(1, actnm); - - /* - * the current rule will become rule number nprod+1 - * move the contents down, and make room for the null - */ - for(p = mem; p >= prdptr[nprod]; --p) - p[2] = *p; - mem += 2; - - /* enter null production for action */ - p = prdptr[nprod]; - *p++ = j; - *p++ = -nprod; - - /* update the production information */ - levprd[nprod+1] = levprd[nprod] & ~ACTFLAG; - levprd[nprod] = ACTFLAG; - if(++nprod >= NPROD) - error("more than %d rules", NPROD); - prdptr[nprod] = p; - - /* make the action appear in the original rule */ - *mem++ = j; - - /* get some more of the rule */ - goto more_rule; - } - } - - while(t == ';') - t = gettok(); - *mem++ = -nprod; - - /* check that default action is reasonable */ - if(ntypes && !(levprd[nprod]&ACTFLAG) && nontrst[*prdptr[nprod]-NTBASE].value) { - - /* no explicit action, LHS has value */ - int tempty; - - tempty = prdptr[nprod][1]; - if(tempty < 0) - error("must return a value, since LHS has a type"); - else - if(tempty >= NTBASE) - tempty = nontrst[tempty-NTBASE].value; - else - tempty = TYPE(toklev[tempty]); - if(tempty != nontrst[*prdptr[nprod]-NTBASE].value) - error("default action causes potential type clash"); - } - nprod++; - if(nprod >= NPROD) - error("more than %d rules", NPROD); - prdptr[nprod] = mem; - levprd[nprod] = 0; - } - - /* end of all rules */ - defout(1); - - finact(); - if(t == MARK) { - Bprint(ftable, "\n#line\t%d\t\"%s\"\n", lineno, infile); - while((c=Bgetrune(finput)) != Beof) - Bputrune(ftable, c); - } - Bterm(finput); -} - -/* - * finish action routine - */ -void -finact(void) -{ - - Bterm(faction); - Bprint(ftable, "#define YYEOFCODE %d\n", 1); - Bprint(ftable, "#define YYERRCODE %d\n", 2); -} - -/* - * define s to be a terminal if t=0 - * or a nonterminal if t=1 - */ -int -defin(int nt, char *s) -{ - int val; - Rune rune; - - val = 0; - if(nt) { - nnonter++; - if(nnonter >= NNONTERM) - error("too many nonterminals, limit %d",NNONTERM); - nontrst[nnonter].name = cstash(s); - return NTBASE + nnonter; - } - - /* must be a token */ - ntokens++; - if(ntokens >= NTERMS) - error("too many terminals, limit %d", NTERMS); - tokset[ntokens].name = cstash(s); - - /* establish value for token */ - /* single character literal */ - if(s[0] == ' ') { - val = chartorune(&rune, &s[1]); - if(s[val+1] == 0) { - val = rune; - goto out; - } - } - - /* escape sequence */ - if(s[0] == ' ' && s[1] == '\\') { - if(s[3] == 0) { - /* single character escape sequence */ - switch(s[2]) { - case 'n': val = '\n'; break; - case 'r': val = '\r'; break; - case 'b': val = '\b'; break; - case 't': val = '\t'; break; - case 'f': val = '\f'; break; - case '\'': val = '\''; break; - case '"': val = '"'; break; - case '\\': val = '\\'; break; - default: error("invalid escape"); - } - goto out; - } - - /* \nnn sequence */ - if(s[2] >= '0' && s[2] <= '7') { - if(s[3] < '0' || - s[3] > '7' || - s[4] < '0' || - s[4] > '7' || - s[5] != 0) - error("illegal \\nnn construction"); - val = 64*s[2] + 8*s[3] + s[4] - 73*'0'; - if(val == 0) - error("'\\000' is illegal"); - goto out; - } - error("unknown escape"); - } - val = extval++; - -out: - tokset[ntokens].value = val; - toklev[ntokens] = 0; - return ntokens; -} - -/* - * write out the defines (at the end of the declaration section) - */ -void -defout(int last) -{ - int i, c; - char sar[NAMESIZE+10]; - - for(i=ndefout; i<=ntokens; i++) { - /* non-literals */ - c = tokset[i].name[0]; - if(c != ' ' && c != '$') { - Bprint(ftable, "#define %s %d\n", - tokset[i].name, tokset[i].value); - if(fdefine) - Bprint(fdefine, "#define\t%s\t%d\n", - tokset[i].name, tokset[i].value); - } - } - ndefout = ntokens+1; - if(last && fdebug) { - Bprint(fdebug, "char* yytoknames[] =\n{\n"); - TLOOP(i) { - if(tokset[i].name) { - chcopy(sar, tokset[i].name); - Bprint(fdebug, "\t\"%s\",\n", sar); - continue; - } - Bprint(fdebug, "\t0,\n"); - } - Bprint(fdebug, "};\n"); - } -} - -char* -cstash(char *s) -{ - char *temp; - - temp = cnamp; - do { - if(cnamp >= &cnames[cnamsz]) - error("too many characters in id's and literals"); - else - *cnamp++ = *s; - } while(*s++); - return temp; -} - -long -gettok(void) -{ - long c; - Rune rune; - int i, base, match, reserve; - static int peekline; - -begin: - reserve = 0; - lineno += peekline; - peekline = 0; - c = Bgetrune(finput); - while(c == ' ' || c == '\n' || c == '\t' || c == '\f') { - if(c == '\n') - lineno++; - c = Bgetrune(finput); - } - - /* skip comment */ - if(c == '/') { - lineno += skipcom(); - goto begin; - } - switch(c) { - case Beof: - return ENDFILE; - - case '{': - Bungetrune(finput); - return '='; - - case '<': - /* get, and look up, a type name (union member name) */ - i = 0; - while((c=Bgetrune(finput)) != '>' && c >= 0 && c != '\n') { - rune = c; - c = runetochar(&tokname[i], &rune); - if(i < NAMESIZE) - i += c; - } - if(c != '>') - error("unterminated < ... > clause"); - tokname[i] = 0; - for(i=1; i<=ntypes; i++) - if(!strcmp(typeset[i], tokname)) { - numbval = i; - return TYPENAME; - } - ntypes++; - numbval = ntypes; - typeset[numbval] = cstash(tokname); - return TYPENAME; - - case '"': - case '\'': - match = c; - tokname[0] = ' '; - i = 1; - for(;;) { - c = Bgetrune(finput); - if(c == '\n' || c <= 0) - error("illegal or missing ' or \"" ); - if(c == '\\') { - tokname[i] = '\\'; - if(i < NAMESIZE) - i++; - c = Bgetrune(finput); - } else - if(c == match) - break; - rune = c; - c = runetochar(&tokname[i], &rune); - if(i < NAMESIZE) - i += c; - } - break; - - case '%': - case '\\': - switch(c = Bgetrune(finput)) { - 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: - /* number */ - if(isdigit(c)) { - numbval = c-'0'; - base = (c=='0')? 8: 10; - for(c = Bgetrune(finput); isdigit(c); c = Bgetrune(finput)) - numbval = numbval*base + (c-'0'); - Bungetrune(finput); - return NUMBER; - } - if(islower(c) || isupper(c) || c=='_' || c=='.' || c=='$') { - i = 0; - while(islower(c) || isupper(c) || isdigit(c) || - c == '-' || c=='_' || c=='.' || c=='$') { - if(reserve && isupper(c)) - c += 'a'-'A'; - rune = c; - c = runetochar(&tokname[i], &rune); - if(i < NAMESIZE) - i += c; - c = Bgetrune(finput); - } - } else - return c; - Bungetrune(finput); - } - tokname[i] = 0; - - /* find a reserved word */ - if(reserve) { - for(c=0; resrv[c].name; c++) - if(strcmp(tokname, resrv[c].name) == 0) - return resrv[c].value; - error("invalid escape, or illegal reserved word: %s", tokname); - } - - /* look ahead to distinguish IDENTIFIER from IDENTCOLON */ - c = Bgetrune(finput); - while(c == ' ' || c == '\t'|| c == '\n' || c == '\f' || c == '/') { - if(c == '\n') - peekline++; - /* look for comments */ - if(c == '/') - peekline += skipcom(); - c = Bgetrune(finput); - } - if(c == ':') - return IDENTCOLON; - Bungetrune(finput); - return IDENTIFIER; -} - -/* - * determine the type of a symbol - */ -int -fdtype(int t) -{ - int v; - - if(t >= NTBASE) - v = nontrst[t-NTBASE].value; - else - v = TYPE(toklev[t]); - if(v <= 0) - error("must specify type for %s", (t>=NTBASE)? - nontrst[t-NTBASE].name: tokset[t].name); - return v; -} - -int -chfind(int t, char *s) -{ - int i; - - if(s[0] == ' ') - t = 0; - TLOOP(i) - if(!strcmp(s, tokset[i].name)) - return i; - NTLOOP(i) - if(!strcmp(s, nontrst[i].name)) - return NTBASE+i; - - /* cannot find name */ - if(t > 1) - error("%s should have been defined earlier", s); - return defin(t, s); -} - -/* - * copy the union declaration to the output, and the define file if present - */ -void -cpyunion(void) -{ - long c; - int level; - - Bprint(ftable, "\n#line\t%d\t\"%s\"\n", lineno, infile); - Bprint(ftable, "typedef union "); - if(fdefine != 0) - Bprint(fdefine, "\ntypedef union "); - - level = 0; - for(;;) { - if((c=Bgetrune(finput)) == Beof) - error("EOF encountered while processing %%union"); - Bputrune(ftable, c); - if(fdefine != 0) - Bputrune(fdefine, c); - switch(c) { - case '\n': - lineno++; - break; - case '{': - level++; - break; - case '}': - level--; - - /* we are finished copying */ - if(level == 0) { - Bprint(ftable, " YYSTYPE;\n"); - if(fdefine != 0) - Bprint(fdefine, "\tYYSTYPE;\nextern\tYYSTYPE\tyylval;\n"); - return; - } - } - } -} - -/* - * copies code between \{ and \} - */ -void -cpycode(void) -{ - - long c; - - c = Bgetrune(finput); - if(c == '\n') { - c = Bgetrune(finput); - lineno++; - } - Bprint(ftable, "\n#line\t%d\t\"%s\"\n", lineno, infile); - while(c != Beof) { - if(c == '\\') { - if((c=Bgetrune(finput)) == '}') - return; - Bputc(ftable, '\\'); - } - if(c == '%') { - if((c=Bgetrune(finput)) == '}') - return; - Bputc(ftable, '%'); - } - Bputrune(ftable, c); - if(c == '\n') - lineno++; - c = Bgetrune(finput); - } - error("eof before %%}"); -} - -/* - * skip over comments - * skipcom is called after reading a '/' - */ -int -skipcom(void) -{ - long c; - int i; - - /* i is the number of lines skipped */ - i = 0; - if(Bgetrune(finput) != '*') - error("illegal comment"); - c = Bgetrune(finput); - while(c != Beof) { - while(c == '*') - if((c=Bgetrune(finput)) == '/') - return i; - if(c == '\n') - i++; - c = Bgetrune(finput); - } - error("EOF inside comment"); - return 0; -} - -/* - * copy C action to the next ; or closing } - */ -void -cpyact(int offset) -{ - long c; - int brac, match, j, s, fnd, tok; - - Bprint(faction, "\n#line\t%d\t\"%s\"\n", lineno, infile); - brac = 0; - -loop: - c = Bgetrune(finput); -swt: - switch(c) { - case ';': - if(brac == 0) { - Bputrune(faction, c); - return; - } - goto lcopy; - - case '{': - brac++; - goto lcopy; - - case '$': - s = 1; - tok = -1; - c = Bgetrune(finput); - - /* type description */ - if(c == '<') { - Bungetrune(finput); - if(gettok() != TYPENAME) - error("bad syntax on $<ident> clause"); - tok = numbval; - c = Bgetrune(finput); - } - if(c == '$') { - Bprint(faction, "yyval"); - - /* put out the proper tag... */ - if(ntypes) { - if(tok < 0) - tok = fdtype(*prdptr[nprod]); - Bprint(faction, ".%s", typeset[tok]); - } - goto loop; - } - if(c == '-') { - s = -s; - c = Bgetrune(finput); - } - if(isdigit(c)) { - j = 0; - while(isdigit(c)) { - j = j*10 + (c-'0'); - c = Bgetrune(finput); - } - Bungetrune(finput); - j = j*s - offset; - if(j > 0) - error("Illegal use of $%d", j+offset); - - dollar: - Bprint(faction, "yypt[-%d].yyv", -j); - - /* put out the proper tag */ - if(ntypes) { - if(j+offset <= 0 && tok < 0) - error("must specify type of $%d", j+offset); - if(tok < 0) - tok = fdtype(prdptr[nprod][j+offset]); - Bprint(faction, ".%s", typeset[tok]); - } - goto loop; - } - if(isupper(c) || islower(c) || c == '_' || c == '.') { - int tok; /* tok used oustide for type info */ - - /* look for $name */ - Bungetrune(finput); - if(gettok() != IDENTIFIER) - error("$ must be followed by an identifier"); - tok = chfind(2, tokname); - if((c = Bgetrune(finput)) != '#') { - Bungetrune(finput); - fnd = -1; - } else - if(gettok() != NUMBER) { - error("# must be followed by number"); - fnd = -1; - } else - fnd = numbval; - for(j=1; j<=offset; ++j) - if(tok == prdptr[nprod][j]) { - if(--fnd <= 0) { - j -= offset; - goto dollar; - } - } - error("$name or $name#number not found"); - } - Bputc(faction, '$'); - if(s < 0 ) - Bputc(faction, '-'); - goto swt; - - case '}': - brac--; - if(brac) - goto lcopy; - Bputrune(faction, c); - return; - - case '/': - /* look for comments */ - Bputrune(faction, c); - c = Bgetrune(finput); - if(c != '*') - goto swt; - - /* it really is a comment */ - Bputrune(faction, c); - c = Bgetrune(finput); - while(c >= 0) { - while(c == '*') { - Bputrune(faction, c); - if((c=Bgetrune(finput)) == '/') - goto lcopy; - } - Bputrune(faction, c); - if(c == '\n') - lineno++; - c = Bgetrune(finput); - } - error("EOF inside comment"); - - case '\'': - /* character constant */ - match = '\''; - goto string; - - case '"': - /* character string */ - match = '"'; - - string: - Bputrune(faction, c); - while(c = Bgetrune(finput)) { - if(c == '\\') { - Bputrune(faction, c); - c = Bgetrune(finput); - if(c == '\n') - lineno++; - } else - if(c == match) - goto lcopy; - if(c == '\n') - error("newline in string or char. const."); - Bputrune(faction, c); - } - error("EOF in string or character constant"); - - case Beof: - error("action does not terminate"); - - case '\n': - lineno++; - goto lcopy; - } - -lcopy: - Bputrune(faction, c); - goto loop; -} - -void -openup(char *stem, int dflag, int vflag, int ytab, char *ytabc) -{ - char buf[256]; - - if(vflag) { - sprint(buf, "%s.%s", stem, FILEU); - foutput = Bopen(buf, OWRITE); - if(foutput == 0) - error("cannot open %s", buf); - } - if(yydebug) { - sprint(buf, "%s.%s", stem, FILEDEBUG); - if((fdebug = Bopen(buf, OWRITE)) == 0) - error("can't open %s", buf); - } - if(dflag) { - sprint(buf, "%s.%s", stem, FILED); - fdefine = Bopen(buf, OWRITE); - if(fdefine == 0) - error("can't create %s", buf); - } - if(ytab == 0) - sprint(buf, "%s.%s", stem, OFILE); - else - strcpy(buf, ytabc); - ftable = Bopen(buf, OWRITE); - if(ftable == 0) - error("cannot open table file %s", buf); -} - -/* - * print the output for the states - */ -void -output(void) -{ - int i, k, c; - Wset *u, *v; - - Bprint(ftable, "short yyexca[] =\n{"); - if(fdebug) - Bprint(fdebug, "char* yystates[] =\n{\n"); - - /* output the stuff for state i */ - SLOOP(i) { - nolook = tystate[i]!=MUSTLOOKAHEAD; - closure(i); - - /* output actions */ - nolook = 1; - aryfil(temp1, ntokens+nnonter+1, 0); - WSLOOP(wsets, u) { - c = *(u->pitem); - if(c > 1 && c < NTBASE && temp1[c] == 0) { - WSLOOP(u, v) - if(c == *(v->pitem)) - putitem(v->pitem+1, (Lkset*)0); - temp1[c] = state(c); - } else - if(c > NTBASE && temp1[(c -= NTBASE) + ntokens] == 0) - temp1[c+ntokens] = amem[indgo[i]+c]; - } - if(i == 1) - temp1[1] = ACCEPTCODE; - - /* now, we have the shifts; look at the reductions */ - lastred = 0; - WSLOOP(wsets, u) { - c = *u->pitem; - - /* reduction */ - if(c <= 0) { - lastred = -c; - TLOOP(k) - if(BIT(u->ws.lset, k)) { - if(temp1[k] == 0) - temp1[k] = c; - else - if(temp1[k] < 0) { /* reduce/reduce conflict */ - if(foutput) - Bprint(foutput, - "\n%d: reduce/reduce conflict" - " (red'ns %d and %d ) on %s", - i, -temp1[k], lastred, - symnam(k)); - if(-temp1[k] > lastred) - temp1[k] = -lastred; - zzrrconf++; - } else - /* potential shift/reduce conflict */ - precftn( lastred, k, i ); - } - } - } - wract(i); - } - - if(fdebug) - Bprint(fdebug, "};\n"); - Bprint(ftable, "};\n"); - Bprint(ftable, "#define YYNPROD %d\n", nprod); - Bprint(ftable, "#define YYPRIVATE %d\n", PRIVATE); - if(yydebug) - Bprint(ftable, "#define yydebug %s\n", yydebug); -} - -/* - * pack state i from temp1 into amem - */ -int -apack(int *p, int n) -{ - int *pp, *qq, *rr, off, *q, *r; - - /* we don't need to worry about checking because - * we will only look at entries known to be there... - * eliminate leading and trailing 0's - */ - - q = p+n; - for(pp = p, off = 0; *pp == 0 && pp <= q; ++pp, --off) - ; - /* no actions */ - if(pp > q) - return 0; - p = pp; - - /* now, find a place for the elements from p to q, inclusive */ - r = &amem[ACTSIZE-1]; - for(rr = amem; rr <= r; rr++, off++) { - for(qq = rr, pp = p; pp <= q; pp++, qq++) - if(*pp != 0) - if(*pp != *qq && *qq != 0) - goto nextk; - - /* we have found an acceptable k */ - if(pkdebug && foutput != 0) - Bprint(foutput, "off = %d, k = %d\n", off, (int)(rr-amem)); - for(qq = rr, pp = p; pp <= q; pp++, qq++) - if(*pp) { - if(qq > r) - error("action table overflow"); - if(qq > memp) - memp = qq; - *qq = *pp; - } - if(pkdebug && foutput != 0) - for(pp = amem; pp <= memp; pp += 10) { - Bprint(foutput, "\t"); - for(qq = pp; qq <= pp+9; qq++) - Bprint(foutput, "%d ", *qq); - Bprint(foutput, "\n"); - } - return(off); - nextk:; - } - error("no space in action table"); - return 0; -} - -/* - * output the gotos for the nontermninals - */ -void -go2out(void) -{ - int i, j, k, best, count, cbest, times; - - /* mark begining of gotos */ - Bprint(ftemp, "$\n"); - for(i = 1; i <= nnonter; i++) { - go2gen(i); - - /* find the best one to make default */ - best = -1; - times = 0; - - /* is j the most frequent */ - for(j = 0; j <= nstate; j++) { - if(tystate[j] == 0) - continue; - if(tystate[j] == best) - continue; - - /* is tystate[j] the most frequent */ - count = 0; - cbest = tystate[j]; - for(k = j; k <= nstate; k++) - if(tystate[k] == cbest) - count++; - if(count > times) { - best = cbest; - times = count; - } - } - - /* best is now the default entry */ - zzgobest += times-1; - for(j = 0; j <= nstate; j++) - if(tystate[j] != 0 && tystate[j] != best) { - Bprint(ftemp, "%d,%d,", j, tystate[j]); - zzgoent++; - } - - /* now, the default */ - if(best == -1) - best = 0; - zzgoent++; - Bprint(ftemp, "%d\n", best); - } -} - -/* - * output the gotos for nonterminal c - */ -void -go2gen(int c) -{ - int i, work, cc; - Item *p, *q; - - - /* first, find nonterminals with gotos on c */ - aryfil(temp1, nnonter+1, 0); - temp1[c] = 1; - work = 1; - while(work) { - work = 0; - PLOOP(0, i) - - /* cc is a nonterminal */ - if((cc=prdptr[i][1]-NTBASE) >= 0) - /* cc has a goto on c */ - if(temp1[cc] != 0) { - - /* thus, the left side of production i does too */ - cc = *prdptr[i]-NTBASE; - if(temp1[cc] == 0) { - work = 1; - temp1[cc] = 1; - } - } - } - - /* now, we have temp1[c] = 1 if a goto on c in closure of cc */ - if(g2debug && foutput != 0) { - Bprint(foutput, "%s: gotos on ", nontrst[c].name); - NTLOOP(i) - if(temp1[i]) - Bprint(foutput, "%s ", nontrst[i].name); - Bprint(foutput, "\n"); - } - - /* now, go through and put gotos into tystate */ - aryfil(tystate, nstate, 0); - SLOOP(i) - ITMLOOP(i, p, q) - if((cc = *p->pitem) >= NTBASE) - /* goto on c is possible */ - if(temp1[cc-NTBASE]) { - tystate[i] = amem[indgo[i]+c]; - break; - } -} - -/* - * decide a shift/reduce conflict by precedence. - * r is a rule number, t a token number - * the conflict is in state s - * temp1[t] is changed to reflect the action - */ -void -precftn(int r, int t, int s) -{ - int lp, lt, action; - - lp = levprd[r]; - lt = toklev[t]; - if(PLEVEL(lt) == 0 || PLEVEL(lp) == 0) { - - /* conflict */ - if(foutput != 0) - Bprint(foutput, - "\n%d: shift/reduce conflict (shift %d(%d), red'n %d(%d)) on %s", - s, temp1[t], PLEVEL(lt), r, PLEVEL(lp), symnam(t)); - zzsrconf++; - return; - } - if(PLEVEL(lt) == PLEVEL(lp)) - action = ASSOC(lt); - else - if(PLEVEL(lt) > PLEVEL(lp)) - action = RASC; /* shift */ - else - action = LASC; /* reduce */ - switch(action) { - case BASC: /* error action */ - temp1[t] = ERRCODE; - break; - case LASC: /* reduce */ - temp1[t] = -r; - break; - } -} - -/* - * output state i - * temp1 has the actions, lastred the default - */ -void -wract(int i) -{ - int p, p0, p1, ntimes, tred, count, j, flag; - - /* find the best choice for lastred */ - lastred = 0; - ntimes = 0; - TLOOP(j) { - if(temp1[j] >= 0) - continue; - if(temp1[j]+lastred == 0) - continue; - /* count the number of appearances of temp1[j] */ - count = 0; - tred = -temp1[j]; - levprd[tred] |= REDFLAG; - TLOOP(p) - if(temp1[p]+tred == 0) - count++; - if(count > ntimes) { - lastred = tred; - ntimes = count; - } - } - - /* - * for error recovery, arrange that, if there is a shift on the - * error recovery token, `error', that the default be the error action - */ - if(temp1[2] > 0) - lastred = 0; - - /* clear out entries in temp1 which equal lastred */ - TLOOP(p) - if(temp1[p]+lastred == 0) - temp1[p] = 0; - - wrstate(i); - defact[i] = lastred; - flag = 0; - TLOOP(p0) - if((p1=temp1[p0]) != 0) { - if(p1 < 0) { - p1 = -p1; - goto exc; - } - if(p1 == ACCEPTCODE) { - p1 = -1; - goto exc; - } - if(p1 == ERRCODE) { - p1 = 0; - exc: - if(flag++ == 0) - Bprint(ftable, "-1, %d,\n", i); - Bprint(ftable, "\t%d, %d,\n", p0, p1); - zzexcp++; - continue; - } - Bprint(ftemp, "%d,%d,", p0, p1); - zzacent++; - } - if(flag) { - defact[i] = -2; - Bprint(ftable, "\t-2, %d,\n", lastred); - } - Bprint(ftemp, "\n"); -} - -/* - * writes state i - */ -void -wrstate(int i) -{ - int j0, j1; - Item *pp, *qq; - Wset *u; - - if(fdebug) { - if(lastred) { - Bprint(fdebug, " 0, /*%d*/\n", i); - } else { - Bprint(fdebug, " \""); - ITMLOOP(i, pp, qq) - Bprint(fdebug, "%s\\n", writem(pp->pitem)); - if(tystate[i] == MUSTLOOKAHEAD) - WSLOOP(wsets + (pstate[i+1] - pstate[i]), u) - if(*u->pitem < 0) - Bprint(fdebug, "%s\\n", writem(u->pitem)); - Bprint(fdebug, "\", /*%d*/\n", i); - } - } - if(foutput == 0) - return; - Bprint(foutput, "\nstate %d\n", i); - ITMLOOP(i, pp, qq) - Bprint(foutput, "\t%s\n", writem(pp->pitem)); - if(tystate[i] == MUSTLOOKAHEAD) - /* print out empty productions in closure */ - WSLOOP(wsets+(pstate[i+1]-pstate[i]), u) - if(*u->pitem < 0) - Bprint(foutput, "\t%s\n", writem(u->pitem)); - - /* check for state equal to another */ - TLOOP(j0) - if((j1=temp1[j0]) != 0) { - Bprint(foutput, "\n\t%s ", symnam(j0)); - /* shift, error, or accept */ - if(j1 > 0) { - if(j1 == ACCEPTCODE) - Bprint(foutput, "accept"); - else - if(j1 == ERRCODE) - Bprint(foutput, "error"); - else - Bprint(foutput, "shift %d", j1); - } else - Bprint(foutput, "reduce %d (src line %d)", -j1, rlines[-j1]); - } - - /* output the final production */ - if(lastred) - Bprint(foutput, "\n\t. reduce %d (src line %d)\n\n", - lastred, rlines[lastred]); - else - Bprint(foutput, "\n\t. error\n\n"); - - /* now, output nonterminal actions */ - j1 = ntokens; - for(j0 = 1; j0 <= nnonter; j0++) { - j1++; - if(temp1[j1]) - Bprint(foutput, "\t%s goto %d\n", symnam(j0+NTBASE), temp1[j1]); - } -} - -void -warray(char *s, int *v, int n) -{ - int i; - - Bprint(ftable, "short %s[] =\n{", s); - for(i=0;;) { - if(i%10 == 0) - Bprint(ftable, "\n"); - Bprint(ftable, "%4d", v[i]); - i++; - if(i >= n) { - Bprint(ftable, "\n};\n"); - break; - } - Bprint(ftable, ","); - } -} - -/* - * in order to free up the mem and amem arrays for the optimizer, - * and still be able to output yyr1, etc., after the sizes of - * the action array is known, we hide the nonterminals - * derived by productions in levprd. - */ - -void -hideprod(void) -{ - int i, j; - - j = 0; - levprd[0] = 0; - PLOOP(1, i) { - if(!(levprd[i] & REDFLAG)) { - j++; - if(foutput != 0) - Bprint(foutput, "Rule not reduced: %s\n", writem(prdptr[i])); - } - levprd[i] = *prdptr[i] - NTBASE; - } - if(j) - print("%d rules never reduced\n", j); -} - -void -callopt(void) -{ - int i, *p, j, k, *q; - - /* read the arrays from tempfile and set parameters */ - finput = Bopen(tempname, OREAD); - if(finput == 0) - error("optimizer cannot open tempfile"); - - pgo[0] = 0; - temp1[0] = 0; - nstate = 0; - nnonter = 0; - for(;;) { - switch(gtnm()) { - case '\n': - nstate++; - pmem--; - temp1[nstate] = pmem - mem0; - case ',': - continue; - case '$': - break; - default: - error("bad tempfile"); - } - break; - } - - pmem--; - temp1[nstate] = yypgo[0] = pmem - mem0; - for(;;) { - switch(gtnm()) { - case '\n': - nnonter++; - yypgo[nnonter] = pmem-mem0; - case ',': - continue; - case -1: - break; - default: - error("bad tempfile"); - } - break; - } - pmem--; - yypgo[nnonter--] = pmem - mem0; - for(i = 0; i < nstate; i++) { - k = 32000; - j = 0; - q = mem0 + temp1[i+1]; - for(p = mem0 + temp1[i]; p < q ; p += 2) { - if(*p > j) - j = *p; - if(*p < k) - k = *p; - } - /* nontrivial situation */ - if(k <= j) { - /* j is now the range */ -/* j -= k; *//* call scj */ - if(k > maxoff) - maxoff = k; - } - tystate[i] = (temp1[i+1]-temp1[i]) + 2*j; - if(j > maxspr) - maxspr = j; - } - - /* initialize ggreed table */ - for(i = 1; i <= nnonter; i++) { - ggreed[i] = 1; - j = 0; - - /* minimum entry index is always 0 */ - q = mem0 + yypgo[i+1] - 1; - for(p = mem0+yypgo[i]; p < q ; p += 2) { - ggreed[i] += 2; - if(*p > j) - j = *p; - } - ggreed[i] = ggreed[i] + 2*j; - if(j > maxoff) - maxoff = j; - } - - /* now, prepare to put the shift actions into the amem array */ - for(i = 0; i < ACTSIZE; i++) - amem[i] = 0; - maxa = amem; - for(i = 0; i < nstate; i++) { - if(tystate[i] == 0 && adb > 1) - Bprint(ftable, "State %d: null\n", i); - indgo[i] = YYFLAG1; - } - while((i = nxti()) != NOMORE) - if(i >= 0) - stin(i); - else - gin(-i); - - /* print amem array */ - if(adb > 2 ) - for(p = amem; p <= maxa; p += 10) { - Bprint(ftable, "%4d ", (int)(p-amem)); - for(i = 0; i < 10; ++i) - Bprint(ftable, "%4d ", p[i]); - Bprint(ftable, "\n"); - } - - /* write out the output appropriate to the language */ - aoutput(); - osummary(); - ZAPFILE(tempname); -} - -void -gin(int i) -{ - int *p, *r, *s, *q1, *q2; - - /* enter gotos on nonterminal i into array amem */ - ggreed[i] = 0; - - q2 = mem0+ yypgo[i+1] - 1; - q1 = mem0 + yypgo[i]; - - /* now, find amem place for it */ - for(p = amem; p < &amem[ACTSIZE]; p++) { - if(*p) - continue; - for(r = q1; r < q2; r += 2) { - s = p + *r + 1; - if(*s) - goto nextgp; - if(s > maxa) - if((maxa = s) > &amem[ACTSIZE]) - error("a array overflow"); - } - /* we have found amem spot */ - *p = *q2; - if(p > maxa) - if((maxa = p) > &amem[ACTSIZE]) - error("a array overflow"); - for(r = q1; r < q2; r += 2) { - s = p + *r + 1; - *s = r[1]; - } - pgo[i] = p-amem; - if(adb > 1) - Bprint(ftable, "Nonterminal %d, entry at %d\n", i, pgo[i]); - return; - - nextgp:; - } - error("cannot place goto %d\n", i); -} - -void -stin(int i) -{ - int *r, *s, n, flag, j, *q1, *q2; - - tystate[i] = 0; - - /* enter state i into the amem array */ - q2 = mem0+temp1[i+1]; - q1 = mem0+temp1[i]; - /* find an acceptable place */ - for(n = -maxoff; n < ACTSIZE; n++) { - flag = 0; - for(r = q1; r < q2; r += 2) { - if((s = *r + n + amem) < amem) - goto nextn; - if(*s == 0) - flag++; - else - if(*s != r[1]) - goto nextn; - } - - /* check that the position equals another only if the states are identical */ - for(j=0; j<nstate; j++) { - if(indgo[j] == n) { - - /* we have some disagreement */ - if(flag) - goto nextn; - if(temp1[j+1]+temp1[i] == temp1[j]+temp1[i+1]) { - - /* states are equal */ - indgo[i] = n; - if(adb > 1) - Bprint(ftable, - "State %d: entry at %d equals state %d\n", - i, n, j); - return; - } - - /* we have some disagreement */ - goto nextn; - } - } - - for(r = q1; r < q2; r += 2) { - if((s = *r+n+amem) >= &amem[ACTSIZE]) - error("out of space in optimizer a array"); - if(s > maxa) - maxa = s; - if(*s != 0 && *s != r[1]) - error("clobber of a array, pos'n %d, by %d", s-amem, r[1]); - *s = r[1]; - } - indgo[i] = n; - if(adb > 1) - Bprint(ftable, "State %d: entry at %d\n", i, indgo[i]); - return; - nextn:; - } - error("Error; failure to place state %d\n", i); -} - -/* - * finds the next i - */ -int -nxti(void) -{ - int i, max, maxi; - - max = 0; - maxi = 0; - for(i = 1; i <= nnonter; i++) - if(ggreed[i] >= max) { - max = ggreed[i]; - maxi = -i; - } - for(i = 0; i < nstate; ++i) - if(tystate[i] >= max) { - max = tystate[i]; - maxi = i; - } - if(nxdb) - Bprint(ftable, "nxti = %d, max = %d\n", maxi, max); - if(max == 0) - return NOMORE; - return maxi; -} - -/* - * write summary - */ -void -osummary(void) -{ - - int i, *p; - - if(foutput == 0) - return; - i = 0; - for(p = maxa; p >= amem; p--) - if(*p == 0) - i++; - - Bprint(foutput, "Optimizer space used: input %d/%d, output %d/%d\n", - (int)(pmem-mem0+1), MEMSIZE, (int)(maxa-amem+1), ACTSIZE); - Bprint(foutput, "%d table entries, %d zero\n", (int)(maxa-amem+1), i); - Bprint(foutput, "maximum spread: %d, maximum offset: %d\n", maxspr, maxoff); -} - -/* - * this version is for C - * write out the optimized parser - */ -void -aoutput(void) -{ - Bprint(ftable, "#define\tYYLAST\t%d\n", (int)(maxa-amem+1)); - arout("yyact", amem, (maxa-amem)+1); - arout("yypact", indgo, nstate); - arout("yypgo", pgo, nnonter+1); -} - -void -arout(char *s, int *v, int n) -{ - int i; - - Bprint(ftable, "short %s[] =\n{", s); - for(i = 0; i < n;) { - if(i%10 == 0) - Bprint(ftable, "\n"); - Bprint(ftable, "%4d", v[i]); - i++; - if(i == n) - Bprint(ftable, "\n};\n"); - else - Bprint(ftable, ","); - } -} - -/* - * read and convert an integer from the standard input - * return the terminating character - * blanks, tabs, and newlines are ignored - */ -int -gtnm(void) -{ - int sign, val, c; - - sign = 0; - val = 0; - while((c=Bgetrune(finput)) != Beof) { - if(isdigit(c)) { - val = val*10 + c-'0'; - continue; - } - if(c == '-') { - sign = 1; - continue; - } - break; - } - if(sign) - val = -val; - *pmem++ = val; - if(pmem >= &mem0[MEMSIZE]) - error("out of space"); - return c; -} |