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