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 */
char inpath[1024]; /* input full path */
int numbval; /* value of an input number */
char tokname[NAMESIZE+UTFmax+1]; /* input token name, slop for runes and 0 */
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 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;
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;
/*
* 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];
/*
* 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++;
}
/* 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);
}
}
/* 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...
*/
/* 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);
/*
* 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);
/*
* 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;
}
/* 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();
/* 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;
}
/* 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;
}
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;
}
/*
* 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;
c = Bgetrune(finput);
if(c == '/'){ /* C++ //: skip to end of line */
while((c = Bgetrune(finput)) != Beof)
if(c == '\n')
return 1;
}else if(c == '*'){ /* normal C comment */
while((c = Bgetrune(finput)) != Beof) {
while(c == '*')
if((c = Bgetrune(finput)) == '/')
return i;
if(c == '\n')
i++;
}
}else
error("illegal comment");
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;
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];
/* 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;
/*
* 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;
/*
* 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;
/* 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");
/*
* 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.
*/
/* read the arrays from tempfile and set parameters */
finput = Bopen(tempname, OREAD);
if(finput == 0)
error("optimizer cannot open tempfile");
Blethal(finput, nil);
/* write out the output appropriate to the language */
aoutput();
osummary();
ZAPFILE(ftemp, 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++;
/*
* 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);
}
/*
* 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;