|
|
1.1 ! root 1: /* ! 2: * LALR-1 parser generator ! 3: */ ! 4: ! 5: #include <string.h> ! 6: #include "yacc.h" ! 7: ! 8: main(argc,argv) ! 9: char *argv[]; ! 10: { ! 11: options(argc,argv); ! 12: getfiles(); ! 13: readrules(); ! 14: ntprod(); ! 15: ntderive(); ! 16: listgram(); ! 17: if( nerrors ) ! 18: cleanup(1); ! 19: ntempty(); ! 20: if( nerrors ) ! 21: cleanup(1); ! 22: genstates(); ! 23: genslist(); ! 24: sttrans(); ! 25: genlook(); ! 26: go2out(); ! 27: paout(); ! 28: callopt(); ! 29: cleanup(0); ! 30: } ! 31: ! 32: getfiles() ! 33: { ! 34: if( gramy==NULL ) ! 35: usage(); ! 36: if( strcmp(gramy,"-")==0 ) ! 37: defin = stdin; ! 38: else ! 39: if( (defin = fopen(gramy,"r")) == NULL ) ! 40: yyerror(!FATAL, "cannot open grammar file %s", gramy); ! 41: mktemp(acttmp); ! 42: mktemp(opttmp); ! 43: if( (actout = fopen(acttmp,"w")) == NULL ) ! 44: yyerror(!FATAL, "cannot create action temp file %s", acttmp); ! 45: if( (tabout = fopen(ytabc,"w")) == NULL ) ! 46: yyerror(!FATAL, "cannot create output file %s", ytabc); ! 47: if( (fhdr = fopen(ytabh, "w")) == NULL ) ! 48: yyerror(!FATAL, "cannot create %s", ytabh); ! 49: if( verbose ) ! 50: if( (listout = fopen(youtput,"w")) == NULL ) ! 51: yyerror(NLNO, "cannot open listing file %s", youtput); ! 52: if ((optout = fopen(opttmp, "wb")) == NULL ! 53: || (optout = freopen(opttmp, "rwb", optout)) == NULL) ! 54: yyerror(NLNO, "open error temp %s", opttmp); ! 55: if( nerrors ) ! 56: cleanup(2); ! 57: } ! 58: ! 59: rewopt() ! 60: { ! 61: fseek(optout, 0L, 0); ! 62: } ! 63: ! 64: /* ! 65: * for each non-terminal, generate a list of productions which the ! 66: * the non terminal derives ! 67: */ ! 68: ntprod() ! 69: { ! 70: register i; ! 71: register struct sym *sp; ! 72: ! 73: /* first run down the production table, counting references to ! 74: all the non terminals. */ ! 75: for(i=0; i<nnonterm; i++) ! 76: ntrmptr[i]->s_nprods = 0; ! 77: for(i=0; i<nprod; i++) ! 78: ntrmptr[-prdptr[i]->p_left-NTBASE]->s_nprods++; ! 79: for(i=0; i<nnonterm; i++) ! 80: if( ntrmptr[i]->s_nprods==0 ) ! 81: yyerror(NLNO|!FATAL, "non terminal %s not defined", ! 82: ntrmptr[i]->s_name); ! 83: if( nerrors ) ! 84: cleanup(1); ! 85: /* now allocate list pointers for each non-terminal */ ! 86: for(i=0; i<nnonterm; i++) { ! 87: sp = ntrmptr[i]; ! 88: sp->s_prods = (struct prod **) ! 89: 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 = PROD_RIGHT (pp); *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 = PROD_RIGHT (*ppp); *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] = PROD_RIGHT (prdptr[0]); ! 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 = NULL; ! 238: states[i].s_ntgos = NULL; ! 239: states[i].s_reds = NULL; /* MWC DSC */ ! 240: } ! 241: } while( newgen ); ! 242: free(ntp); ! 243: } ! 244: ! 245: /* ! 246: * generate the closure of a state (found in global variable `nititem' ! 247: * Algorithm: ! 248: * - look at every non terminal's after every '.' item pointer ! 249: * - add all the productions associated with this non-terminal ! 250: * to the state (the '.' being at the beginning of the rhs) unless ! 251: * they are already there. It suffices to test if one of them is ! 252: * already there, since productions are added to the closure according ! 253: * according to their lhs ! 254: * repeat this procedure until no new items are added. ! 255: * ! 256: * "It can be shown that (this procedure) computes exactly the sets ! 257: * of items that are valid for gamma X [Aho and Ullmann 1972]" ! 258: */ ! 259: ! 260: closure() ! 261: { ! 262: register j, **ipp; ! 263: register struct prod **ppp; ! 264: struct sitem *itp; ! 265: struct sym *sp; ! 266: int i, changed, nt; ! 267: ! 268: itp = nititem; ! 269: for(i=0; i<nnonterm; i++) ! 270: ntrmptr[i]->s_flags &= ~CPRES; ! 271: for(i=0; i<itp->i_nitems; i++) ! 272: /* kludge: requires p.left & p.rights contiguous */ ! 273: if( (nt = *(itp->i_items[i]-1)) < 0 ) { /* ARE THEY???? */ ! 274: #if 0 ! 275: fprintf (stderr, "CPRES : %d\n", i); ! 276: #endif ! 277: ntrmptr[-nt-NTBASE]->s_flags |= CPRES; ! 278: } ! 279: do { ! 280: changed = 0; ! 281: for(i=0; i<itp->i_nitems; i++) { ! 282: nt = *(itp->i_items[i]); ! 283: if( nt>=NTBASE && ((sp = ntrmptr[nt-NTBASE])->s_flags ! 284: &CPRES)==0 ) { ! 285: sp->s_flags |= CPRES; ! 286: changed = 1; ! 287: ppp = sp->s_prods; ! 288: ipp = &itp->i_items[itp->i_nitems]; ! 289: itp->i_nitems += j = sp->s_nprods; ! 290: bounded(itp->i_nitems, maxitem, "items in state"); ! 291: do ! 292: *ipp++ = PROD_RIGHT (*ppp++); ! 293: while( --j ); ! 294: } ! 295: } ! 296: } while( changed ); ! 297: } ! 298: ! 299: /* ! 300: * add the state in `nititem' to the collection of sets of accessible ! 301: * items, returning the state pointer ! 302: * the real work is concerned with finding out whether the set is there ! 303: * already or not ! 304: * we sort the items in nititem, compare with every set in "items", ! 305: * and return the old state pointer if its there already ! 306: */ ! 307: install() ! 308: { ! 309: register n, **ipp1, **ipp2; ! 310: struct sitem *itp, *itp1; ! 311: int i; ! 312: ! 313: itp = nititem; ! 314: bubble(itp->i_items, itp->i_nitems); ! 315: for(i=0; i<nstates; i++) { ! 316: itp1 = items[i]; ! 317: if( (n = itp->i_nitems) != itp1->i_nitems ) ! 318: continue; ! 319: ipp1 = itp->i_items; ! 320: ipp2 = itp1->i_items; ! 321: do ! 322: if( *ipp1++ != *ipp2++ ) ! 323: break; ! 324: while( --n ); ! 325: if( n==0 ) ! 326: break; ! 327: } ! 328: if (i == nstates) { ! 329: bounded (nstates,maxstates,"states"); ! 330: chklhs (); ! 331: ! 332: /* ! 333: * NIGEL: Changed to stop use of flex-arrays. ! 334: */ ! 335: ! 336: itp1 = (struct sitem *) ! 337: yalloc (1, SITEM_TOTAL_SIZE (itp->i_nitems)); ! 338: * itp1 = * itp; ! 339: SITEM_EXTRA_INIT (itp1); ! 340: ! 341: if (SITEM_EXTRA_SIZE (itp->i_nitems) > 0) ! 342: memcpy (itp1->i_items, itp->i_items, ! 343: SITEM_EXTRA_SIZE (itp->i_nitems)); ! 344: ! 345: newgen = 1; ! 346: items [nstates] = itp1; ! 347: if (verbose) ! 348: prstate (nstates, listout); ! 349: nstates ++; ! 350: } ! 351: return i; ! 352: } ! 353: ! 354: go2(itp, tk) ! 355: struct sitem *itp; ! 356: int tk; ! 357: { ! 358: register **ipp1, **ipp, n; ! 359: ! 360: nititem->i_nitems = 0; ! 361: ipp1 = nititem->i_items; ! 362: ipp = itp->i_items; ! 363: n = itp->i_nitems; ! 364: do { ! 365: if( **ipp == tk ) { ! 366: nititem->i_nitems++; ! 367: *ipp1++ = *ipp+1; ! 368: } ! 369: ipp++; ! 370: } while( --n ); ! 371: if( nititem->i_nitems==0 ) ! 372: return( -1 ); ! 373: else { ! 374: closure(); ! 375: return( install() ); ! 376: } ! 377: } ! 378: ! 379: chklhs() ! 380: { ! 381: register n, **ipp; ! 382: register char *cp; ! 383: int nt; ! 384: ! 385: n = nnonterm; ! 386: cp = ntp; ! 387: do *cp++ = 0; while( --n ); ! 388: ipp = nititem->i_items; ! 389: n = nititem->i_nitems; ! 390: cp = ntp; ! 391: do ! 392: if( (nt = (*ipp++) [-1]) < 0 ) ! 393: cp[ -nt-NTBASE ] = 1; ! 394: while( --n ); ! 395: for(n=0; n<nnonterm; n++) ! 396: if( cp[n] ) ! 397: ntrmptr[n]->s_nstates++; ! 398: } ! 399: ! 400: /* ! 401: * for each nonterminal generate a list of items ! 402: * containing items with all of the rhs of a production ! 403: * whose lhs is the non-terminal after the '.' ! 404: */ ! 405: genslist() ! 406: { ! 407: register struct sym *sp; ! 408: register i, j; ! 409: int *ip; ! 410: int *stp; ! 411: ! 412: for(i=j=0; i<nnonterm; i++) ! 413: j += ntrmptr[i]->s_nstates; ! 414: stp = (int *)yalloc(j, sizeof *stp); ! 415: for(i=0; i<nnonterm; i++) { ! 416: sp = ntrmptr[i]; ! 417: sp->s_states = stp; ! 418: stp += sp->s_nstates; ! 419: sp->s_nstates = 0; /* a recharcher dans le boucle suivant */ ! 420: } ! 421: for(i=0; i<nnonterm; i++) { ! 422: sp = ntrmptr[i]; ! 423: ip = PROD_RIGHT (sp->s_prods[0]); /* pick an item, any item */ ! 424: for(j=0; j<nstates; j++) ! 425: if( pitem(ip, items[j]) ) ! 426: sp->s_states[sp->s_nstates++] = j; ! 427: } ! 428: } ! 429: ! 430: /* binary search for an item in a state */ ! 431: ! 432: pitem(ip,itp) ! 433: int *ip; ! 434: register struct sitem *itp; ! 435: { ! 436: register int *el, nb; ! 437: int ub, lb; ! 438: ! 439: lb = 0; ! 440: ub = itp->i_nitems-1; ! 441: do { ! 442: nb = (ub+lb) / 2; ! 443: if( (el = itp->i_items[nb]) < ip ) ! 444: lb = nb+1; ! 445: else if( el > ip ) ! 446: ub = nb-1; ! 447: else ! 448: return(1); ! 449: } while( lb<=ub ); ! 450: return(0); ! 451: } ! 452: ! 453: /* ! 454: * linear insertion sort really. ! 455: * the decision not to use bubbbbbbbbbbbble sort is thanks to Randall ! 456: * and to his cs240b notes ! 457: * (p.s. -- i hate sorting) ! 458: */ ! 459: ! 460: bubble(ipp,n) ! 461: register **ipp; ! 462: int n; ! 463: { ! 464: register **min, **jpp; ! 465: int m, *t; /* MWC DSC */ ! 466: ! 467: do { ! 468: m = n; ! 469: min = jpp = ipp; ! 470: do { ! 471: if( *jpp < *min ) ! 472: min = jpp; ! 473: jpp++; ! 474: } while( --m ); ! 475: t = *min; ! 476: *min = *ipp; ! 477: *ipp++ = t; ! 478: } while( --n ); ! 479: } ! 480: ! 481: cleanup(err) ! 482: { ! 483: unlink(acttmp); ! 484: unlink(opttmp); ! 485: stats(); ! 486: exit(err); ! 487: } ! 488: ! 489: stats() ! 490: { ! 491: extern nsrconf, nrrconf; ! 492: ! 493: if( !pstat && (nsrconf || nrrconf) ) { ! 494: if( nrrconf ) { ! 495: fprintf(stderr, "%d R/R conflict", nrrconf); ! 496: if( nrrconf != 1 ) ! 497: fprintf(stderr, "s"); ! 498: } ! 499: if( nrrconf && nsrconf ) ! 500: fprintf(stderr, " and "); ! 501: if( nsrconf ) { ! 502: fprintf(stderr, "%d S/R conflict", nsrconf); ! 503: if( nsrconf != 1) ! 504: fprintf(stderr, "s"); ! 505: } ! 506: fprintf(stderr, "\n"); ! 507: } ! 508: if( verbose ) ! 509: stat1(listout); ! 510: if( pstat ) ! 511: stat1(stdout); ! 512: } ! 513: ! 514: ! 515: stat1(f) ! 516: FILE *f; ! 517: { ! 518: extern nsrconf, nrrconf, yygodef, yypact, yyredns; ! 519: extern ndupgos, ndupacts; ! 520: extern yydefact; ! 521: ! 522: fprintf(f, "Statistics:\n"); ! 523: fprintf(f, "%d/%d tokens, %d/%d non terminals\n", nterm, maxterm, ! 524: nnonterm, maxnterm); ! 525: fprintf(f, "%d/%d productions, %d/%d states\n", nprod, maxprod, ! 526: nstates, maxstates); ! 527: fprintf(f, "%d goto entries; %d saved by goto default\n", ! 528: yyredns, yygodef); ! 529: fprintf(f, "%d parsing actions; %d saved by default\n", ! 530: yypact, yydefact); ! 531: fprintf(f, "%d duplicated goto entries saved; %d actions\n", ! 532: ndupgos, ndupacts); ! 533: if( nsrconf || nrrconf ) ! 534: fprintf(f, "%d R/R conflicts, %d S/R conflicts\n", ! 535: nrrconf, nsrconf); ! 536: } ! 537: ! 538: char * ! 539: yalloc(n, s) ! 540: { ! 541: register char *cp; ! 542: ! 543: if ((cp = calloc(n, s)) == NULL) ! 544: yyerror (NLNO | FATAL, ! 545: "storage overflow (requested %d * %d)\n", n, s); ! 546: ! 547: return cp; ! 548: } ! 549: ! 550: /* ! 551: * transform the state representation ! 552: */ ! 553: ! 554: sttrans() ! 555: { ! 556: register j, k; ! 557: int i, totgo, tontgo; ! 558: register struct state *stp; ! 559: struct tgo *tgp; ! 560: struct ntgo *ngp; ! 561: ! 562: /* a la pubelle !! */ ! 563: for(i=0; i<nstates; i++) ! 564: free(items[i]); ! 565: free(items); ! 566: ! 567: if( yydebug ) ! 568: fprintf(listout,"Automaton transition graph:\n\n"); ! 569: for(i=totgo=0; i<nstates; i++) ! 570: totgo += states[i].s_tgo; ! 571: for(i=tontgo=0; i<nstates; i++) ! 572: tontgo += states[i].s_ntgo; ! 573: tgp = (struct tgo *)yalloc(totgo, sizeof *tgp); ! 574: ngp = (struct ntgo *)yalloc(tontgo, sizeof *ngp); ! 575: rewopt(); ! 576: ! 577: for(j=0; j<nstates; j++) { ! 578: if( yydebug ) ! 579: fprintf(listout, "State %d:\n\n", j); ! 580: stp = &states[j]; ! 581: if( fread(&i, sizeof i, 1, optout)!=1 || i!=j ) ! 582: yyerror(NLNO|FATAL, "temp file i/o error"); ! 583: fread(tgp, sizeof *tgp, stp->s_tgo, optout); ! 584: stp->s_tgos = tgp; ! 585: stp->s_ntgos = ngp; ! 586: if( yydebug ) ! 587: for(k=0; k<stp->s_tgo; k++) ! 588: fprintf(listout, "\t%s\t%d\n", ! 589: ptosym(stp->s_tgos[k].tg_trm), ! 590: stp->s_tgos[k].tg_st); ! 591: fread(ngp, sizeof *ngp, stp->s_ntgo, optout); ! 592: if( yydebug ) ! 593: for(k=0; k<stp->s_ntgo; k++) ! 594: fprintf(listout, "\t%s\t%d\n", ! 595: ptosym(stp->s_ntgos[k].ng_nt), ! 596: stp->s_ntgos[k].ng_st); ! 597: tgp += stp->s_tgo; ! 598: ngp += stp->s_ntgo; ! 599: } ! 600: } ! 601:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.