yacc.c - 9base - revived minimalist port of Plan 9 userland to Unix
 (HTM) git clone git://git.suckless.org/9base
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       yacc.c (58914B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 #include <bio.h>
            4 #include <ctype.h>
            5 
            6 #define        Bungetrune        Bungetc                /* ok for now. */
            7 
            8 /*
            9  * all these are 32 bit
           10  */
           11 #define TBITSET                ((32+NTERMS)/32)        /* BOTCH?? +31 */
           12 #define BIT(a,i)        ((a)[(i)>>5] & (1<<((i)&037)))
           13 #define SETBIT(a,i)        ((a)[(i)>>5] |= (1<<((i)&037)))
           14 #define NWORDS(n)        (((n)+32)/32)
           15 
           16 char *PARSER = "#9/yacc/yaccpar";
           17 char *PARSERS = "#9/yacc/yaccpars";
           18 
           19 #define TEMPNAME        "y.tmp.XXXXXX"
           20 #define ACTNAME                "y.acts.XXXXXX"
           21 #define OFILE                "tab.c"
           22 #define FILEU                "output"
           23 #define FILED                "tab.h"
           24 #define FILEDEBUG        "debug"
           25 
           26 enum
           27 {
           28 /*
           29  * the following are adjustable
           30  * according to memory size
           31  */
           32         ACTSIZE                = 40000,
           33         MEMSIZE                = 40000,
           34         NSTATES                = 2000,
           35         NTERMS                = 511,
           36         NPROD                = 1600,
           37         NNONTERM        = 600,
           38         TEMPSIZE        = 2000,
           39         CNAMSZ                = 10000,
           40         LSETSIZE        = 2400,
           41         WSETSIZE        = 350,
           42 
           43         NAMESIZE        = 50,
           44         NTYPES                = 63,
           45         ISIZE                = 400,
           46 
           47         PRIVATE                = 0xE000,        /* unicode private use */
           48 
           49         /* relationships which must hold:
           50                 TBITSET ints must hold NTERMS+1 bits...
           51                 WSETSIZE >= NNONTERM
           52                 LSETSIZE >= NNONTERM
           53                 TEMPSIZE >= NTERMS + NNONTERM + 1
           54                 TEMPSIZE >= NSTATES
           55         */
           56 
           57         NTBASE                = 010000,
           58         ERRCODE                = 8190,
           59         ACCEPTCODE        = 8191,
           60 
           61         NOASC                = 0,        /* no assoc. */
           62         LASC                = 1,        /* left assoc. */
           63         RASC                = 2,        /* right assoc. */
           64         BASC                = 3,        /* binary assoc. */
           65 
           66         /* flags for state generation */
           67 
           68         DONE                = 0,
           69         MUSTDO                = 1,
           70         MUSTLOOKAHEAD        = 2,
           71 
           72         /* flags for a rule having an action, and being reduced */
           73 
           74         ACTFLAG                = 04,
           75         REDFLAG                = 010,
           76 
           77         /* output parser flags */
           78         YYFLAG1                = -1000,
           79 
           80         /* parse tokens */
           81         IDENTIFIER        = PRIVATE,
           82         MARK,
           83         TERM,
           84         LEFT,
           85         RIGHT,
           86         BINARY,
           87         PREC,
           88         LCURLY,
           89         IDENTCOLON,
           90         NUMBER,
           91         START,
           92         TYPEDEF,
           93         TYPENAME,
           94         UNION,
           95 
           96         ENDFILE                = 0,
           97 
           98         EMPTY                = 1,
           99         WHOKNOWS        = 0,
          100         OK                = 1,
          101         NOMORE                = -1000
          102 };
          103 
          104         /* macros for getting associativity and precedence levels */
          105 
          106 #define ASSOC(i)        ((i)&03)
          107 #define PLEVEL(i)        (((i)>>4)&077)
          108 #define TYPE(i)                (((i)>>10)&077)
          109 
          110         /* macros for setting associativity and precedence levels */
          111 
          112 #define SETASC(i,j)        i |= j
          113 #define SETPLEV(i,j)        i |= (j<<4)
          114 #define SETTYPE(i,j)        i |= (j<<10)
          115 
          116         /* looping macros */
          117 
          118 #define TLOOP(i)        for(i=1; i<=ntokens; i++)
          119 #define NTLOOP(i)        for(i=0; i<=nnonter; i++)
          120 #define PLOOP(s,i)        for(i=s; i<nprod; i++)
          121 #define SLOOP(i)        for(i=0; i<nstate; i++)
          122 #define WSBUMP(x)        x++
          123 #define WSLOOP(s,j)        for(j=s; j<cwp; j++)
          124 #define ITMLOOP(i,p,q)        for(q=pstate[i+1], p=pstate[i]; p<q; p++)
          125 #define SETLOOP(i)        for(i=0; i<tbitset; i++)
          126 
          127         /* command to clobber tempfiles after use */
          128 
          129 #define        ZAPFILE(x)        if(x) remove(x)
          130 
          131         /* I/O descriptors */
          132 
          133 Biobuf*        faction;        /* file for saving actions */
          134 Biobuf*        fdefine;        /* file for #defines */
          135 Biobuf*        fdebug;                /* y.debug for strings for debugging */
          136 Biobuf*        ftable;                /* y.tab.c file */
          137 Biobuf*        ftemp;                /* tempfile to pass 2 */
          138 Biobuf*        finput;                /* input file */
          139 Biobuf*        foutput;        /* y.output file */
          140 
          141         /* communication variables between various I/O routines */
          142 
          143 char*        infile;                        /* input file name */
          144 int        numbval;                /* value of an input number */
          145 char        tokname[NAMESIZE+4];        /* input token name, slop for runes and 0 */
          146 
          147         /* structure declarations */
          148 
          149 typedef
          150 struct
          151 {
          152         int        lset[TBITSET];
          153 } Lkset;
          154 
          155 typedef
          156 struct
          157 {
          158         int*        pitem;
          159         Lkset*        look;
          160 } Item;
          161 
          162 typedef
          163 struct
          164 {
          165         char*        name;
          166         int        value;
          167 } Symb;
          168 
          169 typedef
          170 struct
          171 {
          172         int*        pitem;
          173         int        flag;
          174         Lkset        ws;
          175 } Wset;
          176 
          177         /* storage of names */
          178 
          179 char        cnames[CNAMSZ];                /* place where token and nonterminal names are stored */
          180 int        cnamsz = CNAMSZ;        /* size of cnames */
          181 char*        cnamp = cnames;                /* place where next name is to be put in */
          182 int        ndefout = 4;                /* number of defined symbols output */
          183 char*        tempname;
          184 char*        actname;
          185 char        ttempname[] = TEMPNAME;
          186 char        tactname[] = ACTNAME;
          187 char*        parser;
          188 char*        yydebug;
          189 int        yyarg;
          190 int        yyline = 1;
          191 
          192         /* storage of types */
          193 int        ntypes;                        /* number of types defined */
          194 char*        typeset[NTYPES];        /* pointers to type tags */
          195 
          196         /* token information */
          197 
          198 int        ntokens = 0 ;                /* number of tokens */
          199 Symb        tokset[NTERMS];
          200 int        toklev[NTERMS];                /* vector with the precedence of the terminals */
          201 
          202         /* nonterminal information */
          203 
          204 int        nnonter = -1;                /* the number of nonterminals */
          205 Symb        nontrst[NNONTERM];
          206 int        start;                        /* start symbol */
          207 
          208         /* assigned token type values */
          209 int        extval = 0;
          210 
          211 char*        ytabc = OFILE;        /* name of y.tab.c */
          212 
          213         /* grammar rule information */
          214 
          215 int        mem0[MEMSIZE] ;                /* production storage */
          216 int*        mem = mem0;
          217 int        nprod = 1;                /* number of productions */
          218 int*        prdptr[NPROD];                /* pointers to descriptions of productions */
          219 int        levprd[NPROD];                /* precedence levels for the productions */
          220 int        rlines[NPROD];                /* line number for this rule */
          221 
          222         /* state information */
          223 
          224 int        nstate = 0;                /* number of states */
          225 Item*        pstate[NSTATES+2];        /* pointers to the descriptions of the states */
          226 int        tystate[NSTATES];        /* contains type information about the states */
          227 int        defact[NSTATES];        /* the default actions of states */
          228 int        tstates[NTERMS];        /* states generated by terminal gotos */
          229 int        ntstates[NNONTERM];         /* states generated by nonterminal gotos */
          230 int        mstates[NSTATES];        /* chain of overflows of term/nonterm generation lists  */
          231 int        lastred;                 /* the number of the last reduction of a state */
          232 
          233         /* lookahead set information */
          234 
          235 Lkset        lkst[LSETSIZE];
          236 int        nolook;                        /* flag to turn off lookahead computations */
          237 int        tbitset;                /* size of lookahead sets */
          238 int        nlset = 0;                /* next lookahead set index */
          239 int        nolook = 0;                /* flag to suppress lookahead computations */
          240 Lkset        clset;                  /* temporary storage for lookahead computations */
          241 
          242         /* working set information */
          243 
          244 Wset        wsets[WSETSIZE];
          245 Wset*        cwp;
          246 
          247         /* storage for action table */
          248 
          249 int        amem[ACTSIZE];                /* action table storage */
          250 int*        memp = amem;                /* next free action table position */
          251 int        indgo[NSTATES];                /* index to the stored goto table */
          252 
          253         /* temporary vector, indexable by states, terms, or ntokens */
          254 
          255 int        temp1[TEMPSIZE];        /* temporary storage, indexed by terms + ntokens or states */
          256 int        lineno = 1;                /* current input line number */
          257 int        fatfl = 1;                  /* if on, error is fatal */
          258 int        nerrors = 0;                /* number of errors */
          259 
          260         /* statistics collection variables */
          261 
          262 int        zzgoent;
          263 int        zzgobest;
          264 int        zzacent;
          265 int        zzexcp;
          266 int        zzclose;
          267 int        zzrrconf;
          268 int        zzsrconf;
          269 
          270 int*        ggreed = lkst[0].lset;
          271 int*        pgo = wsets[0].ws.lset;
          272 int*        yypgo = &nontrst[0].value;
          273 
          274 int        maxspr = 0;                  /* maximum spread of any entry */
          275 int        maxoff = 0;                  /* maximum offset into a array */
          276 int*        pmem = mem0;
          277 int*        maxa;
          278 int        nxdb = 0;
          279 int        adb = 0;
          280 
          281 
          282         /* storage for information about the nonterminals */
          283 
          284 int**        pres[NNONTERM+2];          /* vector of pointers to productions yielding each nonterminal */
          285 Lkset*        pfirst[NNONTERM+2];        /* vector of pointers to first sets for each nonterminal */
          286 int        pempty[NNONTERM+1];        /* vector of nonterminals nontrivially deriving e */
          287 
          288         /* random stuff picked out from between functions */
          289 
          290 int        indebug = 0;
          291 Wset*        zzcwp = wsets;
          292 int        zzgoent = 0;
          293 int        zzgobest = 0;
          294 int        zzacent = 0;
          295 int        zzexcp = 0;
          296 int        zzclose = 0;
          297 int        zzsrconf = 0;
          298 int*        zzmemsz = mem0;
          299 int        zzrrconf = 0;
          300 int        pidebug = 0;                /* debugging flag for putitem */
          301 int        gsdebug = 0;
          302 int        cldebug = 0;                /* debugging flag for closure */
          303 int        pkdebug = 0;
          304 int        g2debug = 0;
          305 
          306 struct
          307 {
          308         char*        name;
          309         long        value;
          310 } resrv[] =
          311 {
          312         "binary",        BINARY,
          313         "left",                LEFT,
          314         "nonassoc",        BINARY,
          315         "prec",                PREC,
          316         "right",        RIGHT,
          317         "start",        START,
          318         "term",                TERM,
          319         "token",        TERM,
          320         "type",                TYPEDEF,
          321         "union",        UNION,
          322         0,
          323 };
          324 
          325         /* define functions */
          326 
          327 void        main(int, char**);
          328 void        others(void);
          329 char*        chcopy(char*, char*);
          330 char*        writem(int*);
          331 char*        symnam(int);
          332 void        summary(void);
          333 void        error(char*, ...);
          334 void        aryfil(int*, int, int);
          335 int        setunion(int*, int*);
          336 void        prlook(Lkset*);
          337 void        cpres(void);
          338 void        cpfir(void);
          339 int        state(int);
          340 void        putitem(int*, Lkset*);
          341 void        cempty(void);
          342 void        stagen(void);
          343 void        closure(int);
          344 Lkset*        flset(Lkset*);
          345 void        cleantmp(void);
          346 void        intr(void);
          347 void        setup(int, char**);
          348 void        finact(void);
          349 int        defin(int, char*);
          350 void        defout(int);
          351 char*        cstash(char*);
          352 long        gettok(void);
          353 int        fdtype(int);
          354 int        chfind(int, char*);
          355 void        cpyunion(void);
          356 void        cpycode(void);
          357 int        skipcom(void);
          358 void        cpyact(int);
          359 void        openup(char*, int, int, int, char*);
          360 void        output(void);
          361 int        apack(int*, int);
          362 void        go2out(void);
          363 void        go2gen(int);
          364 void        precftn(int, int, int);
          365 void        wract(int);
          366 void        wrstate(int);
          367 void        warray(char*, int*, int);
          368 void        hideprod(void);
          369 void        callopt(void);
          370 void        gin(int);
          371 void        stin(int);
          372 int        nxti(void);
          373 void        osummary(void);
          374 void        aoutput(void);
          375 void        arout(char*, int*, int);
          376 int        gtnm(void);
          377 
          378 void
          379 main(int argc, char *argv[])
          380 {
          381         PARSER = unsharp(PARSER);
          382         PARSERS = unsharp(PARSERS);
          383         parser = PARSER;
          384 
          385         setup(argc, argv);        /* initialize and read productions */
          386         tbitset = NWORDS(ntokens);
          387         cpres();                /* make table of which productions yield a given nonterminal */
          388         cempty();                /* make a table of which nonterminals can match the empty string */
          389         cpfir();                /* make a table of firsts of nonterminals */
          390         stagen();                /* generate the states */
          391         output();                /* write the states and the tables */
          392         go2out();
          393         hideprod();
          394         summary();
          395         callopt();
          396         others();
          397         exits(0);
          398 }
          399 
          400 /*
          401  * put out other arrays, copy the parsers
          402  */
          403 void
          404 others(void)
          405 {
          406         int c, i, j;
          407 
          408         finput = Bopen(parser, OREAD);
          409         if(finput == 0)
          410                 error("cannot open parser %s: %r", parser);
          411         warray("yyr1", levprd, nprod);
          412         aryfil(temp1, nprod, 0);
          413         PLOOP(1, i)
          414                 temp1[i] = prdptr[i+1]-prdptr[i]-2;
          415         warray("yyr2", temp1, nprod);
          416 
          417         aryfil(temp1, nstate, -1000);
          418         TLOOP(i)
          419                 for(j=tstates[i]; j!=0; j=mstates[j])
          420                         temp1[j] = i;
          421         NTLOOP(i)
          422                 for(j=ntstates[i]; j!=0; j=mstates[j])
          423                         temp1[j] = -i;
          424         warray("yychk", temp1, nstate);
          425         warray("yydef", defact, nstate);
          426 
          427         /* put out token translation tables */
          428         /* table 1 has 0-256 */
          429         aryfil(temp1, 256, 0);
          430         c = 0;
          431         TLOOP(i) {
          432                 j = tokset[i].value;
          433                 if(j >= 0 && j < 256) {
          434                         if(temp1[j]) {
          435                                 print("yacc bug -- cant have 2 different Ts with same value\n");
          436                                 print("        %s and %s\n", tokset[i].name, tokset[temp1[j]].name);
          437                                 nerrors++;
          438                         }
          439                         temp1[j] = i;
          440                         if(j > c)
          441                                 c = j;
          442                 }
          443         }
          444         warray("yytok1", temp1, c+1);
          445 
          446         /* table 2 has PRIVATE-PRIVATE+256 */
          447         aryfil(temp1, 256, 0);
          448         c = 0;
          449         TLOOP(i) {
          450                 j = tokset[i].value - PRIVATE;
          451                 if(j >= 0 && j < 256) {
          452                         if(temp1[j]) {
          453                                 print("yacc bug -- cant have 2 different Ts with same value\n");
          454                                 print("        %s and %s\n", tokset[i].name, tokset[temp1[j]].name);
          455                                 nerrors++;
          456                         }
          457                         temp1[j] = i;
          458                         if(j > c)
          459                                 c = j;
          460                 }
          461         }
          462         warray("yytok2", temp1, c+1);
          463 
          464         /* table 3 has everything else */
          465         Bprint(ftable, "static\tconst\tlong        yytok3[] =\n{\n");
          466         c = 0;
          467         TLOOP(i) {
          468                 j = tokset[i].value;
          469                 if(j >= 0 && j < 256)
          470                         continue;
          471                 if(j >= PRIVATE && j < 256+PRIVATE)
          472                         continue;
          473 
          474                 Bprint(ftable, "%4d,%4d,", j, i);
          475                 c++;
          476                 if(c%5 == 0)
          477                         Bprint(ftable, "\n");
          478         }
          479         Bprint(ftable, "%4d\n};\n", 0);
          480 
          481         /* copy parser text */
          482         while((c=Bgetrune(finput)) != Beof) {
          483                 if(c == '$') {
          484                         if((c = Bgetrune(finput)) != 'A')
          485                                 Bputrune(ftable, '$');
          486                         else { /* copy actions */
          487                                 faction = Bopen(actname, OREAD);
          488                                 if(faction == 0)
          489                                         error("cannot reopen action tempfile");
          490                                 while((c=Bgetrune(faction)) != Beof)
          491                                         Bputrune(ftable, c);
          492                                 Bterm(faction);
          493                                 ZAPFILE(actname);
          494                                 c = Bgetrune(finput);
          495                         }
          496                 }
          497                 Bputrune(ftable, c);
          498         }
          499         Bterm(ftable);
          500 }
          501 
          502 /*
          503  * copies string q into p, returning next free char ptr
          504  */
          505 char*
          506 chcopy(char* p, char* q)
          507 {
          508         int c;
          509 
          510         while(c = *q) {
          511                 if(c == '"')
          512                         *p++ = '\\';
          513                 *p++ = c;
          514                 q++;
          515         }
          516         *p = 0;
          517         return p;
          518 }
          519 
          520 /*
          521  * creates output string for item pointed to by pp
          522  */
          523 char*
          524 writem(int *pp)
          525 {
          526         int i,*p;
          527         static char sarr[ISIZE];
          528         char* q;
          529 
          530         for(p=pp; *p>0; p++)
          531                 ;
          532         p = prdptr[-*p];
          533         q = chcopy(sarr, nontrst[*p-NTBASE].name);
          534         q = chcopy(q, ": ");
          535         for(;;) {
          536                 *q = ' ';
          537                 p++;
          538                 if(p == pp)
          539                         *q = '.';
          540                 q++;
          541                 *q = '\0';
          542                 i = *p;
          543                 if(i <= 0)
          544                         break;
          545                 q = chcopy(q, symnam(i));
          546                 if(q > &sarr[ISIZE-30])
          547                         error("item too big");
          548         }
          549 
          550         /* an item calling for a reduction */
          551         i = *pp;
          552         if(i < 0 ) {
          553                 q = chcopy(q, "    (");
          554                 sprint(q, "%d)", -i);
          555         }
          556         return sarr;
          557 }
          558 
          559 /*
          560  * return a pointer to the name of symbol i
          561  */
          562 char*
          563 symnam(int i)
          564 {
          565         char* cp;
          566 
          567         cp = (i >= NTBASE)? nontrst[i-NTBASE].name: tokset[i].name;
          568         if(*cp == ' ')
          569                 cp++;
          570         return cp;
          571 }
          572 
          573 /*
          574  * output the summary on y.output
          575  */
          576 void
          577 summary(void)
          578 {
          579 
          580         if(foutput != 0) {
          581                 Bprint(foutput, "\n%d/%d terminals, %d/%d nonterminals\n",
          582                         ntokens, NTERMS, nnonter, NNONTERM);
          583                 Bprint(foutput, "%d/%d grammar rules, %d/%d states\n",
          584                         nprod, NPROD, nstate, NSTATES);
          585                 Bprint(foutput, "%d shift/reduce, %d reduce/reduce conflicts reported\n",
          586                         zzsrconf, zzrrconf);
          587                 Bprint(foutput, "%d/%d working sets used\n",
          588                         (int)(zzcwp-wsets), WSETSIZE);
          589                 Bprint(foutput, "memory: states,etc. %d/%d, parser %d/%d\n",
          590                         (int)(zzmemsz-mem0), MEMSIZE, (int)(memp-amem), ACTSIZE);
          591                 Bprint(foutput, "%d/%d distinct lookahead sets\n", nlset, LSETSIZE);
          592                 Bprint(foutput, "%d extra closures\n", zzclose - 2*nstate);
          593                 Bprint(foutput, "%d shift entries, %d exceptions\n", zzacent, zzexcp);
          594                 Bprint(foutput, "%d goto entries\n", zzgoent);
          595                 Bprint(foutput, "%d entries saved by goto default\n", zzgobest);
          596         }
          597         if(zzsrconf != 0 || zzrrconf != 0) {
          598                 print("\nconflicts: ");
          599                 if(zzsrconf)
          600                         print("%d shift/reduce", zzsrconf);
          601                 if(zzsrconf && zzrrconf)
          602                         print(", ");
          603                 if(zzrrconf)
          604                         print("%d reduce/reduce", zzrrconf);
          605                 print("\n");
          606         }
          607         if(ftemp != 0) {
          608                 Bterm(ftemp);
          609                 ftemp = 0;
          610         }
          611         if(fdefine != 0) {
          612                 Bterm(fdefine);
          613                 fdefine = 0;
          614         }
          615 }
          616 
          617 /*
          618  * write out error comment -- NEEDS WORK
          619  */
          620 void
          621 error(char *s, ...)
          622 {
          623         va_list arg;
          624 
          625         nerrors++;
          626         fprint(2, "\n fatal error:");
          627         va_start(arg, s);
          628         vfprint(2, s, arg);
          629         va_end(arg);
          630         fprint(2, ", %s:%d\n", infile, lineno);
          631         if(!fatfl)
          632                 return;
          633         summary();
          634         cleantmp();
          635         exits("error");
          636 }
          637 
          638 /*
          639  * set elements 0 through n-1 to c
          640  */
          641 void
          642 aryfil(int *v, int n, int c)
          643 {
          644         int i;
          645 
          646         for(i=0; i<n; i++)
          647                 v[i] = c;
          648 }
          649 
          650 /*
          651  * set a to the union of a and b
          652  * return 1 if b is not a subset of a, 0 otherwise
          653  */
          654 int
          655 setunion(int *a, int *b)
          656 {
          657         int i, x, sub;
          658 
          659         sub = 0;
          660         SETLOOP(i) {
          661                 x = *a;
          662                 *a |= *b;
          663                 if(*a != x)
          664                         sub = 1;
          665                 a++;
          666                 b++;
          667         }
          668         return sub;
          669 }
          670 
          671 void
          672 prlook(Lkset* p)
          673 {
          674         int j, *pp;
          675 
          676         pp = p->lset;
          677         if(pp == 0)
          678                 Bprint(foutput, "\tNULL");
          679         else {
          680                 Bprint(foutput, " { ");
          681                 TLOOP(j)
          682                         if(BIT(pp,j))
          683                                 Bprint(foutput, "%s ", symnam(j));
          684                 Bprint(foutput, "}");
          685         }
          686 }
          687 
          688 /*
          689  * compute an array with the beginnings of  productions yielding given nonterminals
          690  * The array pres points to these lists
          691  * the array pyield has the lists: the total size is only NPROD+1
          692  */
          693 void
          694 cpres(void)
          695 {
          696         int c, j, i, **pmem;
          697         static int *pyield[NPROD];
          698 
          699         pmem = pyield;
          700         NTLOOP(i) {
          701                 c = i+NTBASE;
          702                 pres[i] = pmem;
          703                 fatfl = 0;          /* make undefined  symbols  nonfatal */
          704                 PLOOP(0, j)
          705                         if(*prdptr[j] == c)
          706                                 *pmem++ =  prdptr[j]+1;
          707                 if(pres[i] == pmem)
          708                         error("nonterminal %s not defined!", nontrst[i].name);
          709         }
          710         pres[i] = pmem;
          711         fatfl = 1;
          712         if(nerrors) {
          713                 summary();
          714                 cleantmp();
          715                 exits("error");
          716         }
          717         if(pmem != &pyield[nprod])
          718                 error("internal Yacc error: pyield %d", pmem-&pyield[nprod]);
          719 }
          720 
          721 /*
          722  * compute an array with the first of nonterminals
          723  */
          724 void
          725 cpfir(void)
          726 {
          727         int *p, **s, i, **t, ch, changes;
          728 
          729         zzcwp = &wsets[nnonter];
          730         NTLOOP(i) {
          731                 aryfil(wsets[i].ws.lset, tbitset, 0);
          732                 t = pres[i+1];
          733                 /* initially fill the sets */
          734                 for(s=pres[i]; s<t; ++s)
          735                         for(p = *s; (ch = *p) > 0; ++p) {
          736                                 if(ch < NTBASE) {
          737                                         SETBIT(wsets[i].ws.lset, ch);
          738                                         break;
          739                                 }
          740                                 if(!pempty[ch-NTBASE])
          741                                         break;
          742                         }
          743         }
          744 
          745         /* now, reflect transitivity */
          746         changes = 1;
          747         while(changes) {
          748                 changes = 0;
          749                 NTLOOP(i) {
          750                         t = pres[i+1];
          751                         for(s = pres[i]; s < t; ++s)
          752                                 for(p = *s; (ch = (*p-NTBASE)) >= 0; ++p) {
          753                                         changes |= setunion(wsets[i].ws.lset, wsets[ch].ws.lset);
          754                                         if(!pempty[ch])
          755                                                 break;
          756                                 }
          757                 }
          758         }
          759 
          760         NTLOOP(i)
          761                 pfirst[i] = flset(&wsets[i].ws);
          762         if(!indebug)
          763                 return;
          764         if(foutput != 0)
          765                 NTLOOP(i) {
          766                         Bprint(foutput, "\n%s: ", nontrst[i].name);
          767                         prlook(pfirst[i]);
          768                         Bprint(foutput, " %d\n", pempty[i]);
          769                 }
          770 }
          771 
          772 /*
          773  * sorts last state,and sees if it equals earlier ones. returns state number
          774  */
          775 int
          776 state(int c)
          777 {
          778         Item *p1, *p2, *k, *l, *q1, *q2;
          779         int size1, size2, i;
          780 
          781         p1 = pstate[nstate];
          782         p2 = pstate[nstate+1];
          783         if(p1 == p2)
          784                 return 0;        /* null state */
          785         /* sort the items */
          786         for(k = p2-1; k > p1; k--)        /* make k the biggest */
          787                 for(l = k-1; l >= p1; --l)
          788                         if(l->pitem > k->pitem) {
          789                                 int *s;
          790                                 Lkset *ss;
          791 
          792                                 s = k->pitem;
          793                                 k->pitem = l->pitem;
          794                                 l->pitem = s;
          795                                 ss = k->look;
          796                                 k->look = l->look;
          797                                 l->look = ss;
          798                         }
          799         size1 = p2 - p1;        /* size of state */
          800 
          801         for(i = (c>=NTBASE)? ntstates[c-NTBASE]: tstates[c]; i != 0; i = mstates[i]) {
          802                 /* get ith state */
          803                 q1 = pstate[i];
          804                 q2 = pstate[i+1];
          805                 size2 = q2 - q1;
          806                 if(size1 != size2)
          807                         continue;
          808                 k = p1;
          809                 for(l = q1; l < q2; l++) {
          810                         if(l->pitem != k->pitem)
          811                                 break;
          812                         k++;
          813                 }
          814                 if(l != q2)
          815                         continue;
          816                 /* found it */
          817                 pstate[nstate+1] = pstate[nstate];        /* delete last state */
          818                 /* fix up lookaheads */
          819                 if(nolook)
          820                         return i;
          821                 for(l = q1, k = p1; l < q2; ++l, ++k ) {
          822                         int s;
          823 
          824                         SETLOOP(s)
          825                                 clset.lset[s] = l->look->lset[s];
          826                         if(setunion(clset.lset, k->look->lset)) {
          827                                 tystate[i] = MUSTDO;
          828                                 /* register the new set */
          829                                 l->look = flset( &clset );
          830                         }
          831                 }
          832                 return i;
          833         }
          834         /* state is new */
          835         if(nolook)
          836                 error("yacc state/nolook error");
          837         pstate[nstate+2] = p2;
          838         if(nstate+1 >= NSTATES)
          839                 error("too many states");
          840         if(c >= NTBASE) {
          841                 mstates[nstate] = ntstates[c-NTBASE];
          842                 ntstates[c-NTBASE] = nstate;
          843         } else {
          844                 mstates[nstate] = tstates[c];
          845                 tstates[c] = nstate;
          846         }
          847         tystate[nstate] = MUSTDO;
          848         return nstate++;
          849 }
          850 
          851 void
          852 putitem(int *ptr, Lkset *lptr)
          853 {
          854         Item *j;
          855 
          856         if(pidebug && foutput != 0)
          857                 Bprint(foutput, "putitem(%s), state %d\n", writem(ptr), nstate);
          858         j = pstate[nstate+1];
          859         j->pitem = ptr;
          860         if(!nolook)
          861                 j->look = flset(lptr);
          862         pstate[nstate+1] = ++j;
          863         if((int*)j > zzmemsz) {
          864                 zzmemsz = (int*)j;
          865                 if(zzmemsz >=  &mem0[MEMSIZE])
          866                         error("out of state space");
          867         }
          868 }
          869 
          870 /*
          871  * mark nonterminals which derive the empty string
          872  * also, look for nonterminals which don't derive any token strings
          873  */
          874 void
          875 cempty(void)
          876 {
          877 
          878         int i, *p;
          879 
          880         /* first, use the array pempty to detect productions that can never be reduced */
          881         /* set pempty to WHONOWS */
          882         aryfil(pempty, nnonter+1, WHOKNOWS);
          883 
          884         /* now, look at productions, marking nonterminals which derive something */
          885 more:
          886         PLOOP(0, i) {
          887                 if(pempty[*prdptr[i] - NTBASE])
          888                         continue;
          889                 for(p = prdptr[i]+1; *p >= 0; ++p)
          890                         if(*p >= NTBASE && pempty[*p-NTBASE] == WHOKNOWS)
          891                                 break;
          892                 /* production can be derived */
          893                 if(*p < 0) {
          894                         pempty[*prdptr[i]-NTBASE] = OK;
          895                         goto more;
          896                 }
          897         }
          898 
          899         /* now, look at the nonterminals, to see if they are all OK */
          900         NTLOOP(i) {
          901                 /* the added production rises or falls as the start symbol ... */
          902                 if(i == 0)
          903                         continue;
          904                 if(pempty[i] != OK) {
          905                         fatfl = 0;
          906                         error("nonterminal %s never derives any token string", nontrst[i].name);
          907                 }
          908         }
          909 
          910         if(nerrors) {
          911                 summary();
          912                 cleantmp();
          913                 exits("error");
          914         }
          915 
          916         /* now, compute the pempty array, to see which nonterminals derive the empty string */
          917         /* set pempty to WHOKNOWS */
          918         aryfil( pempty, nnonter+1, WHOKNOWS);
          919 
          920         /* loop as long as we keep finding empty nonterminals */
          921 
          922 again:
          923         PLOOP(1, i) {
          924                 /* not known to be empty */
          925                 if(pempty[*prdptr[i]-NTBASE] == WHOKNOWS) {
          926                         for(p = prdptr[i]+1; *p >= NTBASE && pempty[*p-NTBASE] == EMPTY ; ++p)
          927                                 ;
          928                         /* we have a nontrivially empty nonterminal */
          929                         if(*p < 0) {
          930                                 pempty[*prdptr[i]-NTBASE] = EMPTY;
          931                                 /* got one ... try for another */
          932                                 goto again;
          933                         }
          934                 }
          935         }
          936 }
          937 
          938 /*
          939  * generate the states
          940  */
          941 void
          942 stagen(void)
          943 {
          944 
          945         int c, i, j, more;
          946         Wset *p, *q;
          947 
          948         /* initialize */
          949         nstate = 0;
          950 
          951         /* THIS IS FUNNY from the standpoint of portability
          952          * it represents the magic moment when the mem0 array, which has
          953          * been holding the productions, starts to hold item pointers, of a
          954          * different type...
          955          * someday, alloc should be used to allocate all this stuff... for now, we
          956          * accept that if pointers don't fit in integers, there is a problem...
          957          */
          958 
          959         pstate[0] = pstate[1] = (Item*)mem;
          960         aryfil(clset.lset, tbitset, 0);
          961         putitem(prdptr[0]+1, &clset);
          962         tystate[0] = MUSTDO;
          963         nstate = 1;
          964         pstate[2] = pstate[1];
          965 
          966         aryfil(amem, ACTSIZE, 0);
          967 
          968         /* now, the main state generation loop */
          969         for(more=1; more;) {
          970                 more = 0;
          971                 SLOOP(i) {
          972                         if(tystate[i] != MUSTDO)
          973                                 continue;
          974                         tystate[i] = DONE;
          975                         aryfil(temp1, nnonter+1, 0);
          976                         /* take state i, close it, and do gotos */
          977                         closure(i);
          978                         /* generate goto's */
          979                         WSLOOP(wsets, p) {
          980                                 if(p->flag)
          981                                         continue;
          982                                 p->flag = 1;
          983                                 c = *(p->pitem);
          984                                 if(c <= 1) {
          985                                         if(pstate[i+1]-pstate[i] <= p-wsets)
          986                                                 tystate[i] = MUSTLOOKAHEAD;
          987                                         continue;
          988                                 }
          989                                 /* do a goto on c */
          990                                 WSLOOP(p, q)
          991                                         /* this item contributes to the goto */
          992                                         if(c == *(q->pitem)) {
          993                                                 putitem(q->pitem+1, &q->ws);
          994                                                 q->flag = 1;
          995                                         }
          996                                 if(c < NTBASE)
          997                                         state(c);        /* register new state */
          998                                 else
          999                                         temp1[c-NTBASE] = state(c);
         1000                         }
         1001                         if(gsdebug && foutput != 0) {
         1002                                 Bprint(foutput, "%d: ", i);
         1003                                 NTLOOP(j)
         1004                                         if(temp1[j])
         1005                                                 Bprint(foutput, "%s %d, ",
         1006                                                 nontrst[j].name, temp1[j]);
         1007                                 Bprint(foutput, "\n");
         1008                         }
         1009                         indgo[i] = apack(&temp1[1], nnonter-1) - 1;
         1010                         /* do some more */
         1011                         more = 1;
         1012                 }
         1013         }
         1014 }
         1015 
         1016 /*
         1017  * generate the closure of state i
         1018  */
         1019 void
         1020 closure(int i)
         1021 {
         1022 
         1023         Wset *u, *v;
         1024         Item *p, *q;
         1025         int c, ch, work, k, *pi, **s, **t;
         1026 
         1027         zzclose++;
         1028 
         1029         /* first, copy kernel of state i to wsets */
         1030         cwp = wsets;
         1031         ITMLOOP(i, p, q) {
         1032                 cwp->pitem = p->pitem;
         1033                 cwp->flag = 1;                        /* this item must get closed */
         1034                 SETLOOP(k)
         1035                         cwp->ws.lset[k] = p->look->lset[k];
         1036                 WSBUMP(cwp);
         1037         }
         1038 
         1039         /* now, go through the loop, closing each item */
         1040         work = 1;
         1041         while(work) {
         1042                 work = 0;
         1043                 WSLOOP(wsets, u) {
         1044                         if(u->flag == 0)
         1045                                 continue;
         1046                         /* dot is before c */
         1047                         c = *(u->pitem);
         1048                         if(c < NTBASE) {
         1049                                 u->flag = 0;
         1050                                 /* only interesting case is where . is before nonterminal */
         1051                                 continue;
         1052                         }
         1053 
         1054                         /* compute the lookahead */
         1055                         aryfil(clset.lset, tbitset, 0);
         1056 
         1057                         /* find items involving c */
         1058                         WSLOOP(u, v)
         1059                                 if(v->flag == 1 && *(pi=v->pitem) == c) {
         1060                                         v->flag = 0;
         1061                                         if(nolook)
         1062                                                 continue;
         1063                                         while((ch = *++pi) > 0) {
         1064                                                 /* terminal symbol */
         1065                                                 if(ch < NTBASE) {
         1066                                                         SETBIT(clset.lset, ch);
         1067                                                         break;
         1068                                                 }
         1069                                                 /* nonterminal symbol */
         1070                                                 setunion(clset.lset, pfirst[ch-NTBASE]->lset);
         1071                                                 if(!pempty[ch-NTBASE])
         1072                                                         break;
         1073                                         }
         1074                                         if(ch <= 0)
         1075                                                 setunion(clset.lset, v->ws.lset);
         1076                                 }
         1077 
         1078                         /*
         1079                          * now loop over productions derived from c
         1080                          * c is now nonterminal number
         1081                          */
         1082                         c -= NTBASE;
         1083                         t = pres[c+1];
         1084                         for(s = pres[c]; s < t; ++s) {
         1085                                 /*
         1086                                  * put these items into the closure
         1087                                  * is the item there
         1088                                  */
         1089                                 WSLOOP(wsets, v)
         1090                                         /* yes, it is there */
         1091                                         if(v->pitem == *s) {
         1092                                                 if(nolook)
         1093                                                         goto nexts;
         1094                                                 if(setunion(v->ws.lset, clset.lset))
         1095                                                         v->flag = work = 1;
         1096                                                 goto nexts;
         1097                                         }
         1098 
         1099                                 /*  not there; make a new entry */
         1100                                 if(cwp-wsets+1 >= WSETSIZE)
         1101                                         error( "working set overflow");
         1102                                 cwp->pitem = *s;
         1103                                 cwp->flag = 1;
         1104                                 if(!nolook) {
         1105                                         work = 1;
         1106                                         SETLOOP(k) cwp->ws.lset[k] = clset.lset[k];
         1107                                 }
         1108                                 WSBUMP(cwp);
         1109 
         1110                         nexts:;
         1111                         }
         1112                 }
         1113         }
         1114 
         1115         /* have computed closure; flags are reset; return */
         1116         if(cwp > zzcwp)
         1117                 zzcwp = cwp;
         1118         if(cldebug && foutput != 0) {
         1119                 Bprint(foutput, "\nState %d, nolook = %d\n", i, nolook);
         1120                 WSLOOP(wsets, u) {
         1121                         if(u->flag)
         1122                                 Bprint(foutput, "flag set!\n");
         1123                         u->flag = 0;
         1124                         Bprint(foutput, "\t%s", writem(u->pitem));
         1125                         prlook(&u->ws);
         1126                         Bprint(foutput, "\n");
         1127                 }
         1128         }
         1129 }
         1130 
         1131 /*
         1132  * decide if the lookahead set pointed to by p is known
         1133  * return pointer to a perminent location for the set
         1134  */
         1135 Lkset*
         1136 flset(Lkset *p)
         1137 {
         1138         Lkset *q;
         1139         int *u, *v, *w, j;
         1140 
         1141         for(q = &lkst[nlset]; q-- > lkst;) {
         1142                 u = p->lset;
         1143                 v = q->lset;
         1144                 w = &v[tbitset];
         1145                 while(v < w)
         1146                         if(*u++ != *v++)
         1147                                 goto more;
         1148                 /* we have matched */
         1149                 return q;
         1150         more:;
         1151         }
         1152         /* add a new one */
         1153         q = &lkst[nlset++];
         1154         if(nlset >= LSETSIZE)
         1155                 error("too many lookahead sets");
         1156         SETLOOP(j)
         1157                 q->lset[j] = p->lset[j];
         1158         return q;
         1159 }
         1160 
         1161 void
         1162 cleantmp(void)
         1163 {
         1164         ZAPFILE(actname);
         1165         ZAPFILE(tempname);
         1166 }
         1167 
         1168 void
         1169 intr(void)
         1170 {
         1171         cleantmp();
         1172         exits("interrupted");
         1173 }
         1174 
         1175 void
         1176 setup(int argc, char *argv[])
         1177 {
         1178         long c, t;
         1179         int i, j, fd, lev, ty, ytab, *p;
         1180         int vflag, dflag, stem;
         1181         char actnm[8], *stemc, *s, dirbuf[128];
         1182         Biobuf *fout;
         1183 
         1184         ytab = 0;
         1185         vflag = 0;
         1186         dflag = 0;
         1187         stem = 0;
         1188         stemc = "y";
         1189         foutput = 0;
         1190         fdefine = 0;
         1191         fdebug = 0;
         1192         ARGBEGIN{
         1193         case 'v':
         1194         case 'V':
         1195                 vflag++;
         1196                 break;
         1197         case 'D':
         1198                 yydebug = ARGF();
         1199                 break;
         1200         case 'a':
         1201                 yyarg = 1;
         1202                 break;
         1203         case 'd':
         1204                 dflag++;
         1205                 break;
         1206         case 'l':
         1207                 yyline = 0;
         1208                 break;
         1209         case 'o':
         1210                 ytab++;
         1211                 ytabc = ARGF();
         1212                 break;
         1213         case 's':
         1214                 stem++;
         1215                 stemc = ARGF();
         1216                 break;
         1217         case 'S':
         1218                 parser = PARSERS;
         1219                 break;
         1220         default:
         1221                 error("illegal option: %c", ARGC());
         1222         }ARGEND
         1223         openup(stemc, dflag, vflag, ytab, ytabc);
         1224         fout = dflag?fdefine:ftable;
         1225         if(yyarg){
         1226                 Bprint(ftable, "#define\tYYARG\t1\n\n");
         1227         }
         1228         if((fd = mkstemp(ttempname)) >= 0){
         1229                 tempname = ttempname;
         1230                 ftemp = Bfdopen(fd, OWRITE);
         1231         }
         1232         if((fd = mkstemp(tactname)) >= 0){
         1233                 actname = tactname;
         1234                 faction = Bfdopen(fd, OWRITE);
         1235         }
         1236         if(ftemp == 0 || faction == 0)
         1237                 error("cannot open temp file");
         1238         if(argc < 1)
         1239                 error("no input file");
         1240         infile = argv[0];
         1241         if(infile[0] != '/' && getwd(dirbuf, sizeof dirbuf)!=nil){
         1242                 i = strlen(infile)+1+strlen(dirbuf)+1+10;
         1243                 s = malloc(i);
         1244                 if(s != nil){
         1245                         snprint(s, i, "%s/%s", dirbuf, infile);
         1246                         cleanname(s);
         1247                         infile = s;
         1248                 }
         1249         }
         1250         finput = Bopen(infile, OREAD);
         1251         if(finput == 0)
         1252                 error("cannot open '%s'", argv[0]);
         1253         cnamp = cnames;
         1254 
         1255         defin(0, "$end");
         1256         extval = PRIVATE;        /* tokens start in unicode 'private use' */
         1257         defin(0, "error");
         1258         defin(1, "$accept");
         1259         defin(0, "$unk");
         1260         mem = mem0;
         1261         i = 0;
         1262 
         1263         for(t = gettok(); t != MARK && t != ENDFILE;)
         1264         switch(t) {
         1265         case ';':
         1266                 t = gettok();
         1267                 break;
         1268 
         1269         case START:
         1270                 if(gettok() != IDENTIFIER)
         1271                         error("bad %%start construction");
         1272                 start = chfind(1, tokname);
         1273                 t = gettok();
         1274                 continue;
         1275 
         1276         case TYPEDEF:
         1277                 if(gettok() != TYPENAME)
         1278                         error("bad syntax in %%type");
         1279                 ty = numbval;
         1280                 for(;;) {
         1281                         t = gettok();
         1282                         switch(t) {
         1283                         case IDENTIFIER:
         1284                                 if((t=chfind(1, tokname)) < NTBASE) {
         1285                                         j = TYPE(toklev[t]);
         1286                                         if(j != 0 && j != ty)
         1287                                                 error("type redeclaration of token %s",
         1288                                                         tokset[t].name);
         1289                                         else
         1290                                                 SETTYPE(toklev[t], ty);
         1291                                 } else {
         1292                                         j = nontrst[t-NTBASE].value;
         1293                                         if(j != 0 && j != ty)
         1294                                                 error("type redeclaration of nonterminal %s",
         1295                                                         nontrst[t-NTBASE].name );
         1296                                         else
         1297                                                 nontrst[t-NTBASE].value = ty;
         1298                                 }
         1299                         case ',':
         1300                                 continue;
         1301                         case ';':
         1302                                 t = gettok();
         1303                         default:
         1304                                 break;
         1305                         }
         1306                         break;
         1307                 }
         1308                 continue;
         1309 
         1310         case UNION:
         1311                 /* copy the union declaration to the output */
         1312                 cpyunion();
         1313                 t = gettok();
         1314                 continue;
         1315 
         1316         case LEFT:
         1317         case BINARY:
         1318         case RIGHT:
         1319                 i++;
         1320 
         1321         case TERM:
         1322                 /* nonzero means new prec. and assoc. */
         1323                 lev = t-TERM;
         1324                 ty = 0;
         1325 
         1326                 /* get identifiers so defined */
         1327                 t = gettok();
         1328 
         1329                 /* there is a type defined */
         1330                 if(t == TYPENAME) {
         1331                         ty = numbval;
         1332                         t = gettok();
         1333                 }
         1334                 for(;;) {
         1335                         switch(t) {
         1336                         case ',':
         1337                                 t = gettok();
         1338                                 continue;
         1339 
         1340                         case ';':
         1341                                 break;
         1342 
         1343                         case IDENTIFIER:
         1344                                 j = chfind(0, tokname);
         1345                                 if(j >= NTBASE)
         1346                                         error("%s defined earlier as nonterminal", tokname);
         1347                                 if(lev) {
         1348                                         if(ASSOC(toklev[j]))
         1349                                                 error("redeclaration of precedence of %s", tokname);
         1350                                         SETASC(toklev[j], lev);
         1351                                         SETPLEV(toklev[j], i);
         1352                                 }
         1353                                 if(ty) {
         1354                                         if(TYPE(toklev[j]))
         1355                                                 error("redeclaration of type of %s", tokname);
         1356                                         SETTYPE(toklev[j],ty);
         1357                                 }
         1358                                 t = gettok();
         1359                                 if(t == NUMBER) {
         1360                                         tokset[j].value = numbval;
         1361                                         if(j < ndefout && j > 3)
         1362                                                 error("please define type number of %s earlier",
         1363                                                         tokset[j].name);
         1364                                         t = gettok();
         1365                                 }
         1366                                 continue;
         1367                         }
         1368                         break;
         1369                 }
         1370                 continue;
         1371 
         1372         case LCURLY:
         1373                 defout(0);
         1374                 cpycode();
         1375                 t = gettok();
         1376                 continue;
         1377 
         1378         default:
         1379                 error("syntax error");
         1380         }
         1381         if(t == ENDFILE)
         1382                 error("unexpected EOF before %%");
         1383 
         1384         /* t is MARK */
         1385         if(!yyarg)
         1386                 Bprint(ftable, "extern        int        yyerrflag;\n");
         1387         Bprint(ftable, "#ifndef        YYMAXDEPTH\n");
         1388         Bprint(ftable, "#define        YYMAXDEPTH        150\n");
         1389         Bprint(ftable, "#endif\n" );
         1390         if(!ntypes) {
         1391                 Bprint(ftable, "#ifndef        YYSTYPE\n");
         1392                 Bprint(ftable, "#define        YYSTYPE        int\n");
         1393                 Bprint(ftable, "#endif\n");
         1394         }
         1395         if(!yyarg){
         1396                 Bprint(ftable, "YYSTYPE        yylval;\n");
         1397                 Bprint(ftable, "YYSTYPE        yyval;\n");
         1398         }else{
         1399                 if(dflag)
         1400                         Bprint(ftable, "#include \"%s.%s\"\n\n", stemc, FILED);
         1401                 Bprint(fout, "struct Yyarg {\n");
         1402                 Bprint(fout, "\tint\tyynerrs;\n");
         1403                 Bprint(fout, "\tint\tyyerrflag;\n");
         1404                 Bprint(fout, "\tvoid*\targ;\n");
         1405                 Bprint(fout, "\tYYSTYPE\tyyval;\n");
         1406                 Bprint(fout, "\tYYSTYPE\tyylval;\n");
         1407                 Bprint(fout, "};\n\n");
         1408         }
         1409         prdptr[0] = mem;
         1410 
         1411         /* added production */
         1412         *mem++ = NTBASE;
         1413 
         1414         /* if start is 0, we will overwrite with the lhs of the first rule */
         1415         *mem++ = start;
         1416         *mem++ = 1;
         1417         *mem++ = 0;
         1418         prdptr[1] = mem;
         1419         while((t=gettok()) == LCURLY)
         1420                 cpycode();
         1421         if(t != IDENTCOLON)
         1422                 error("bad syntax on first rule");
         1423 
         1424         if(!start)
         1425                 prdptr[0][1] = chfind(1, tokname);
         1426 
         1427         /* read rules */
         1428         while(t != MARK && t != ENDFILE) {
         1429                 /* process a rule */
         1430                 rlines[nprod] = lineno;
         1431                 if(t == '|')
         1432                         *mem++ = *prdptr[nprod-1];
         1433                 else
         1434                         if(t == IDENTCOLON) {
         1435                                 *mem = chfind(1, tokname);
         1436                                 if(*mem < NTBASE)
         1437                                         error("token illegal on LHS of grammar rule");
         1438                                 mem++;
         1439                         } else
         1440                                 error("illegal rule: missing semicolon or | ?");
         1441                 /* read rule body */
         1442                 t = gettok();
         1443 
         1444         more_rule:
         1445                 while(t == IDENTIFIER) {
         1446                         *mem = chfind(1, tokname);
         1447                         if(*mem < NTBASE)
         1448                                 levprd[nprod] = toklev[*mem];
         1449                         mem++;
         1450                         t = gettok();
         1451                 }
         1452                 if(t == PREC) {
         1453                         if(gettok() != IDENTIFIER)
         1454                                 error("illegal %%prec syntax");
         1455                         j = chfind(2, tokname);
         1456                         if(j >= NTBASE)
         1457                                 error("nonterminal %s illegal after %%prec",
         1458                                         nontrst[j-NTBASE].name);
         1459                         levprd[nprod] = toklev[j];
         1460                         t = gettok();
         1461                 }
         1462                 if(t == '=') {
         1463                         levprd[nprod] |= ACTFLAG;
         1464                         Bprint(faction, "\ncase %d:", nprod);
         1465                         cpyact(mem-prdptr[nprod]-1);
         1466                         Bprint(faction, " break;");
         1467                         if((t=gettok()) == IDENTIFIER) {
         1468 
         1469                                 /* action within rule... */
         1470                                 sprint(actnm, "$$%d", nprod);
         1471 
         1472                                 /* make it a nonterminal */
         1473                                 j = chfind(1, actnm);
         1474 
         1475                                 /*
         1476                                  * the current rule will become rule number nprod+1
         1477                                  * move the contents down, and make room for the null
         1478                                  */
         1479                                 for(p = mem; p >= prdptr[nprod]; --p)
         1480                                         p[2] = *p;
         1481                                 mem += 2;
         1482 
         1483                                 /* enter null production for action */
         1484                                 p = prdptr[nprod];
         1485                                 *p++ = j;
         1486                                 *p++ = -nprod;
         1487 
         1488                                 /* update the production information */
         1489                                 levprd[nprod+1] = levprd[nprod] & ~ACTFLAG;
         1490                                 levprd[nprod] = ACTFLAG;
         1491                                 if(++nprod >= NPROD)
         1492                                         error("more than %d rules", NPROD);
         1493                                 prdptr[nprod] = p;
         1494 
         1495                                 /* make the action appear in the original rule */
         1496                                 *mem++ = j;
         1497 
         1498                                 /* get some more of the rule */
         1499                                 goto more_rule;
         1500                         }
         1501                 }
         1502 
         1503                 while(t == ';')
         1504                         t = gettok();
         1505                 *mem++ = -nprod;
         1506 
         1507                 /* check that default action is reasonable */
         1508                 if(ntypes && !(levprd[nprod]&ACTFLAG) && nontrst[*prdptr[nprod]-NTBASE].value) {
         1509 
         1510                         /* no explicit action, LHS has value */
         1511                         int tempty;
         1512 
         1513                         tempty = prdptr[nprod][1];
         1514                         if(tempty < 0)
         1515                                 error("must return a value, since LHS has a type");
         1516                         else
         1517                                 if(tempty >= NTBASE)
         1518                                         tempty = nontrst[tempty-NTBASE].value;
         1519                                 else
         1520                                         tempty = TYPE(toklev[tempty]);
         1521                         if(tempty != nontrst[*prdptr[nprod]-NTBASE].value)
         1522                                 error("default action causes potential type clash");
         1523                 }
         1524                 nprod++;
         1525                 if(nprod >= NPROD)
         1526                         error("more than %d rules", NPROD);
         1527                 prdptr[nprod] = mem;
         1528                 levprd[nprod] = 0;
         1529         }
         1530 
         1531         /* end of all rules */
         1532         defout(1);
         1533 
         1534         finact();
         1535         if(t == MARK) {
         1536                 Bprint(ftable, "\n");
         1537                 if(yyline)
         1538                         Bprint(ftable, "#line\t%d\t\"%s\"\n", lineno, infile);
         1539                 while((c=Bgetrune(finput)) != Beof)
         1540                         Bputrune(ftable, c);
         1541         }
         1542         Bterm(finput);
         1543 }
         1544 
         1545 /*
         1546  * finish action routine
         1547  */
         1548 void
         1549 finact(void)
         1550 {
         1551 
         1552         Bterm(faction);
         1553         Bprint(ftable, "#define YYEOFCODE %d\n", 1);
         1554         Bprint(ftable, "#define YYERRCODE %d\n", 2);
         1555 }
         1556 
         1557 /*
         1558  * define s to be a terminal if t=0
         1559  * or a nonterminal if t=1
         1560  */
         1561 int
         1562 defin(int nt, char *s)
         1563 {
         1564         int val;
         1565         Rune rune;
         1566 
         1567         val = 0;
         1568         if(nt) {
         1569                 nnonter++;
         1570                 if(nnonter >= NNONTERM)
         1571                         error("too many nonterminals, limit %d",NNONTERM);
         1572                 nontrst[nnonter].name = cstash(s);
         1573                 return NTBASE + nnonter;
         1574         }
         1575 
         1576         /* must be a token */
         1577         ntokens++;
         1578         if(ntokens >= NTERMS)
         1579                 error("too many terminals, limit %d", NTERMS);
         1580         tokset[ntokens].name = cstash(s);
         1581 
         1582         /* establish value for token */
         1583         /* single character literal */
         1584         if(s[0] == ' ') {
         1585                 val = chartorune(&rune, &s[1]);
         1586                 if(s[val+1] == 0) {
         1587                         val = rune;
         1588                         goto out;
         1589                 }
         1590         }
         1591 
         1592         /* escape sequence */
         1593         if(s[0] == ' ' && s[1] == '\\') {
         1594                 if(s[3] == 0) {
         1595                         /* single character escape sequence */
         1596                         switch(s[2]) {
         1597                         case 'n':        val = '\n'; break;
         1598                         case 'r':        val = '\r'; break;
         1599                         case 'b':        val = '\b'; break;
         1600                         case 't':        val = '\t'; break;
         1601                         case 'f':        val = '\f'; break;
         1602                         case '\'':        val = '\''; break;
         1603                         case '"':        val = '"'; break;
         1604                         case '\\':        val = '\\'; break;
         1605                         default:        error("invalid escape");
         1606                         }
         1607                         goto out;
         1608                 }
         1609 
         1610                 /* \nnn sequence */
         1611                 if(s[2] >= '0' && s[2] <= '7') {
         1612                         if(s[3] < '0' ||
         1613                            s[3] > '7' ||
         1614                            s[4] < '0' ||
         1615                            s[4] > '7' ||
         1616                            s[5] != 0)
         1617                                 error("illegal \\nnn construction");
         1618                         val = 64*s[2] + 8*s[3] + s[4] - 73*'0';
         1619                         if(val == 0)
         1620                                 error("'\\000' is illegal");
         1621                         goto out;
         1622                 }
         1623                 error("unknown escape");
         1624         }
         1625         val = extval++;
         1626 
         1627 out:
         1628         tokset[ntokens].value = val;
         1629         toklev[ntokens] = 0;
         1630         return ntokens;
         1631 }
         1632 
         1633 /*
         1634  * write out the defines (at the end of the declaration section)
         1635  */
         1636 void
         1637 defout(int last)
         1638 {
         1639         int i, c;
         1640         char sar[NAMESIZE+10];
         1641 
         1642         for(i=ndefout; i<=ntokens; i++) {
         1643                 /* non-literals */
         1644                 c = tokset[i].name[0];
         1645                 if(c != ' ' && c != '$') {
         1646                         Bprint(ftable, "#define        %s        %d\n",
         1647                                 tokset[i].name, tokset[i].value);
         1648                         if(fdefine)
         1649                                 Bprint(fdefine, "#define\t%s\t%d\n",
         1650                                         tokset[i].name, tokset[i].value);
         1651                 }
         1652         }
         1653         ndefout = ntokens+1;
         1654         if(last && fdebug) {
         1655                 Bprint(fdebug, "static        char*        yytoknames[] =\n{\n");
         1656                 TLOOP(i) {
         1657                         if(tokset[i].name) {
         1658                                 chcopy(sar, tokset[i].name);
         1659                                 Bprint(fdebug, "\t\"%s\",\n", sar);
         1660                                 continue;
         1661                         }
         1662                         Bprint(fdebug, "\t0,\n");
         1663                 }
         1664                 Bprint(fdebug, "};\n");
         1665         }
         1666 }
         1667 
         1668 char*
         1669 cstash(char *s)
         1670 {
         1671         char *temp;
         1672 
         1673         temp = cnamp;
         1674         do {
         1675                 if(cnamp >= &cnames[cnamsz])
         1676                         error("too many characters in id's and literals");
         1677                 else
         1678                         *cnamp++ = *s;
         1679         } while(*s++);
         1680         return temp;
         1681 }
         1682 
         1683 long
         1684 gettok(void)
         1685 {
         1686         long c;
         1687         Rune rune;
         1688         int i, base, match, reserve;
         1689         static int peekline;
         1690 
         1691 begin:
         1692         reserve = 0;
         1693         lineno += peekline;
         1694         peekline = 0;
         1695         c = Bgetrune(finput);
         1696         while(c == ' ' || c == '\n' || c == '\t' || c == '\f') {
         1697                 if(c == '\n')
         1698                         lineno++;
         1699                 c = Bgetrune(finput);
         1700         }
         1701 
         1702         /* skip comment */
         1703         if(c == '/') {
         1704                 lineno += skipcom();
         1705                 goto begin;
         1706         }
         1707         switch(c) {
         1708         case Beof:
         1709                 return ENDFILE;
         1710 
         1711         case '{':
         1712                 Bungetrune(finput);
         1713                 return '=';
         1714 
         1715         case '<':
         1716                 /* get, and look up, a type name (union member name) */
         1717                 i = 0;
         1718                 while((c=Bgetrune(finput)) != '>' && c >= 0 && c != '\n') {
         1719                         rune = c;
         1720                         c = runetochar(&tokname[i], &rune);
         1721                         if(i < NAMESIZE)
         1722                                 i += c;
         1723                 }
         1724                 if(c != '>')
         1725                         error("unterminated < ... > clause");
         1726                 tokname[i] = 0;
         1727                 for(i=1; i<=ntypes; i++)
         1728                         if(!strcmp(typeset[i], tokname)) {
         1729                                 numbval = i;
         1730                                 return TYPENAME;
         1731                         }
         1732                 ntypes++;
         1733                 numbval = ntypes;
         1734                 typeset[numbval] = cstash(tokname);
         1735                 return TYPENAME;
         1736 
         1737         case '"':
         1738         case '\'':
         1739                 match = c;
         1740                 tokname[0] = ' ';
         1741                 i = 1;
         1742                 for(;;) {
         1743                         c = Bgetrune(finput);
         1744                         if(c == '\n' || c <= 0)
         1745                                 error("illegal or missing ' or \"" );
         1746                         if(c == '\\') {
         1747                                 tokname[i] = '\\';
         1748                                 if(i < NAMESIZE)
         1749                                         i++;
         1750                                 c = Bgetrune(finput);
         1751                         } else
         1752                                 if(c == match)
         1753                                         break;
         1754                         rune = c;
         1755                         c = runetochar(&tokname[i], &rune);
         1756                         if(i < NAMESIZE)
         1757                                 i += c;
         1758                 }
         1759                 break;
         1760 
         1761         case '%':
         1762         case '\\':
         1763                 switch(c = Bgetrune(finput)) {
         1764                 case '0':        return TERM;
         1765                 case '<':        return LEFT;
         1766                 case '2':        return BINARY;
         1767                 case '>':        return RIGHT;
         1768                 case '%':
         1769                 case '\\':        return MARK;
         1770                 case '=':        return PREC;
         1771                 case '{':        return LCURLY;
         1772                 default:        reserve = 1;
         1773                 }
         1774 
         1775         default:
         1776                 /* number */
         1777                 if(isdigit(c)) {
         1778                         numbval = c-'0';
         1779                         base = (c=='0')? 8: 10;
         1780                         for(c = Bgetrune(finput); isdigit(c); c = Bgetrune(finput))
         1781                                 numbval = numbval*base + (c-'0');
         1782                         Bungetrune(finput);
         1783                         return NUMBER;
         1784                 }
         1785                 if(islower(c) || isupper(c) || c=='_' || c=='.' || c=='$')  {
         1786                         i = 0;
         1787                         while(islower(c) || isupper(c) || isdigit(c) ||
         1788                             c == '-' || c=='_' || c=='.' || c=='$') {
         1789                                 if(reserve && isupper(c))
         1790                                         c += 'a'-'A';
         1791                                 rune = c;
         1792                                 c = runetochar(&tokname[i], &rune);
         1793                                 if(i < NAMESIZE)
         1794                                         i += c;
         1795                                 c = Bgetrune(finput);
         1796                         }
         1797                 } else
         1798                         return c;
         1799                 Bungetrune(finput);
         1800         }
         1801         tokname[i] = 0;
         1802 
         1803         /* find a reserved word */
         1804         if(reserve) {
         1805                 for(c=0; resrv[c].name; c++)
         1806                         if(strcmp(tokname, resrv[c].name) == 0)
         1807                                 return resrv[c].value;
         1808                 error("invalid escape, or illegal reserved word: %s", tokname);
         1809         }
         1810 
         1811         /* look ahead to distinguish IDENTIFIER from IDENTCOLON */
         1812         c = Bgetrune(finput);
         1813         while(c == ' ' || c == '\t'|| c == '\n' || c == '\f' || c == '/') {
         1814                 if(c == '\n')
         1815                         peekline++;
         1816                 /* look for comments */
         1817                 if(c == '/')
         1818                         peekline += skipcom();
         1819                 c = Bgetrune(finput);
         1820         }
         1821         if(c == ':')
         1822                 return IDENTCOLON;
         1823         Bungetrune(finput);
         1824         return IDENTIFIER;
         1825 }
         1826 
         1827 /*
         1828  * determine the type of a symbol
         1829  */
         1830 int
         1831 fdtype(int t)
         1832 {
         1833         int v;
         1834 
         1835         if(t >= NTBASE)
         1836                 v = nontrst[t-NTBASE].value;
         1837         else
         1838                 v = TYPE(toklev[t]);
         1839         if(v <= 0)
         1840                 error("must specify type for %s", (t>=NTBASE)?
         1841                         nontrst[t-NTBASE].name: tokset[t].name);
         1842         return v;
         1843 }
         1844 
         1845 int
         1846 chfind(int t, char *s)
         1847 {
         1848         int i;
         1849 
         1850         if(s[0] == ' ')
         1851                 t = 0;
         1852         TLOOP(i)
         1853                 if(!strcmp(s, tokset[i].name))
         1854                         return i;
         1855         NTLOOP(i)
         1856                 if(!strcmp(s, nontrst[i].name))
         1857                         return NTBASE+i;
         1858 
         1859         /* cannot find name */
         1860         if(t > 1)
         1861                 error("%s should have been defined earlier", s);
         1862         return defin(t, s);
         1863 }
         1864 
         1865 /*
         1866  * copy the union declaration to the output, and the define file if present
         1867  */
         1868 void
         1869 cpyunion(void)
         1870 {
         1871         long c;
         1872         int level;
         1873 
         1874         Bprint(ftable, "\n");
         1875         if(yyline)
         1876                 Bprint(ftable, "#line\t%d\t\"%s\"\n", lineno, infile);
         1877         Bprint(ftable, "typedef union ");
         1878         if(fdefine != 0)
         1879                 Bprint(fdefine, "\ntypedef union ");
         1880 
         1881         level = 0;
         1882         for(;;) {
         1883                 if((c=Bgetrune(finput)) == Beof)
         1884                         error("EOF encountered while processing %%union");
         1885                 Bputrune(ftable, c);
         1886                 if(fdefine != 0)
         1887                         Bputrune(fdefine, c);
         1888                 switch(c) {
         1889                 case '\n':
         1890                         lineno++;
         1891                         break;
         1892                 case '{':
         1893                         level++;
         1894                         break;
         1895                 case '}':
         1896                         level--;
         1897 
         1898                         /* we are finished copying */
         1899                         if(level == 0) {
         1900                                 Bprint(ftable, " YYSTYPE;\n");
         1901                                 if(fdefine != 0){
         1902                                         Bprint(fdefine, "\tYYSTYPE;\n");
         1903                                         if(!yyarg)
         1904                                                 Bprint(fdefine, "extern\tYYSTYPE\tyylval;\n");
         1905                                 }
         1906                                 return;
         1907                         }
         1908                 }
         1909         }
         1910 }
         1911 
         1912 /*
         1913  * copies code between \{ and \}
         1914  */
         1915 void
         1916 cpycode(void)
         1917 {
         1918         long c;
         1919 
         1920         c = Bgetrune(finput);
         1921         if(c == '\n') {
         1922                 c = Bgetrune(finput);
         1923                 lineno++;
         1924         }
         1925         Bprint(ftable, "\n");
         1926         if(yyline)
         1927                 Bprint(ftable, "#line\t%d\t\"%s\"\n", lineno, infile);
         1928         while(c != Beof) {
         1929                 if(c == '\\') {
         1930                         if((c=Bgetrune(finput)) == '}')
         1931                                 return;
         1932                         Bputc(ftable, '\\');
         1933                 }
         1934                 if(c == '%') {
         1935                         if((c=Bgetrune(finput)) == '}')
         1936                                 return;
         1937                         Bputc(ftable, '%');
         1938                 }
         1939                 Bputrune(ftable, c);
         1940                 if(c == '\n')
         1941                         lineno++;
         1942                 c = Bgetrune(finput);
         1943         }
         1944         error("eof before %%}");
         1945 }
         1946 
         1947 /*
         1948  * skip over comments
         1949  * skipcom is called after reading a '/'
         1950  */
         1951 int
         1952 skipcom(void)
         1953 {
         1954         long c;
         1955         int i;
         1956 
         1957         /* i is the number of lines skipped */
         1958         i = 0;
         1959         if(Bgetrune(finput) != '*')
         1960                 error("illegal comment");
         1961         c = Bgetrune(finput);
         1962         while(c != Beof) {
         1963                 while(c == '*')
         1964                         if((c=Bgetrune(finput)) == '/')
         1965                                 return i;
         1966                 if(c == '\n')
         1967                         i++;
         1968                 c = Bgetrune(finput);
         1969         }
         1970         error("EOF inside comment");
         1971         return 0;
         1972 }
         1973 
         1974 /*
         1975  * copy C action to the next ; or closing }
         1976  */
         1977 void
         1978 cpyact(int offset)
         1979 {
         1980         long c;
         1981         int brac, match, j, s, fnd, tok;
         1982 
         1983         Bprint(faction, "\n");
         1984         if(yyline)
         1985                 Bprint(faction, "#line\t%d\t\"%s\"\n", lineno, infile);
         1986         brac = 0;
         1987 
         1988 loop:
         1989         c = Bgetrune(finput);
         1990 swt:
         1991         switch(c) {
         1992         case ';':
         1993                 if(brac == 0) {
         1994                         Bputrune(faction, c);
         1995                         return;
         1996                 }
         1997                 goto lcopy;
         1998 
         1999         case '{':
         2000                 brac++;
         2001                 goto lcopy;
         2002 
         2003         case '$':
         2004                 s = 1;
         2005                 tok = -1;
         2006                 c = Bgetrune(finput);
         2007 
         2008                 /* type description */
         2009                 if(c == '<') {
         2010                         Bungetrune(finput);
         2011                         if(gettok() != TYPENAME)
         2012                                 error("bad syntax on $<ident> clause");
         2013                         tok = numbval;
         2014                         c = Bgetrune(finput);
         2015                 }
         2016                 if(c == '$') {
         2017                         Bprint(faction, "yyval");
         2018 
         2019                         /* put out the proper tag... */
         2020                         if(ntypes) {
         2021                                 if(tok < 0)
         2022                                         tok = fdtype(*prdptr[nprod]);
         2023                                 Bprint(faction, ".%s", typeset[tok]);
         2024                         }
         2025                         goto loop;
         2026                 }
         2027                 if(c == '-') {
         2028                         s = -s;
         2029                         c = Bgetrune(finput);
         2030                 }
         2031                 if(isdigit(c)) {
         2032                         j = 0;
         2033                         while(isdigit(c)) {
         2034                                 j = j*10 + (c-'0');
         2035                                 c = Bgetrune(finput);
         2036                         }
         2037                         Bungetrune(finput);
         2038                         j = j*s - offset;
         2039                         if(j > 0)
         2040                                 error("Illegal use of $%d", j+offset);
         2041 
         2042                 dollar:
         2043                         Bprint(faction, "yypt[-%d].yyv", -j);
         2044 
         2045                         /* put out the proper tag */
         2046                         if(ntypes) {
         2047                                 if(j+offset <= 0 && tok < 0)
         2048                                         error("must specify type of $%d", j+offset);
         2049                                 if(tok < 0)
         2050                                         tok = fdtype(prdptr[nprod][j+offset]);
         2051                                 Bprint(faction, ".%s", typeset[tok]);
         2052                         }
         2053                         goto loop;
         2054                 }
         2055                 if(isupper(c) || islower(c) || c == '_' || c == '.') {
         2056                         int tok; /* tok used oustide for type info */
         2057 
         2058                         /* look for $name */
         2059                         Bungetrune(finput);
         2060                         if(gettok() != IDENTIFIER)
         2061                                 error("$ must be followed by an identifier");
         2062                         tok = chfind(2, tokname);
         2063                         if((c = Bgetrune(finput)) != '#') {
         2064                                 Bungetrune(finput);
         2065                                 fnd = -1;
         2066                         } else
         2067                                 if(gettok() != NUMBER) {
         2068                                         error("# must be followed by number");
         2069                                         fnd = -1;
         2070                                 } else
         2071                                         fnd = numbval;
         2072                         for(j=1; j<=offset; ++j)
         2073                                 if(tok == prdptr[nprod][j]) {
         2074                                         if(--fnd <= 0) {
         2075                                                 j -= offset;
         2076                                                 goto dollar;
         2077                                         }
         2078                                 }
         2079                         error("$name or $name#number not found");
         2080                 }
         2081                 Bputc(faction, '$');
         2082                 if(s < 0 )
         2083                         Bputc(faction, '-');
         2084                 goto swt;
         2085 
         2086         case '}':
         2087                 brac--;
         2088                 if(brac)
         2089                         goto lcopy;
         2090                 Bputrune(faction, c);
         2091                 return;
         2092 
         2093         case '/':
         2094                 /* look for comments */
         2095                 Bputrune(faction, c);
         2096                 c = Bgetrune(finput);
         2097                 if(c != '*')
         2098                         goto swt;
         2099 
         2100                 /* it really is a comment */
         2101                 Bputrune(faction, c);
         2102                 c = Bgetrune(finput);
         2103                 while(c >= 0) {
         2104                         while(c == '*') {
         2105                                 Bputrune(faction, c);
         2106                                 if((c=Bgetrune(finput)) == '/')
         2107                                         goto lcopy;
         2108                         }
         2109                         Bputrune(faction, c);
         2110                         if(c == '\n')
         2111                                 lineno++;
         2112                         c = Bgetrune(finput);
         2113                 }
         2114                 error("EOF inside comment");
         2115 
         2116         case '\'':
         2117                 /* character constant */
         2118                 match = '\'';
         2119                 goto string;
         2120 
         2121         case '"':
         2122                 /* character string */
         2123                 match = '"';
         2124 
         2125         string:
         2126                 Bputrune(faction, c);
         2127                 while(c = Bgetrune(finput)) {
         2128                         if(c == '\\') {
         2129                                 Bputrune(faction, c);
         2130                                 c = Bgetrune(finput);
         2131                                 if(c == '\n')
         2132                                         lineno++;
         2133                         } else
         2134                                 if(c == match)
         2135                                         goto lcopy;
         2136                                 if(c == '\n')
         2137                                         error("newline in string or char. const.");
         2138                         Bputrune(faction, c);
         2139                 }
         2140                 error("EOF in string or character constant");
         2141 
         2142         case Beof:
         2143                 error("action does not terminate");
         2144 
         2145         case '\n':
         2146                 lineno++;
         2147                 goto lcopy;
         2148         }
         2149 
         2150 lcopy:
         2151         Bputrune(faction, c);
         2152         goto loop;
         2153 }
         2154 
         2155 void
         2156 openup(char *stem, int dflag, int vflag, int ytab, char *ytabc)
         2157 {
         2158         char buf[256];
         2159 
         2160         if(vflag) {
         2161                 sprint(buf, "%s.%s", stem, FILEU);
         2162                 foutput = Bopen(buf, OWRITE);
         2163                 if(foutput == 0)
         2164                         error("cannot open %s", buf);
         2165         }
         2166         if(yydebug) {
         2167                 sprint(buf, "%s.%s", stem, FILEDEBUG);
         2168                 if((fdebug = Bopen(buf, OWRITE)) == 0)
         2169                         error("can't open %s", buf);
         2170         }
         2171         if(dflag) {
         2172                 sprint(buf, "%s.%s", stem, FILED);
         2173                 fdefine = Bopen(buf, OWRITE);
         2174                 if(fdefine == 0)
         2175                         error("can't create %s", buf);
         2176         }
         2177         if(ytab == 0)
         2178                 sprint(buf, "%s.%s", stem, OFILE);
         2179         else
         2180                 strcpy(buf, ytabc);
         2181         ftable = Bopen(buf, OWRITE);
         2182         if(ftable == 0)
         2183                 error("cannot open table file %s", buf);
         2184 }
         2185 
         2186 /*
         2187  * print the output for the states
         2188  */
         2189 void
         2190 output(void)
         2191 {
         2192         int i, k, c;
         2193         Wset *u, *v;
         2194 
         2195         Bprint(ftable, "static\tconst\tshort        yyexca[] =\n{");
         2196         if(fdebug)
         2197                 Bprint(fdebug, "static\tconst\tchar*        yystates[] =\n{\n");
         2198 
         2199         /* output the stuff for state i */
         2200         SLOOP(i) {
         2201                 nolook = tystate[i]!=MUSTLOOKAHEAD;
         2202                 closure(i);
         2203 
         2204                 /* output actions */
         2205                 nolook = 1;
         2206                 aryfil(temp1, ntokens+nnonter+1, 0);
         2207                 WSLOOP(wsets, u) {
         2208                         c = *(u->pitem);
         2209                         if(c > 1 && c < NTBASE && temp1[c] == 0) {
         2210                                 WSLOOP(u, v)
         2211                                         if(c == *(v->pitem))
         2212                                                 putitem(v->pitem+1, (Lkset*)0);
         2213                                 temp1[c] = state(c);
         2214                         } else
         2215                                 if(c > NTBASE && temp1[(c -= NTBASE) + ntokens] == 0)
         2216                                         temp1[c+ntokens] = amem[indgo[i]+c];
         2217                 }
         2218                 if(i == 1)
         2219                         temp1[1] = ACCEPTCODE;
         2220 
         2221                 /* now, we have the shifts; look at the reductions */
         2222                 lastred = 0;
         2223                 WSLOOP(wsets, u) {
         2224                         c = *u->pitem;
         2225 
         2226                         /* reduction */
         2227                         if(c <= 0) {
         2228                                 lastred = -c;
         2229                                 TLOOP(k)
         2230                                         if(BIT(u->ws.lset, k)) {
         2231                                                 if(temp1[k] == 0)
         2232                                                         temp1[k] = c;
         2233                                                 else
         2234                                                 if(temp1[k] < 0) { /* reduce/reduce conflict */
         2235                                                         if(foutput)
         2236                                                                 Bprint(foutput,
         2237                                                                         "\n%d: reduce/reduce conflict"
         2238                                                                         " (red'ns %d and %d ) on %s",
         2239                                                                         i, -temp1[k], lastred,
         2240                                                                         symnam(k));
         2241                                                         if(-temp1[k] > lastred)
         2242                                                                 temp1[k] = -lastred;
         2243                                                         zzrrconf++;
         2244                                                 } else
         2245                                                         /* potential shift/reduce conflict */
         2246                                                         precftn( lastred, k, i );
         2247                                         }
         2248                                 }
         2249                 }
         2250                 wract(i);
         2251         }
         2252 
         2253         if(fdebug)
         2254                 Bprint(fdebug, "};\n");
         2255         Bprint(ftable, "};\n");
         2256         Bprint(ftable, "#define        YYNPROD        %d\n", nprod);
         2257         Bprint(ftable, "#define        YYPRIVATE %d\n", PRIVATE);
         2258         if(yydebug)
         2259                 Bprint(ftable, "#define        yydebug        %s\n", yydebug);
         2260 }
         2261 
         2262 /*
         2263  * pack state i from temp1 into amem
         2264  */
         2265 int
         2266 apack(int *p, int n)
         2267 {
         2268         int *pp, *qq, *rr, off, *q, *r;
         2269 
         2270         /* we don't need to worry about checking because
         2271          * we will only look at entries known to be there...
         2272          * eliminate leading and trailing 0's
         2273          */
         2274 
         2275         q = p+n;
         2276         for(pp = p, off = 0; *pp == 0 && pp <= q; ++pp, --off)
         2277                 ;
         2278          /* no actions */
         2279         if(pp > q)
         2280                 return 0;
         2281         p = pp;
         2282 
         2283         /* now, find a place for the elements from p to q, inclusive */
         2284         r = &amem[ACTSIZE-1];
         2285         for(rr = amem; rr <= r; rr++, off++) {
         2286                 for(qq = rr, pp = p; pp <= q; pp++, qq++)
         2287                         if(*pp != 0)
         2288                                 if(*pp != *qq && *qq != 0)
         2289                                         goto nextk;
         2290 
         2291                 /* we have found an acceptable k */
         2292                 if(pkdebug && foutput != 0)
         2293                         Bprint(foutput, "off = %d, k = %d\n", off, (int)(rr-amem));
         2294                 for(qq = rr, pp = p; pp <= q; pp++, qq++)
         2295                         if(*pp) {
         2296                                 if(qq > r)
         2297                                         error("action table overflow");
         2298                                 if(qq > memp)
         2299                                         memp = qq;
         2300                                 *qq = *pp;
         2301                         }
         2302                 if(pkdebug && foutput != 0)
         2303                         for(pp = amem; pp <= memp; pp += 10) {
         2304                                 Bprint(foutput, "\t");
         2305                                 for(qq = pp; qq <= pp+9; qq++)
         2306                                         Bprint(foutput, "%d ", *qq);
         2307                                 Bprint(foutput, "\n");
         2308                         }
         2309                 return(off);
         2310         nextk:;
         2311         }
         2312         error("no space in action table");
         2313         return 0;
         2314 }
         2315 
         2316 /*
         2317  * output the gotos for the nontermninals
         2318  */
         2319 void
         2320 go2out(void)
         2321 {
         2322         int i, j, k, best, count, cbest, times;
         2323 
         2324         /* mark begining of gotos */
         2325         Bprint(ftemp, "$\n");
         2326         for(i = 1; i <= nnonter; i++) {
         2327                 go2gen(i);
         2328 
         2329                 /* find the best one to make default */
         2330                 best = -1;
         2331                 times = 0;
         2332 
         2333                 /* is j the most frequent */
         2334                 for(j = 0; j <= nstate; j++) {
         2335                         if(tystate[j] == 0)
         2336                                 continue;
         2337                         if(tystate[j] == best)
         2338                                 continue;
         2339 
         2340                         /* is tystate[j] the most frequent */
         2341                         count = 0;
         2342                         cbest = tystate[j];
         2343                         for(k = j; k <= nstate; k++)
         2344                                 if(tystate[k] == cbest)
         2345                                         count++;
         2346                         if(count > times) {
         2347                                 best = cbest;
         2348                                 times = count;
         2349                         }
         2350                 }
         2351 
         2352                 /* best is now the default entry */
         2353                 zzgobest += times-1;
         2354                 for(j = 0; j <= nstate; j++)
         2355                         if(tystate[j] != 0 && tystate[j] != best) {
         2356                                 Bprint(ftemp, "%d,%d,", j, tystate[j]);
         2357                                 zzgoent++;
         2358                         }
         2359 
         2360                 /* now, the default */
         2361                 if(best == -1)
         2362                         best = 0;
         2363                 zzgoent++;
         2364                 Bprint(ftemp, "%d\n", best);
         2365         }
         2366 }
         2367 
         2368 /*
         2369  * output the gotos for nonterminal c
         2370  */
         2371 void
         2372 go2gen(int c)
         2373 {
         2374         int i, work, cc;
         2375         Item *p, *q;
         2376 
         2377 
         2378         /* first, find nonterminals with gotos on c */
         2379         aryfil(temp1, nnonter+1, 0);
         2380         temp1[c] = 1;
         2381         work = 1;
         2382         while(work) {
         2383                 work = 0;
         2384                 PLOOP(0, i)
         2385 
         2386                         /* cc is a nonterminal */
         2387                         if((cc=prdptr[i][1]-NTBASE) >= 0)
         2388                                 /* cc has a goto on c */
         2389                                 if(temp1[cc] != 0) {
         2390 
         2391                                         /* thus, the left side of production i does too */
         2392                                         cc = *prdptr[i]-NTBASE;
         2393                                         if(temp1[cc] == 0) {
         2394                                                   work = 1;
         2395                                                   temp1[cc] = 1;
         2396                                         }
         2397                                 }
         2398         }
         2399 
         2400         /* now, we have temp1[c] = 1 if a goto on c in closure of cc */
         2401         if(g2debug && foutput != 0) {
         2402                 Bprint(foutput, "%s: gotos on ", nontrst[c].name);
         2403                 NTLOOP(i)
         2404                         if(temp1[i])
         2405                                 Bprint(foutput, "%s ", nontrst[i].name);
         2406                 Bprint(foutput, "\n");
         2407         }
         2408 
         2409         /* now, go through and put gotos into tystate */
         2410         aryfil(tystate, nstate, 0);
         2411         SLOOP(i)
         2412                 ITMLOOP(i, p, q)
         2413                         if((cc = *p->pitem) >= NTBASE)
         2414                                 /* goto on c is possible */
         2415                                 if(temp1[cc-NTBASE]) {
         2416                                         tystate[i] = amem[indgo[i]+c];
         2417                                         break;
         2418                                 }
         2419 }
         2420 
         2421 /*
         2422  * decide a shift/reduce conflict by precedence.
         2423  * r is a rule number, t a token number
         2424  * the conflict is in state s
         2425  * temp1[t] is changed to reflect the action
         2426  */
         2427 void
         2428 precftn(int r, int t, int s)
         2429 {
         2430         int lp, lt, action;
         2431 
         2432         lp = levprd[r];
         2433         lt = toklev[t];
         2434         if(PLEVEL(lt) == 0 || PLEVEL(lp) == 0) {
         2435 
         2436                 /* conflict */
         2437                 if(foutput != 0)
         2438                         Bprint(foutput,
         2439                                 "\n%d: shift/reduce conflict (shift %d(%d), red'n %d(%d)) on %s",
         2440                                 s, temp1[t], PLEVEL(lt), r, PLEVEL(lp), symnam(t));
         2441                 zzsrconf++;
         2442                 return;
         2443         }
         2444         if(PLEVEL(lt) == PLEVEL(lp))
         2445                 action = ASSOC(lt);
         2446         else
         2447                 if(PLEVEL(lt) > PLEVEL(lp))
         2448                         action = RASC;  /* shift */
         2449                 else
         2450                         action = LASC;  /* reduce */
         2451         switch(action) {
         2452         case BASC:  /* error action */
         2453                 temp1[t] = ERRCODE;
         2454                 break;
         2455         case LASC:  /* reduce */
         2456                 temp1[t] = -r;
         2457                 break;
         2458         }
         2459 }
         2460 
         2461 /*
         2462  * output state i
         2463  * temp1 has the actions, lastred the default
         2464  */
         2465 void
         2466 wract(int i)
         2467 {
         2468         int p, p0, p1, ntimes, tred, count, j, flag;
         2469 
         2470         /* find the best choice for lastred */
         2471         lastred = 0;
         2472         ntimes = 0;
         2473         TLOOP(j) {
         2474                 if(temp1[j] >= 0)
         2475                         continue;
         2476                 if(temp1[j]+lastred == 0)
         2477                         continue;
         2478                 /* count the number of appearances of temp1[j] */
         2479                 count = 0;
         2480                 tred = -temp1[j];
         2481                 levprd[tred] |= REDFLAG;
         2482                 TLOOP(p)
         2483                         if(temp1[p]+tred == 0)
         2484                                 count++;
         2485                 if(count > ntimes) {
         2486                         lastred = tred;
         2487                         ntimes = count;
         2488                 }
         2489         }
         2490 
         2491         /*
         2492          * for error recovery, arrange that, if there is a shift on the
         2493          * error recovery token, `error', that the default be the error action
         2494          */
         2495         if(temp1[2] > 0)
         2496                 lastred = 0;
         2497 
         2498         /* clear out entries in temp1 which equal lastred */
         2499         TLOOP(p)
         2500                 if(temp1[p]+lastred == 0)
         2501                         temp1[p] = 0;
         2502 
         2503         wrstate(i);
         2504         defact[i] = lastred;
         2505         flag = 0;
         2506         TLOOP(p0)
         2507                 if((p1=temp1[p0]) != 0) {
         2508                         if(p1 < 0) {
         2509                                 p1 = -p1;
         2510                                 goto exc;
         2511                         }
         2512                         if(p1 == ACCEPTCODE) {
         2513                                 p1 = -1;
         2514                                 goto exc;
         2515                         }
         2516                         if(p1 == ERRCODE) {
         2517                                 p1 = 0;
         2518                         exc:
         2519                                 if(flag++ == 0)
         2520                                         Bprint(ftable, "-1, %d,\n", i);
         2521                                 Bprint(ftable, "\t%d, %d,\n", p0, p1);
         2522                                 zzexcp++;
         2523                                 continue;
         2524                         }
         2525                         Bprint(ftemp, "%d,%d,", p0, p1);
         2526                         zzacent++;
         2527                 }
         2528         if(flag) {
         2529                 defact[i] = -2;
         2530                 Bprint(ftable, "\t-2, %d,\n", lastred);
         2531         }
         2532         Bprint(ftemp, "\n");
         2533 }
         2534 
         2535 /*
         2536  * writes state i
         2537  */
         2538 void
         2539 wrstate(int i)
         2540 {
         2541         int j0, j1;
         2542         Item *pp, *qq;
         2543         Wset *u;
         2544 
         2545         if(fdebug) {
         2546                 if(lastred) {
         2547                         Bprint(fdebug, "        0, /*%d*/\n", i);
         2548                 } else {
         2549                         Bprint(fdebug, "        \"");
         2550                         ITMLOOP(i, pp, qq)
         2551                                 Bprint(fdebug, "%s\\n", writem(pp->pitem));
         2552                         if(tystate[i] == MUSTLOOKAHEAD)
         2553                                 WSLOOP(wsets + (pstate[i+1] - pstate[i]), u)
         2554                                         if(*u->pitem < 0)
         2555                                                 Bprint(fdebug, "%s\\n", writem(u->pitem));
         2556                         Bprint(fdebug, "\", /*%d*/\n", i);
         2557                 }
         2558         }
         2559         if(foutput == 0)
         2560                 return;
         2561         Bprint(foutput, "\nstate %d\n", i);
         2562         ITMLOOP(i, pp, qq)
         2563                 Bprint(foutput, "\t%s\n", writem(pp->pitem));
         2564         if(tystate[i] == MUSTLOOKAHEAD)
         2565                 /* print out empty productions in closure */
         2566                 WSLOOP(wsets+(pstate[i+1]-pstate[i]), u)
         2567                         if(*u->pitem < 0)
         2568                                 Bprint(foutput, "\t%s\n", writem(u->pitem));
         2569 
         2570         /* check for state equal to another */
         2571         TLOOP(j0)
         2572                 if((j1=temp1[j0]) != 0) {
         2573                         Bprint(foutput, "\n\t%s  ", symnam(j0));
         2574                         /* shift, error, or accept */
         2575                         if(j1 > 0) {
         2576                                 if(j1 == ACCEPTCODE)
         2577                                         Bprint(foutput,  "accept");
         2578                                 else
         2579                                         if(j1 == ERRCODE)
         2580                                                 Bprint(foutput, "error");
         2581                                         else
         2582                                                 Bprint(foutput, "shift %d", j1);
         2583                         } else
         2584                                 Bprint(foutput, "reduce %d (src line %d)", -j1, rlines[-j1]);
         2585                 }
         2586 
         2587         /* output the final production */
         2588         if(lastred)
         2589                 Bprint(foutput, "\n\t.  reduce %d (src line %d)\n\n",
         2590                         lastred, rlines[lastred]);
         2591         else
         2592                 Bprint(foutput, "\n\t.  error\n\n");
         2593 
         2594         /* now, output nonterminal actions */
         2595         j1 = ntokens;
         2596         for(j0 = 1; j0 <= nnonter; j0++) {
         2597                 j1++;
         2598                 if(temp1[j1])
         2599                         Bprint(foutput, "\t%s  goto %d\n", symnam(j0+NTBASE), temp1[j1]);
         2600         }
         2601 }
         2602 
         2603 void
         2604 warray(char *s, int *v, int n)
         2605 {
         2606         int i;
         2607 
         2608         Bprint(ftable, "static\tconst\tshort        %s[] =\n{", s);
         2609         for(i=0;;) {
         2610                 if(i%10 == 0)
         2611                         Bprint(ftable, "\n");
         2612                 Bprint(ftable, "%4d", v[i]);
         2613                 i++;
         2614                 if(i >= n) {
         2615                         Bprint(ftable, "\n};\n");
         2616                         break;
         2617                 }
         2618                 Bprint(ftable, ",");
         2619         }
         2620 }
         2621 
         2622 /*
         2623  * in order to free up the mem and amem arrays for the optimizer,
         2624  * and still be able to output yyr1, etc., after the sizes of
         2625  * the action array is known, we hide the nonterminals
         2626  * derived by productions in levprd.
         2627  */
         2628 
         2629 void
         2630 hideprod(void)
         2631 {
         2632         int i, j;
         2633 
         2634         j = 0;
         2635         levprd[0] = 0;
         2636         PLOOP(1, i) {
         2637                 if(!(levprd[i] & REDFLAG)) {
         2638                         j++;
         2639                         if(foutput != 0)
         2640                                 Bprint(foutput, "Rule not reduced:   %s\n", writem(prdptr[i]));
         2641                 }
         2642                 levprd[i] = *prdptr[i] - NTBASE;
         2643         }
         2644         if(j)
         2645                 print("%d rules never reduced\n", j);
         2646 }
         2647 
         2648 void
         2649 callopt(void)
         2650 {
         2651         int i, *p, j, k, *q;
         2652 
         2653         /* read the arrays from tempfile and set parameters */
         2654         finput = Bopen(tempname, OREAD);
         2655         if(finput == 0)
         2656                 error("optimizer cannot open tempfile");
         2657 
         2658         pgo[0] = 0;
         2659         temp1[0] = 0;
         2660         nstate = 0;
         2661         nnonter = 0;
         2662         for(;;) {
         2663                 switch(gtnm()) {
         2664                 case '\n':
         2665                         nstate++;
         2666                         pmem--;
         2667                         temp1[nstate] = pmem - mem0;
         2668                 case ',':
         2669                         continue;
         2670                 case '$':
         2671                         break;
         2672                 default:
         2673                         error("bad tempfile %s", tempname);
         2674                 }
         2675                 break;
         2676         }
         2677 
         2678         pmem--;
         2679         temp1[nstate] = yypgo[0] = pmem - mem0;
         2680         for(;;) {
         2681                 switch(gtnm()) {
         2682                 case '\n':
         2683                         nnonter++;
         2684                         yypgo[nnonter] = pmem-mem0;
         2685                 case ',':
         2686                         continue;
         2687                 case -1:
         2688                         break;
         2689                 default:
         2690                         error("bad tempfile");
         2691                 }
         2692                 break;
         2693         }
         2694         pmem--;
         2695         yypgo[nnonter--] = pmem - mem0;
         2696         for(i = 0; i < nstate; i++) {
         2697                 k = 32000;
         2698                 j = 0;
         2699                 q = mem0 + temp1[i+1];
         2700                 for(p = mem0 + temp1[i]; p < q ; p += 2) {
         2701                         if(*p > j)
         2702                                 j = *p;
         2703                         if(*p < k)
         2704                                 k = *p;
         2705                 }
         2706                 /* nontrivial situation */
         2707                 if(k <= j) {
         2708                         /* j is now the range */
         2709 /*                        j -= k;                        *//* call scj */
         2710                         if(k > maxoff)
         2711                                 maxoff = k;
         2712                 }
         2713                 tystate[i] = (temp1[i+1]-temp1[i]) + 2*j;
         2714                 if(j > maxspr)
         2715                         maxspr = j;
         2716         }
         2717 
         2718         /* initialize ggreed table */
         2719         for(i = 1; i <= nnonter; i++) {
         2720                 ggreed[i] = 1;
         2721                 j = 0;
         2722 
         2723                 /* minimum entry index is always 0 */
         2724                 q = mem0 + yypgo[i+1] - 1;
         2725                 for(p = mem0+yypgo[i]; p < q ; p += 2) {
         2726                         ggreed[i] += 2;
         2727                         if(*p > j)
         2728                                 j = *p;
         2729                 }
         2730                 ggreed[i] = ggreed[i] + 2*j;
         2731                 if(j > maxoff)
         2732                         maxoff = j;
         2733         }
         2734 
         2735         /* now, prepare to put the shift actions into the amem array */
         2736         for(i = 0; i < ACTSIZE; i++)
         2737                 amem[i] = 0;
         2738         maxa = amem;
         2739         for(i = 0; i < nstate; i++) {
         2740                 if(tystate[i] == 0 && adb > 1)
         2741                         Bprint(ftable, "State %d: null\n", i);
         2742                 indgo[i] = YYFLAG1;
         2743         }
         2744         while((i = nxti()) != NOMORE)
         2745                 if(i >= 0)
         2746                         stin(i);
         2747                 else
         2748                         gin(-i);
         2749 
         2750         /* print amem array */
         2751         if(adb > 2 )
         2752                 for(p = amem; p <= maxa; p += 10) {
         2753                         Bprint(ftable, "%4d  ", (int)(p-amem));
         2754                         for(i = 0; i < 10; ++i)
         2755                                 Bprint(ftable, "%4d  ", p[i]);
         2756                         Bprint(ftable, "\n");
         2757                 }
         2758 
         2759         /* write out the output appropriate to the language */
         2760         aoutput();
         2761         osummary();
         2762         ZAPFILE(tempname);
         2763 }
         2764 
         2765 void
         2766 gin(int i)
         2767 {
         2768         int *p, *r, *s, *q1, *q2;
         2769 
         2770         /* enter gotos on nonterminal i into array amem */
         2771         ggreed[i] = 0;
         2772 
         2773         q2 = mem0+ yypgo[i+1] - 1;
         2774         q1 = mem0 + yypgo[i];
         2775 
         2776         /* now, find amem place for it */
         2777         for(p = amem; p < &amem[ACTSIZE]; p++) {
         2778                 if(*p)
         2779                         continue;
         2780                 for(r = q1; r < q2; r += 2) {
         2781                         s = p + *r + 1;
         2782                         if(*s)
         2783                                 goto nextgp;
         2784                         if(s > maxa)
         2785                                 if((maxa = s) > &amem[ACTSIZE])
         2786                                         error("a array overflow");
         2787                 }
         2788                 /* we have found amem spot */
         2789                 *p = *q2;
         2790                 if(p > maxa)
         2791                         if((maxa = p) > &amem[ACTSIZE])
         2792                                 error("a array overflow");
         2793                 for(r = q1; r < q2; r += 2) {
         2794                         s = p + *r + 1;
         2795                         *s = r[1];
         2796                 }
         2797                 pgo[i] = p-amem;
         2798                 if(adb > 1)
         2799                         Bprint(ftable, "Nonterminal %d, entry at %d\n", i, pgo[i]);
         2800                 return;
         2801 
         2802         nextgp:;
         2803         }
         2804         error("cannot place goto %d\n", i);
         2805 }
         2806 
         2807 void
         2808 stin(int i)
         2809 {
         2810         int *r, *s, n, flag, j, *q1, *q2;
         2811 
         2812         tystate[i] = 0;
         2813 
         2814         /* enter state i into the amem array */
         2815         q2 = mem0+temp1[i+1];
         2816         q1 = mem0+temp1[i];
         2817         /* find an acceptable place */
         2818         for(n = -maxoff; n < ACTSIZE; n++) {
         2819                 flag = 0;
         2820                 for(r = q1; r < q2; r += 2) {
         2821                         if((s = *r + n + amem) < amem)
         2822                                 goto nextn;
         2823                         if(*s == 0)
         2824                                 flag++;
         2825                         else
         2826                                 if(*s != r[1])
         2827                                         goto nextn;
         2828                 }
         2829 
         2830                 /* check that the position equals another only if the states are identical */
         2831                 for(j=0; j<nstate; j++) {
         2832                         if(indgo[j] == n) {
         2833 
         2834                                 /* we have some disagreement */
         2835                                 if(flag)
         2836                                         goto nextn;
         2837                                 if(temp1[j+1]+temp1[i] == temp1[j]+temp1[i+1]) {
         2838 
         2839                                         /* states are equal */
         2840                                         indgo[i] = n;
         2841                                         if(adb > 1)
         2842                                                 Bprint(ftable,
         2843                                                 "State %d: entry at %d equals state %d\n",
         2844                                                 i, n, j);
         2845                                         return;
         2846                                 }
         2847 
         2848                                 /* we have some disagreement */
         2849                                 goto nextn;
         2850                         }
         2851                 }
         2852 
         2853                 for(r = q1; r < q2; r += 2) {
         2854                         if((s = *r+n+amem) >= &amem[ACTSIZE])
         2855                                 error("out of space in optimizer a array");
         2856                         if(s > maxa)
         2857                                 maxa = s;
         2858                         if(*s != 0 && *s != r[1])
         2859                                 error("clobber of a array, pos'n %d, by %d", s-amem, r[1]);
         2860                         *s = r[1];
         2861                 }
         2862                 indgo[i] = n;
         2863                 if(adb > 1)
         2864                         Bprint(ftable, "State %d: entry at %d\n", i, indgo[i]);
         2865                 return;
         2866         nextn:;
         2867         }
         2868         error("Error; failure to place state %d\n", i);
         2869 }
         2870 
         2871 /*
         2872  * finds the next i
         2873  */
         2874 int
         2875 nxti(void)
         2876 {
         2877         int i, max, maxi;
         2878 
         2879         max = 0;
         2880         maxi = 0;
         2881         for(i = 1; i <= nnonter; i++)
         2882                 if(ggreed[i] >= max) {
         2883                         max = ggreed[i];
         2884                         maxi = -i;
         2885                 }
         2886         for(i = 0; i < nstate; ++i)
         2887                 if(tystate[i] >= max) {
         2888                         max = tystate[i];
         2889                         maxi = i;
         2890                 }
         2891         if(nxdb)
         2892                 Bprint(ftable, "nxti = %d, max = %d\n", maxi, max);
         2893         if(max == 0)
         2894                 return NOMORE;
         2895         return maxi;
         2896 }
         2897 
         2898 /*
         2899  * write summary
         2900  */
         2901 void
         2902 osummary(void)
         2903 {
         2904 
         2905         int i, *p;
         2906 
         2907         if(foutput == 0)
         2908                 return;
         2909         i = 0;
         2910         for(p = maxa; p >= amem; p--)
         2911                 if(*p == 0)
         2912                         i++;
         2913 
         2914         Bprint(foutput, "Optimizer space used: input %d/%d, output %d/%d\n",
         2915                 (int)(pmem-mem0+1), MEMSIZE, (int)(maxa-amem+1), ACTSIZE);
         2916         Bprint(foutput, "%d table entries, %d zero\n", (int)(maxa-amem+1), i);
         2917         Bprint(foutput, "maximum spread: %d, maximum offset: %d\n", maxspr, maxoff);
         2918 }
         2919 
         2920 /*
         2921  * this version is for C
         2922  * write out the optimized parser
         2923  */
         2924 void
         2925 aoutput(void)
         2926 {
         2927         Bprint(ftable, "#define\tYYLAST\t%d\n", (int)(maxa-amem+1));
         2928         arout("yyact", amem, (maxa-amem)+1);
         2929         arout("yypact", indgo, nstate);
         2930         arout("yypgo", pgo, nnonter+1);
         2931 }
         2932 
         2933 void
         2934 arout(char *s, int *v, int n)
         2935 {
         2936         int i;
         2937 
         2938         Bprint(ftable, "static\tconst\tshort        %s[] =\n{", s);
         2939         for(i = 0; i < n;) {
         2940                 if(i%10 == 0)
         2941                         Bprint(ftable, "\n");
         2942                 Bprint(ftable, "%4d", v[i]);
         2943                 i++;
         2944                 if(i == n)
         2945                         Bprint(ftable, "\n};\n");
         2946                 else
         2947                         Bprint(ftable, ",");
         2948         }
         2949 }
         2950 
         2951 /*
         2952  * read and convert an integer from the standard input
         2953  * return the terminating character
         2954  * blanks, tabs, and newlines are ignored
         2955  */
         2956 int
         2957 gtnm(void)
         2958 {
         2959         int sign, val, c;
         2960 
         2961         sign = 0;
         2962         val = 0;
         2963         while((c=Bgetrune(finput)) != Beof) {
         2964                 if(isdigit(c)) {
         2965                         val = val*10 + c-'0';
         2966                         continue;
         2967                 }
         2968                 if(c == '-') {
         2969                         sign = 1;
         2970                         continue;
         2971                 }
         2972                 break;
         2973         }
         2974         if(sign)
         2975                 val = -val;
         2976         *pmem++ = val;
         2977         if(pmem >= &mem0[MEMSIZE])
         2978                 error("out of space");
         2979         return c;
         2980 }