|
|
1.1 root 1: /*
2: * LALR-1 parser generator
3: *
4: * the comments previously here have been suppressed since they were
5: * boring
6: */
7: #include "yacc.h"
8:
9: main(argc,argv)
10: char *argv[];
11: {
12: options(argc,argv);
13: getfiles();
14: readrules();
15: ntprod();
16: ntderive();
17: listgram();
18: if( nerrors )
19: cleanup(1);
20: ntempty();
21: if( nerrors )
22: cleanup(1);
23: genstates();
24: genslist();
25: sttrans();
26: genlook();
27: go2out();
28: paout();
29: callopt();
30: cleanup(0);
31: }
32:
33: getfiles()
34: {
35: if( gramy==NULL )
36: usage();
37: if( strcmp(gramy,"-")==0 )
38: defin = stdin;
39: else
40: if( (defin = fopen(gramy,"r")) == NULL )
41: yyerror(!FATAL, "cannot open grammar file %s", gramy);
42: mktemp(acttmp);
43: mktemp(opttmp);
44: if( (actout = fopen(acttmp,"w")) == NULL )
45: yyerror(!FATAL, "cannot create action temp file %s", acttmp);
46: if( (tabout = fopen(ytabc,"w")) == NULL )
47: yyerror(!FATAL, "cannot create output file %s", ytabc);
48: if( (fhdr = fopen(ytabh, "w")) == NULL )
49: yyerror(!FATAL, "cannot create %s", ytabh);
50: if( verbose )
51: if( (listout = fopen(youtput,"w")) == NULL )
52: yyerror(NLNO, "cannot open listing file %s", youtput);
53: if ((optout = fopen(opttmp, "wb")) == NULL
54: || (optout = freopen(opttmp, "rwb", optout)) == NULL)
55: yyerror(NLNO, "open error temp %s", opttmp);
56: if( nerrors )
57: cleanup(2);
58: }
59:
60: rewopt()
61: {
62: fseek(optout, 0L, 0);
63: }
64:
65: /*
66: * for each non-terminal, generate a list of productions which the
67: * the non terminal derives
68: */
69: ntprod()
70: {
71: register i;
72: register struct sym *sp;
73:
74: /* first run down the production table, counting references to
75: all the non terminals. */
76: for(i=0; i<nnonterm; i++)
77: ntrmptr[i]->s_nprods = 0;
78: for(i=0; i<nprod; i++)
79: ntrmptr[-prdptr[i]->p_left-NTBASE]->s_nprods++;
80: for(i=0; i<nnonterm; i++)
81: if( ntrmptr[i]->s_nprods==0 )
82: yyerror(NLNO|!FATAL, "non terminal %s not defined",
83: ntrmptr[i]->s_name);
84: if( nerrors )
85: cleanup(1);
86: /* now allocate list pointers for each non-terminal */
87: for(i=0; i<nnonterm; i++) {
88: sp = ntrmptr[i];
89: sp->s_prods = (struct prod **)yalloc(sp->s_nprods, sizeof *sp->s_prods);
90: sp->s_nprods = 0; /* il sera recharge a la suite */
91: }
92: /* finally, run down the production table again filling in the
93: list pointers for the corresponding non terminal */
94: for(i=0; i<nprod; i++) {
95: sp = ntrmptr[ -prdptr[i]->p_left-NTBASE ];
96: sp->s_prods[sp->s_nprods++] = prdptr[i];
97: }
98: }
99:
100: /*
101: * assure that all non-terminals generate a token string
102: * algorithm:
103: * assume a priori that no non-terminal generates a token string
104: * if a non terminal contains a production which consists only
105: * of non-terminals generating a token string, and terminals
106: * then it generates a token string
107: * cycle on this until no new non terminals are found
108: * - a similar procedure applies for finding out which non terminals
109: * generate the empty string
110: */
111:
112: ntderive()
113: {
114: register i, j;
115: register struct sym *sp;
116: register struct prod *pp;
117: int *ip;
118: int changed;
119:
120: for(i=0; i<nnonterm; i++)
121: ntrmptr[i]->s_flags &= ~DERIV;
122: do {
123: changed = 0;
124: for(i=0; i<nnonterm; i++) {
125: sp = ntrmptr[i];
126: if( sp->s_flags&DERIV )
127: continue;
128: for(j=0; j<sp->s_nprods; j++) {
129: pp = sp->s_prods[j];
130: for(ip=pp->p_right; *ip!=-1; ip++)
131: if( *ip>=NTBASE &&
132: (ntrmptr[*ip-NTBASE]->s_flags&DERIV)==0 )
133: break;
134: if( *ip == -1 ) {
135: sp->s_flags |= DERIV;
136: changed++;
137: break;
138: }
139: }
140: }
141: } while( changed );
142: for(i=0; i<nnonterm; i++)
143: if( (ntrmptr[i]->s_flags&DERIV)==0 )
144: yyerror(NLNO|!FATAL, "nonterminal %s derives no token string",
145: ntrmptr[i]->s_name);
146: if( nerrors )
147: cleanup(1);
148: }
149:
150: /*
151: * find out which non-terminals derive the empty string
152: * algorithm is simple
153: * if the non-terminal has a production deriving the empty string
154: * it derives the empty string trivially
155: * otherwise if it consists only of productions which can derive the
156: * empty string, then it derives the empty string as well
157: */
158:
159: ntempty()
160: {
161: register *kp;
162: register struct prod **ppp;
163: register struct sym *sp;
164: int i, changed;
165:
166: for(i=0; i<nnonterm; i++)
167: ntrmptr[i]->s_flags &= ~DERIV;
168: do {
169: changed = 0;
170: for(i=0; i<nnonterm; i++) {
171: sp = ntrmptr[i];
172: if( sp->s_flags&DERIV )
173: continue;
174: for(ppp=sp->s_prods; ppp<&sp->s_prods[sp->s_nprods]; ppp++) {
175: for(kp = (*ppp)->p_right; *kp!=-1; kp++ )
176: if( *kp<NTBASE ||
177: (ntrmptr[*kp-NTBASE]->s_flags&DERIV)==0 )
178: break;
179: if( *kp==-1 ) {
180: sp->s_flags |= DERIV;
181: changed++;
182: break;
183: }
184: }
185: }
186: } while( changed );
187: }
188:
189: /* some useful local variables */
190: static newgen; /* communication between genstates and install */
191: static char *ntp; /* buffer for use by chklhs */
192:
193: genstates()
194: {
195: extern struct sitem *nititem;
196: register k, sno;
197: int i;
198: struct tgo tgo;
199: struct ntgo ntgo;
200:
201: /* initialize the list of states associated with each nt to empty */
202: if( verbose )
203: fprintf(listout, "\nAutomaton state description:\n\n");
204: for(i=0; i<nnonterm; i++)
205: ntrmptr[i]->s_nstates = 0;
206: ntp = yalloc(nnonterm, sizeof *ntp); /* array used by "install" */
207: nititem->i_nitems = 1;
208: nititem->i_items[0] = prdptr[0]->p_right;
209: closure();
210: install();
211: i = 0;
212: do {
213: newgen = 0; /* newgen is flagged by the install routine */
214: for(; i<nstates; i++) {
215: fwrite(&i, sizeof i, 1, optout); /* sync number */
216: states[i].s_tgo = 0;
217: for(k=0; k<nterm; k++)
218: if( (sno = go2(items[i], k)) >= 0 ) {
219: states[i].s_tgo++;
220: tgo.tg_st = sno;
221: tgo.tg_trm = k;
222: fwrite(&tgo, sizeof tgo, 1, optout);
223: }
224: states[i].s_ntgo = 0;
225: for(k=0; k<nnonterm; k++)
226: if( (sno = go2(items[i], k+NTBASE)) >= 0 ) {
227: states[i].s_ntgo++;
228: ntgo.ng_st = sno;
229: ntgo.ng_nt = k+NTBASE;
230: ntgo.ng_rel = NULL; /* MWC DSC */
231: fwrite(&ntgo, sizeof ntgo, 1, optout);
232: }
233: states[i].s_nred = 0;
234: for(k=0; k<items[i]->i_nitems; k++)
235: if( *(items[i]->i_items[k]) == -1 )
236: states[i].s_nred++;
237: states[i].s_tgos = states[i].s_ntgos =
238: states[i].s_reds = NULL; /* MWC DSC */
239: }
240: } while( newgen );
241: free(ntp);
242: }
243:
244: /*
245: * generate the closure of a state (found in global variable `nititem'
246: * Algorithm:
247: * - look at every non terminal's after every '.' item pointer
248: * - add all the productions associated with this non-terminal
249: * to the state (the '.' being at the beginning of the rhs) unless
250: * they are already there. It suffices to test if one of them is
251: * already there, since productions are added to the closure according
252: * according to their lhs
253: * repeat this procedure until no new items are added.
254: *
255: * "It can be shown that (this procedure) computes exactly the sets
256: * of items that are valid for gamma X [Aho and Ullmann 1972]"
257: */
258:
259: closure()
260: {
261: register j, **ipp;
262: register struct prod **ppp;
263: struct sitem *itp;
264: struct sym *sp;
265: int i, changed, nt;
266:
267: itp = nititem;
268: for(i=0; i<nnonterm; i++)
269: ntrmptr[i]->s_flags &= ~CPRES;
270: for(i=0; i<itp->i_nitems; i++)
271: /* kludge: requires p.left & p.rights contigouuous */
272: if( (nt = *(itp->i_items[i]-1)) < 0 ) /* ARE THEY???? */
273: ntrmptr[-nt-NTBASE]->s_flags |= CPRES;
274: do {
275: changed = 0;
276: for(i=0; i<itp->i_nitems; i++) {
277: nt = *(itp->i_items[i]);
278: if( nt>=NTBASE && ((sp = ntrmptr[nt-NTBASE])->s_flags
279: &CPRES)==0 ) {
280: sp->s_flags |= CPRES;
281: changed = 1;
282: ppp = sp->s_prods;
283: ipp = &itp->i_items[itp->i_nitems];
284: itp->i_nitems += j = sp->s_nprods;
285: bounded(itp->i_nitems, MAXITEM, "items in state");
286: do
287: *ipp++ = (*ppp++)->p_right;
288: while( --j );
289: }
290: }
291: } while( changed );
292: }
293:
294: /*
295: * add the state in `nititem' to the collection of sets of accessible
296: * items, returning the state pointer
297: * the real work is concerned with finding out whether the set is there
298: * already or not
299: * we sort the items in nititem, compare with every set in "items",
300: * and return the old state pointer if its there already
301: */
302: install()
303: {
304: register n, **ipp1, **ipp2;
305: struct sitem *itp, *itp1;
306: int i;
307:
308: itp = nititem;
309: bubble(itp->i_items, itp->i_nitems);
310: for(i=0; i<nstates; i++) {
311: itp1 = items[i];
312: if( (n = itp->i_nitems) != itp1->i_nitems )
313: continue;
314: ipp1 = itp->i_items;
315: ipp2 = itp1->i_items;
316: do
317: if( *ipp1++ != *ipp2++ )
318: break;
319: while( --n );
320: if( n==0 )
321: break;
322: }
323: if( i==nstates ) {
324: bounded(nstates,maxstates,"states");
325: chklhs();
326: itp1 = (struct sitem *)yalloc(1, sizeof *itp1 + itp->i_nitems *
327: sizeof itp->i_items[0]);
328: copyb(itp, itp1, sizeof *itp1 + itp->i_nitems *
329: sizeof itp->i_items[0]);
330: newgen = 1;
331: items[nstates] = itp1;
332: if( verbose )
333: prstate(nstates, listout);
334: nstates++;
335: }
336: return( i );
337: }
338:
339: go2(itp, tk)
340: struct sitem *itp;
341: int tk;
342: {
343: register **ipp1, **ipp, n;
344:
345: nititem->i_nitems = 0;
346: ipp1 = nititem->i_items;
347: ipp = itp->i_items;
348: n = itp->i_nitems;
349: do {
350: if( **ipp == tk ) {
351: nititem->i_nitems++;
352: *ipp1++ = *ipp+1;
353: }
354: ipp++;
355: } while( --n );
356: if( nititem->i_nitems==0 )
357: return( -1 );
358: else {
359: closure();
360: return( install() );
361: }
362: }
363:
364: chklhs()
365: {
366: register n, **ipp;
367: register char *cp;
368: int nt;
369:
370: n = nnonterm;
371: cp = ntp;
372: do *cp++ = 0; while( --n );
373: ipp = nititem->i_items;
374: n = nititem->i_nitems;
375: cp = ntp;
376: do
377: if( (nt = (*ipp++) [-1]) < 0 )
378: cp[ -nt-NTBASE ] = 1;
379: while( --n );
380: for(n=0; n<nnonterm; n++)
381: if( cp[n] )
382: ntrmptr[n]->s_nstates++;
383: }
384:
385: /*
386: * for each nonterminal generate a list of items
387: * containing items with all of the rhs of a production
388: * whose lhs is the non-terminal after the '.'
389: */
390: genslist()
391: {
392: register struct sym *sp;
393: register i, j;
394: int *ip;
395: int *stp;
396:
397: for(i=j=0; i<nnonterm; i++)
398: j += ntrmptr[i]->s_nstates;
399: stp = (int *)yalloc(j, sizeof *stp);
400: for(i=0; i<nnonterm; i++) {
401: sp = ntrmptr[i];
402: sp->s_states = stp;
403: stp += sp->s_nstates;
404: sp->s_nstates = 0; /* a recharcher dans le boucle suivant */
405: }
406: for(i=0; i<nnonterm; i++) {
407: sp = ntrmptr[i];
408: ip = sp->s_prods[0]->p_right; /* pick an item, any item */
409: for(j=0; j<nstates; j++)
410: if( pitem(ip, items[j]) )
411: sp->s_states[sp->s_nstates++] = j;
412: }
413: }
414:
415: /* binary search for an item in a state */
416:
417: pitem(ip,itp)
418: int *ip;
419: register struct sitem *itp;
420: {
421: register int *el, nb;
422: int ub, lb;
423:
424: lb = 0;
425: ub = itp->i_nitems-1;
426: do {
427: nb = (ub+lb) / 2;
428: if( (el = itp->i_items[nb]) < ip )
429: lb = nb+1;
430: else if( el > ip )
431: ub = nb-1;
432: else
433: return(1);
434: } while( lb<=ub );
435: return(0);
436: }
437:
438: /*
439: * linear insertion sort really.
440: * the decision not to use bubbbbbbbbbbbble sort is thanks to Randall
441: * and to his cs240b notes
442: * (p.s. -- i hate sorting)
443: */
444:
445: bubble(ipp,n)
446: register **ipp;
447: int n;
448: {
449: register **min, **jpp;
450: int m, *t; /* MWC DSC */
451:
452: do {
453: m = n;
454: min = jpp = ipp;
455: do {
456: if( *jpp < *min )
457: min = jpp;
458: jpp++;
459: } while( --m );
460: t = *min;
461: *min = *ipp;
462: *ipp++ = t;
463: } while( --n );
464: }
465:
466: copyb(sp,dp,n)
467: register char *sp, *dp;
468: register n;
469: {
470: do
471: *dp++ = *sp++;
472: while( --n );
473: }
474:
475: cleanup(err)
476: {
477: unlink(acttmp);
478: unlink(opttmp);
479: stats();
480: exit(err);
481: }
482:
483: stats()
484: {
485: extern nsrconf, nrrconf;
486:
487: if( !pstat && (nsrconf || nrrconf) ) {
488: if( nrrconf ) {
489: fprintf(stderr, "%d R/R conflict", nrrconf);
490: if( nrrconf != 1 )
491: fprintf(stderr, "s");
492: }
493: if( nrrconf && nsrconf )
494: fprintf(stderr, " and ");
495: if( nsrconf ) {
496: fprintf(stderr, "%d S/R conflict", nsrconf);
497: if( nsrconf != 1)
498: fprintf(stderr, "s");
499: }
500: fprintf(stderr, "\n");
501: }
502: if( verbose )
503: stat1(listout);
504: if( pstat )
505: stat1(stdout);
506: }
507:
508:
509: stat1(f)
510: FILE *f;
511: {
512: extern nsrconf, nrrconf, yygodef, yypact, yyredns;
513: extern ndupgos, ndupacts;
514: extern yydefact;
515:
516: fprintf(f, "Statistics:\n");
517: fprintf(f, "%d/%d tokens, %d/%d non terminals\n", nterm, maxterm,
518: nnonterm, maxnterm);
519: fprintf(f, "%d/%d productions, %d/%d states\n", nprod, maxprod,
520: nstates, maxstates);
521: fprintf(f, "%d goto entries; %d saved by goto default\n",
522: yyredns, yygodef);
523: fprintf(f, "%d parsing actions; %d saved by default\n",
524: yypact, yydefact);
525: fprintf(f, "%d duplicated goto entries saved; %d actions\n",
526: ndupgos, ndupacts);
527: if( nsrconf || nrrconf )
528: fprintf(f, "%d R/R conflicts, %d S/R conflicts\n",
529: nrrconf, nsrconf);
530: }
531:
532: char *
533: yalloc(n, s)
534: {
535: register char *cp;
536:
537: if( cp = calloc(n, s) )
538: return(cp);
539: yyerror(NLNO|FATAL, "storage overflow (requested %d)\n", n*s);
540: }
541:
542: /*
543: * transform the state representation
544: */
545:
546: sttrans()
547: {
548: register j, k;
549: int i, totgo, tontgo;
550: register struct state *stp;
551: struct tgo *tgp;
552: struct ntgo *ngp;
553:
554: /* a la pubelle !! */
555: for(i=0; i<nstates; i++)
556: free(items[i]);
557: free(items);
558:
559: if( yydebug )
560: fprintf(listout,"Automaton transition graph:\n\n");
561: for(i=totgo=0; i<nstates; i++)
562: totgo += states[i].s_tgo;
563: for(i=tontgo=0; i<nstates; i++)
564: tontgo += states[i].s_ntgo;
565: tgp = (struct tgo *)yalloc(totgo, sizeof *tgp);
566: ngp = (struct ntgo *)yalloc(tontgo, sizeof *ngp);
567: rewopt();
568:
569: for(j=0; j<nstates; j++) {
570: if( yydebug )
571: fprintf(listout, "State %d:\n\n", j);
572: stp = &states[j];
573: if( fread(&i, sizeof i, 1, optout)!=1 || i!=j )
574: yyerror(NLNO|FATAL, "temp file i/o error");
575: fread(tgp, sizeof *tgp, stp->s_tgo, optout);
576: stp->s_tgos = tgp;
577: stp->s_ntgos = ngp;
578: if( yydebug )
579: for(k=0; k<stp->s_tgo; k++)
580: fprintf(listout, "\t%s\t%d\n",
581: ptosym(stp->s_tgos[k].tg_trm),
582: stp->s_tgos[k].tg_st);
583: fread(ngp, sizeof *ngp, stp->s_ntgo, optout);
584: if( yydebug )
585: for(k=0; k<stp->s_ntgo; k++)
586: fprintf(listout, "\t%s\t%d\n",
587: ptosym(stp->s_ntgos[k].ng_nt),
588: stp->s_ntgos[k].ng_st);
589: tgp += stp->s_tgo;
590: ngp += stp->s_ntgo;
591: }
592: }
593:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.