]> Cypherpunks repositories - gostls13.git/commitdiff
goyacc command
authorKen Thompson <ken@golang.org>
Thu, 10 Sep 2009 20:19:46 +0000 (13:19 -0700)
committerKen Thompson <ken@golang.org>
Thu, 10 Sep 2009 20:19:46 +0000 (13:19 -0700)
written in (c-style) go
produces go source parser

R=rsc
OCL=34522
CL=34522

src/cmd/goyacc/Makefile [new file with mode: 0644]
src/cmd/goyacc/goyacc.go [new file with mode: 0644]

diff --git a/src/cmd/goyacc/Makefile b/src/cmd/goyacc/Makefile
new file mode 100644 (file)
index 0000000..cca46c3
--- /dev/null
@@ -0,0 +1,12 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include $(GOROOT)/src/Make.$(GOARCH)
+
+TARG=goyacc
+GOFILES=\
+       goyacc.go\
+
+include $(GOROOT)/src/Make.cmd
+
diff --git a/src/cmd/goyacc/goyacc.go b/src/cmd/goyacc/goyacc.go
new file mode 100644 (file)
index 0000000..480d34e
--- /dev/null
@@ -0,0 +1,3543 @@
+/*
+Derived from Inferno's utils/iyacc/yacc.c
+http://code.google.com/p/inferno-os/source/browse/utils/iyacc/yacc.c
+
+This copyright NOTICE applies to all files in this directory and
+subdirectories, unless another copyright notice appears in a given
+file or subdirectory.  If you take substantial code from this software to use in
+other programs, you must somehow include with it an appropriate
+copyright notice that includes the copyright notice and the other
+notices below.  It is fine (and often tidier) to do that in a separate
+file such as NOTICE, LICENCE or COPYING.
+
+       Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+       Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+       Portions Copyright © 1997-1999 Vita Nuova Limited
+       Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+       Portions Copyright © 2004,2006 Bruce Ellis
+       Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+       Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+       Portions Copyright © 2009 The Go Authors.  All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+package main
+
+// yacc
+// major difference is lack of stem ("y" variable)
+//
+
+import
+(
+       "flag";
+       "io";
+       "fmt";
+       "bufio";
+       "os";
+)
+
+// the following are adjustable
+// according to memory size
+const
+(
+       ACTSIZE         = 30000;
+       NSTATES         = 2000;
+       TEMPSIZE        = 2000;
+
+       SYMINC          = 50;                           // increase for non-term or term
+       RULEINC         = 50;                           // increase for max rule length prodptr[i]
+       PRODINC         = 100;                          // increase for productions     prodptr
+       WSETINC         = 50;                           // increase for working sets    wsets
+       STATEINC        = 200;                          // increase for states          statemem
+
+       NAMESIZE        = 50;
+       NTYPES          = 63;
+       ISIZE           = 400;
+
+       PRIVATE         = 0xE000;                       // unicode private use
+
+// relationships which must hold:
+//     TEMPSIZE >= NTERMS + NNONTERM + 1;
+//     TEMPSIZE >= NSTATES;
+//
+
+       NTBASE          = 010000;
+       ERRCODE         = 8190;
+       ACCEPTCODE      = 8191;
+       YYLEXUNK        = 3;
+       TOKSTART        = 4;                            //index of first defined token
+)
+
+// no, left, right, binary assoc.
+const
+(
+       NOASC           = iota;
+       LASC;
+       RASC;
+       BASC;
+)
+
+// flags for state generation
+const
+(
+       DONE            = iota;
+       MUSTDO;
+       MUSTLOOKAHEAD;
+)
+
+// flags for a rule having an action, and being reduced
+const
+(
+       ACTFLAG         = 1<<(iota+2);
+       REDFLAG;
+)
+
+// output parser flags
+const  YYFLAG          = -1000
+
+// parse tokens
+const
+(
+       IDENTIFIER      = PRIVATE+iota;
+       MARK;
+       TERM;
+       LEFT;
+       RIGHT;
+       BINARY;
+       PREC;
+       LCURLY;
+       IDENTCOLON;
+       NUMBER;
+       START;
+       TYPEDEF;
+       TYPENAME;
+       UNION;
+)
+
+const  ENDFILE         = 0
+const  EMPTY           = 1
+const  WHOKNOWS        = 0
+const  OK              = 1
+const  NOMORE          = -1000
+
+// macros for getting associativity and precedence levels
+func
+ASSOC(i int) int
+{
+       return i & 3;
+}
+
+func
+PLEVEL(i int) int
+{
+       return (i >> 4) & 077;
+}
+
+func
+TYPE(i int) int
+{
+       return (i >> 10) & 077;
+}
+
+// macros for setting associativity and precedence levels
+func
+SETASC(i, j int) int
+{
+       return i | j;
+}
+
+func
+SETPLEV(i, j int) int
+{
+       return i | (j << 4);
+}
+
+func
+SETTYPE(i, j int) int
+{
+       return i | (j << 10);
+}
+
+// I/O descriptors
+var    finput          *bufio.Reader                   // input file
+var    stderr          *bufio.Writer
+var    ftable          *bufio.Writer                   // y.go file
+var    foutput         *bufio.Writer                   // y.output file
+
+var    oflag           string                          // -o [y.go]            - y.go file
+var    vflag           string                          // -v [y.output]        - y.output file
+var    lflag           bool                            // -l                   - disable line directives
+
+var    stacksize       = 200
+
+// communication variables between various I/O routines
+var    infile          string                          // input file name
+var    numbval         int                             // value of an input number
+var    tokname         string                          // input token name, slop for runes and 0
+var    tokflag         = false;
+
+// structure declarations
+type   Lkset           []int
+
+type   Pitem
+struct
+{
+       prod            []int;
+       off             int;                            // offset within the production
+       first           int;                            // first term or non-term in item
+       prodno          int;                            // production number for sorting
+}
+
+type   Item
+struct
+{
+       pitem           Pitem;
+       look            Lkset;
+}
+
+type   Symb
+struct
+{
+       name            string;
+       value           int;
+}
+
+type   Wset
+struct
+{
+       pitem           Pitem;
+       flag            int;
+       ws              Lkset;
+}
+
+// storage of types
+var    ntypes          int                             // number of types defined
+var    typeset         [NTYPES]string                  // pointers to type tags
+
+// token information
+
+var    ntokens         = 0                             // number of tokens
+var    tokset          []Symb
+var    toklev          []int                           // vector with the precedence of the terminals
+
+// nonterminal information
+
+var    nnonter         = -1                            // the number of nonterminals
+var    nontrst         []Symb
+var    start           int                             // start symbol
+
+// state information
+
+var    nstate          = 0                             // number of states
+var    pstate          = make([]int, NSTATES+2)        // index into statemem to the descriptions of the states
+var    statemem        []Item
+var    tystate         = make([]int, NSTATES)          // contains type information about the states
+var    tstates         []int                           // states generated by terminal gotos
+var    ntstates        []int                           // states generated by nonterminal gotos
+var    mstates         = make([]int, NSTATES)          // chain of overflows of term/nonterm generation lists
+var    lastred         int                             // number of last reduction of a state
+var    defact          = make([]int, NSTATES)          // default actions of states
+
+// lookahead set information
+
+var    lkst            []Lkset
+var    nolook          = 0                             // flag to turn off lookahead computations
+var    tbitset         = 0                             // size of lookahead sets
+var    clset           Lkset                           // temporary storage for lookahead computations
+
+// working set information
+
+var    wsets           []Wset
+var    cwp             int
+
+// storage for action table
+
+var    amem            []int                           // action table storage
+var    memp            int                             // next free action table position
+var    indgo           = make([]int, NSTATES)          // index to the stored goto table
+
+// temporary vector, indexable by states, terms, or ntokens
+
+var    temp1           = make([]int, TEMPSIZE)         // temporary storage, indexed by terms + ntokens or states
+var    lineno          = 1                             // current input line number
+var    fatfl           = 1                             // if on, error is fatal
+var    nerrors         = 0                             // number of errors
+
+// assigned token type values
+
+var    extval          = 0
+
+// grammar rule information
+
+var    nprod           = 1                             // number of productions
+var    prdptr          [][]int                         // pointers to descriptions of productions
+var    levprd          []int                           // precedence levels for the productions
+var    rlines          []int                           // line number for this rule
+
+// statistics collection variables
+
+var    zzgoent         = 0
+var    zzgobest        = 0
+var    zzacent         = 0
+var    zzexcp          = 0
+var    zzclose         = 0
+var    zzrrconf        = 0
+var    zzsrconf        = 0
+var    zzstate         = 0
+
+// optimizer arrays
+
+var    yypgo           [][]int
+var    optst           [][]int
+var    ggreed          []int
+var    pgo             []int
+
+var    maxspr          int                             // maximum spread of any entry
+var    maxoff          int                             // maximum offset into a array
+var    maxa            int
+
+// storage for information about the nonterminals
+
+var    pres            [][][]int                       // vector of pointers to productions yielding each nonterminal
+var    pfirst          []Lkset
+var    pempty          []int                           // vector of nonterminals nontrivially deriving e
+
+// random stuff picked out from between functions
+
+var    indebug         = 0                             // debugging flag for cpfir
+var    pidebug         = 0                             // debugging flag for putitem
+var    gsdebug         = 0                             // debugging flag for stagen
+var    cldebug         = 0                             // debugging flag for closure
+var    pkdebug         = 0                             // debugging flag for apack
+var    g2debug         = 0                             // debugging for go2gen
+var    adb             = 0                             // debugging for callopt
+
+type   Resrv
+struct
+{
+       name    string;
+       value   int;
+}
+
+var    resrv           =
+[]Resrv {
+       Resrv{"binary",         BINARY},
+       Resrv{"left",           LEFT},
+       Resrv{"nonassoc",       BINARY},
+       Resrv{"prec",           PREC},
+       Resrv{"right",          RIGHT},
+       Resrv{"start",          START},
+       Resrv{"term",           TERM},
+       Resrv{"token",          TERM},
+       Resrv{"type",           TYPEDEF},
+       Resrv{"union",          UNION},
+       Resrv{"struct",         UNION}
+}
+
+var    zznewstate      = 0
+const  EOF             = -1
+const  UTFmax          = 0x3f
+
+func
+main()
+{
+
+       setup();                // initialize and read productions
+
+       tbitset = (ntokens+32)/32;
+       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
+
+       yypgo = make([][]int, nnonter+1);
+       optst = make([][]int, nstate);
+       output();               // write the states and the tables
+       go2out();
+
+       hideprod();
+       summary();
+
+       callopt();
+
+       others();
+
+       exit(0);
+}
+
+func
+setup()
+{
+       var j, ty int;
+
+       stderr = bufio.NewWriter(os.NewFile(2, "stderr"));
+       foutput = nil;
+
+       flag.StringVar(&oflag, "o", "", "parser output");
+       flag.StringVar(&vflag, "v", "", "create parsing tables");
+       flag.BoolVar(&lflag, "l", false, "disable line directives");
+
+       flag.Parse();
+       if flag.NArg() != 1 {
+               usage();
+       }
+       if stacksize < 1 {
+               // never set so cannot happen
+               fmt.Fprintf(stderr, "yacc: stack size too small\n");
+               usage();
+       }
+       openup();
+
+       defin(0, "$end");
+       extval = PRIVATE;       // tokens start in unicode 'private use'
+       defin(0, "error");
+       defin(1, "$accept");
+       defin(0, "$unk");
+       i := 0;
+
+       t := gettok();
+
+    outer:
+       for {
+               switch t {
+               default:
+                       error("syntax error tok=%v", t-PRIVATE);
+
+               case MARK,ENDFILE:
+                       break outer;
+
+               case ';':
+
+               case START:
+                       t = gettok();
+                       if t != IDENTIFIER {
+                               error("bad %%start construction");
+                       }
+                       start = chfind(1, tokname);
+
+               case TYPEDEF:
+                       t = gettok();
+                       if t != TYPENAME {
+                               error("bad syntax in %%type");
+                       }
+                       ty = numbval;
+                       for {
+                               t = gettok();
+                               switch t {
+                               case IDENTIFIER:
+                                       t = chfind(1, tokname);
+                                       if t < NTBASE {
+                                               j = TYPE(toklev[t]);
+                                               if(j != 0 && j != ty) {
+                                                       error("type redeclaration of token ",
+                                                               tokset[t].name);
+                                               } else
+                                                       toklev[t] = SETTYPE(toklev[t], ty);
+                                       } else {
+                                               j = nontrst[t-NTBASE].value;
+                                               if(j != 0 && j != ty) {
+                                                       error("type redeclaration of nonterminal %v",
+                                                               nontrst[t-NTBASE].name);
+                                               } else
+                                                       nontrst[t-NTBASE].value = ty;
+                                       }
+                                       continue;
+
+                               case ',':
+                                       continue;
+                               }
+                               break;
+                       }
+                       continue;
+
+               case UNION:
+                       cpyunion();
+
+               case LEFT,BINARY,RIGHT,TERM:
+                       // nonzero means new prec. and assoc.
+                       lev := t-TERM;
+                       if lev != 0 {
+                               i++;
+                       }
+                       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("%v defined earlier as nonterminal", tokname);
+                                       }
+                                       if lev != 0 {
+                                               if ASSOC(toklev[j]) != 0 {
+                                                       error("redeclaration of precedence of %v", tokname);
+                                               }
+                                               toklev[j] = SETASC(toklev[j], lev);
+                                               toklev[j] = SETPLEV(toklev[j], i);
+                                       }
+                                       if ty != 0 {
+                                               if TYPE(toklev[j]) != 0 {
+                                                       error("redeclaration of type of %v", tokname);
+                                               }
+                                               toklev[j] = SETTYPE(toklev[j], ty);
+                                       }
+                                       t = gettok();
+                                       if t == NUMBER {
+                                               tokset[j].value = numbval;
+                                               t = gettok();
+                                       }
+
+                                       continue;
+                               }
+                               break;
+                       }
+                       continue;
+
+               case LCURLY:
+                       cpycode();
+               }
+               t = gettok();
+       }
+
+       if t == ENDFILE {
+               error("unexpected EOF before %%");
+       }
+
+       // put out non-literal terminals
+       for i:=TOKSTART; i<=ntokens; i++ {
+               // non-literals
+               c := tokset[i].name[0];
+               if c != ' ' && c != '$' {
+                       fmt.Fprintf(ftable, "const\t%v\t= %v\n", tokset[i].name, tokset[i].value);
+               }
+       }
+
+       // put out names of token names
+       fmt.Fprintf(ftable, "var\tToknames\t =[]string {\n");
+       for i:=TOKSTART; i<=ntokens; i++ {
+               fmt.Fprintf(ftable, "\t\"%v\",\n", tokset[i].name);
+       }
+       fmt.Fprintf(ftable, "}\n");
+
+       // put out names of state names
+       fmt.Fprintf(ftable, "var\tStatenames\t =[]string {\n");
+//     for i:=TOKSTART; i<=ntokens; i++ {
+//             fmt.Fprintf(ftable, "\t\"%v\",\n", tokset[i].name);
+//     }
+       fmt.Fprintf(ftable, "}\n");
+
+       fmt.Fprintf(ftable, "\nfunc\n");
+       fmt.Fprintf(ftable, "yyrun(p int, yypt int) {\n");
+       fmt.Fprintf(ftable, "switch p {\n");
+
+       moreprod();
+       prdptr[0] = []int{NTBASE,start,1,0};
+
+       nprod = 1;
+       curprod := make([]int, RULEINC);
+       t = gettok();
+       if t != IDENTCOLON {
+               error("bad syntax on first rule");
+       }
+
+       if start == 0 {
+               prdptr[0][1] = chfind(1, tokname);
+       }
+
+       // read rules
+       // put into prdptr array in the format
+       // target
+       // followed by id's of terminals and non-terminals
+       // followd by -nprod
+
+       for t != MARK && t != ENDFILE {
+               mem := 0;
+
+               // process a rule
+               rlines[nprod] = lineno;
+               if t == '|' {
+                       curprod[mem] = prdptr[nprod-1][0];
+                       mem++;
+               } else
+               if t == IDENTCOLON {
+                       curprod[mem] = chfind(1, tokname);
+                       if curprod[mem] < NTBASE {
+                               error("token illegal on LHS of grammar rule");
+                       }
+                       mem++;
+               } else
+                       error("illegal rule: missing semicolon or | ?");
+
+               // read rule body
+               t = gettok();
+               for {
+                       for t == IDENTIFIER {
+                               curprod[mem] = chfind(1, tokname);
+                               if curprod[mem] < NTBASE {
+                                       levprd[nprod] = toklev[curprod[mem]];
+                               }
+                               mem++;
+                               if mem >= len(curprod) {
+                                       ncurprod := make([]int, mem+RULEINC);
+                                       for ll:=0; ll<mem; ll++ {
+                                               ncurprod[ll] = curprod[ll];
+                                       }
+                                       curprod = ncurprod;
+                               }
+                               t = gettok();
+                       }
+                       if t == PREC {
+                               if gettok() != IDENTIFIER {
+                                       error("illegal %%prec syntax");
+                               }
+                               j = chfind(2, tokname);
+                               if j >= NTBASE {
+                                       error("nonterminal "+nontrst[j-NTBASE].name+" illegal after %%prec");
+                               }
+                               levprd[nprod] = toklev[j];
+                               t = gettok();
+                       }
+                       if t != '=' {
+                               break;
+                       }
+                       levprd[nprod] |= ACTFLAG;
+                       fmt.Fprintf(ftable, "\ncase %v:", nprod);
+                       cpyact(curprod, mem);
+
+                       // action within rule...
+                       t = gettok();
+                       if t == IDENTIFIER {
+                               // make it a nonterminal
+                               j = chfind(1, fmt.Sprintf("$$%v",nprod));
+
+                               //
+                               // the current rule will become rule number nprod+1
+                               // enter null production for action
+                               //
+                               prdptr[nprod] = make([]int, 2);
+                               prdptr[nprod][0] = j;
+                               prdptr[nprod][1] = -nprod;
+
+                               // update the production information
+                               nprod++;
+                               moreprod();
+                               levprd[nprod] = levprd[nprod-1] & ^ACTFLAG;
+                               levprd[nprod-1] = ACTFLAG;
+                               rlines[nprod] = lineno;
+
+                               // make the action appear in the original rule
+                               curprod[mem] = j;
+                               mem++;
+                               if mem >= len(curprod) {
+                                       ncurprod := make([]int, mem+RULEINC);
+                                       for ll:=0; ll<mem; ll++ {
+                                               ncurprod[ll] = curprod[ll];
+                                       }
+                                       curprod = ncurprod;
+                               }
+                       }
+               }
+
+               for t == ';' {
+                       t = gettok();
+               }
+               curprod[mem] = -nprod;
+               mem++;
+
+               // check that default action is reasonable
+               if ntypes != 0 && (levprd[nprod]&ACTFLAG) == 0 &&
+                  nontrst[curprod[0]-NTBASE].value != 0 {
+                       // no explicit action, LHS has value
+                       tempty := curprod[1];
+                       if tempty < 0 {
+                               error("must return a value, since LHS has a type");
+                       }
+                       if tempty >= NTBASE {
+                               tempty = nontrst[tempty-NTBASE].value;
+                       } else
+                               tempty = TYPE(toklev[tempty]);
+                       if tempty != nontrst[curprod[0]-NTBASE].value {
+                               error("default action causes potential type clash");
+                       }
+                       fmt.Fprintf(ftable, "\ncase %v:", nprod);
+                       fmt.Fprintf(ftable, "\n\tYYVAL.%v = YYS[yypt-0].%v;",
+                               typeset[tempty], typeset[tempty]);
+               }
+               moreprod();
+               prdptr[nprod] = make([]int, mem);
+               for ll:=0; ll<mem; ll++ {
+                       prdptr[nprod][ll] = curprod[ll];
+               }
+               nprod++;
+               moreprod();
+               levprd[nprod] = 0;
+       }
+
+       //
+       // end of all rules
+       // dump out the prefix code
+       //
+
+       fmt.Fprintf(ftable, "\n\t}");
+       fmt.Fprintf(ftable, "\n}\n");
+
+       fmt.Fprintf(ftable, "const      YYEOFCODE       = 1\n");
+       fmt.Fprintf(ftable, "const      YYERRCODE       = 2\n");
+       fmt.Fprintf(ftable, "const      YYMAXDEPTH      = %v\n", stacksize);
+
+       //
+       // copy any postfix code
+       //
+       if t == MARK {
+               if !lflag {
+                       fmt.Fprintf(ftable, "\n//line %v:%v\n", infile, lineno);
+               }
+               for {
+                       c := getrune(finput);
+                       if c == EOF {
+                               break;
+                       }
+                       putrune(ftable, c);
+               }
+       }
+}
+
+//
+// allocate enough room to hold another production
+//
+func
+moreprod()
+{
+       n := len(prdptr);
+       if nprod >= n {
+               nn := n+PRODINC;
+               aprod := make([][]int, nn);
+               alevprd := make([]int, nn);
+               arlines := make([]int, nn);
+
+               for ll:=0; ll<n; ll++ {
+                       aprod[ll] = prdptr[ll];
+                       alevprd[ll] = levprd[ll];
+                       arlines[ll] = rlines[ll];
+               }
+
+               prdptr = aprod;
+               levprd = alevprd;
+               rlines = arlines;
+       }
+}
+
+//
+// define s to be a terminal if t=0
+// or a nonterminal if t=1
+//
+func
+defin(nt int, s string) int
+{
+       val := 0;
+       if nt != 0 {
+               nnonter++;
+               if nnonter >= len(nontrst) {
+                       anontrst := make([]Symb, nnonter+SYMINC);
+                       for ll:=0; ll<len(nontrst); ll++ {
+                               anontrst[ll] = nontrst[ll];
+                       }
+                       nontrst = anontrst;
+               }
+               nontrst[nnonter] = Symb{s, 0};
+               return NTBASE + nnonter;
+       }
+
+       // must be a token
+       ntokens++;
+       if ntokens >= len(tokset) {
+               nn := ntokens+SYMINC;
+               atokset := make([]Symb, nn);
+               atoklev := make([]int, nn);
+
+               for ll:=0; ll<len(tokset); ll++ {
+                       atoklev[ll] = toklev[ll];
+                       atokset[ll] = tokset[ll];
+               }
+
+               tokset = atokset;
+               toklev = atoklev;
+       }
+       tokset[ntokens].name = s;
+       toklev[ntokens] = 0;
+
+       // establish value for token
+       // single character literal
+       if s[0] == ' ' && len(s) == 1+1 {
+               val = int(s[1]);
+       } else
+       if s[0] == ' ' && s[1] == '\\' { // escape sequence
+               if(len(s) == 2+1) {
+                       // single character escape sequence
+                       switch s[2] {
+                       case '\'':      val = '\'';
+                       case '"':       val = '"';
+                       case '\\':      val = '\\';
+                       case 'a':       val = '\a';
+                       case 'b':       val = '\b';
+                       case 'n':       val = '\n';
+                       case 'r':       val = '\r';
+                       case 't':       val = '\t';
+                       case 'v':       val = '\v';
+                       default:
+                               error("invalid escape %v", s[1:3]);
+                       }
+               } else
+               if s[2] == 'u' && len(s) == 2+1+4 { // \unnnn sequence
+                       val = 0;
+                       s = s[3:len(s)];
+                       for s != "" {
+                               c := int(s[0]);
+                               switch {
+                               case c >= '0' && c <= '9':
+                                       c -= '0';
+                               case c >= 'a' && c <= 'f':
+                                       c -= 'a' - 10;
+                               case c >= 'A' && c <= 'F':
+                                       c -= 'A' - 10;
+                               default:
+                                       error("illegal \\unnnn construction");
+                               }
+                               val = val * 16 + c;
+                               s = s[1:len(s)];
+                       }
+                       if val == 0 {
+                               error("'\\u0000' is illegal");
+                       }
+               } else
+                       error("unknown escape");
+       } else {
+               val = extval;
+               extval++;
+       }
+
+       tokset[ntokens].value = val;
+       return ntokens;
+}
+
+var peekline = 0;
+func
+gettok() int
+{
+       var i, match, c int;
+
+       tokname = "";
+       for {
+               lineno += peekline;
+               peekline = 0;
+               c = getrune(finput);
+               for c == ' ' || c == '\n' || c == '\t' || c == '\v' || c == '\r' {
+                       if c == '\n' {
+                               lineno++;
+                       }
+                       c = getrune(finput);
+               }
+
+               // skip comment -- fix
+               if c != '/' {
+                       break;
+               }
+               lineno += skipcom();
+       }
+
+       switch c {
+       case EOF:
+               if tokflag {
+                       fmt.Printf(">>> ENDFILE %v\n", lineno);
+               }
+               return ENDFILE;
+
+       case '{':
+               ungetrune(finput, c);
+               if tokflag {
+                       fmt.Printf(">>> ={ %v\n", lineno);
+               }
+               return '=';
+
+       case '<':
+               // get, and look up, a type name (union member name)
+               c = getrune(finput);
+               for c != '>' && c != EOF && c != '\n' {
+                       tokname += string(c);
+                       c = getrune(finput);
+               }
+
+               if c != '>' {
+                       error("unterminated < ... > clause");
+               }
+
+               for i=1; i<=ntypes; i++ {
+                       if typeset[i] == tokname {
+                               numbval = i;
+                               if tokflag {
+                                       fmt.Printf(">>> TYPENAME old <%v> %v\n", tokname, lineno);
+                               }
+                               return TYPENAME;
+                       }
+               }
+               ntypes++;
+               numbval = ntypes;
+               typeset[numbval] = tokname;
+               if tokflag {
+                       fmt.Printf(">>> TYPENAME new <%v> %v\n", tokname, lineno);
+               }
+               return TYPENAME;
+
+       case '"', '\'':
+               match = c;
+               tokname = " ";
+               for {
+                       c = getrune(finput);
+                       if c == '\n' || c == EOF {
+                               error("illegal or missing ' or \"" );
+                       }
+                       if c == '\\' {
+                               tokname += string('\\');
+                               c = getrune(finput);
+                       } else
+                       if c == match {
+                               if tokflag {
+                                       fmt.Printf(">>> IDENTIFIER \"%v\" %v\n", tokname, lineno);
+                               }
+                               return IDENTIFIER;
+                       }
+                       tokname += string(c);
+               }
+
+       case '%':
+               c = getrune(finput);
+               switch c {
+               case '%':
+                       if tokflag {
+                               fmt.Printf(">>> MARK %%%% %v\n", lineno);
+                       }
+                       return MARK;
+               case '=':
+                       if tokflag {
+                               fmt.Printf(">>> PREC %%= %v\n", lineno);
+                       }
+                       return PREC;
+               case '{':
+                       if tokflag {
+                               fmt.Printf(">>> LCURLY %%{ %v\n", lineno);
+                       }
+                       return LCURLY;
+               }
+
+               getword(c);
+               // find a reserved word
+               for c=0; c < len(resrv); c++ {
+                       if tokname == resrv[c].name {
+                               if tokflag {
+                                       fmt.Printf(">>> %%%v %v %v\n", tokname,
+                                               resrv[c].value-PRIVATE, lineno);
+                               }
+                               return resrv[c].value;
+                       }
+               }
+               error("invalid escape, or illegal reserved word: %v", tokname);
+
+       case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+               numbval = c - '0';
+               for {
+                       c = getrune(finput);
+                       if !isdigit(c) {
+                               break;
+                       }
+                       numbval = numbval*10 + c-'0';
+               }
+               ungetrune(finput, c);
+               if tokflag {
+                       fmt.Printf(">>> NUMBER %v %v\n", numbval, lineno);
+               }
+               return NUMBER;
+
+       default:
+               if isword(c) || c == '.' || c == '$' {
+                       getword(c);
+                       break;
+               }
+               if tokflag {
+                       fmt.Printf(">>> OPERATOR %v %v\n", string(c), lineno);
+               }
+               return c;
+       }
+
+       // look ahead to distinguish IDENTIFIER from IDENTCOLON
+       c = getrune(finput);
+       for c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\r' || c == '/' {
+               if c == '\n' {
+                       peekline++;
+               }
+               // look for comments
+               if c == '/' {
+                       peekline += skipcom();
+               }
+               c = getrune(finput);
+       }
+       if c == ':' {
+               if tokflag {
+                       fmt.Printf(">>> IDENTCOLON %v: %v\n", tokname, lineno);
+               }
+               return IDENTCOLON;
+       }
+
+       ungetrune(finput, c);
+       if tokflag {
+               fmt.Printf(">>> IDENTIFIER %v %v\n", tokname, lineno);
+       }
+       return IDENTIFIER;
+}
+
+func
+getword(c int)
+{
+       tokname = "";
+       for isword(c) || isdigit(c) || c == '_' || c == '.' || c == '$' {
+               tokname += string(c);
+               c = getrune(finput);
+       }
+       ungetrune(finput, c);
+}
+
+//
+// determine the type of a symbol
+//
+func
+fdtype(t int) int
+{
+       var v int;
+       var s string;
+
+       if t >= NTBASE {
+               v = nontrst[t-NTBASE].value;
+               s = nontrst[t-NTBASE].name;
+       } else {
+               v = TYPE(toklev[t]);
+               s = tokset[t].name;
+       }
+       if v <= 0 {
+               error("must specify type for %v", s);
+       }
+       return v;
+}
+
+func
+chfind(t int, s string) int
+{
+       if s[0] == ' ' {
+               t = 0;
+       }
+       for i:=0; i<=ntokens; i++ {
+               if s == tokset[i].name {
+                       return i;
+               }
+       }
+       for i:=0; i<=nnonter; i++ {
+               if s == nontrst[i].name {
+                       return NTBASE+i;
+               }
+       }
+
+       // cannot find name
+       if t > 1 {
+               error("%v should have been defined earlier", s);
+       }
+       return defin(t, s);
+}
+
+//
+// copy the union declaration to the output, and the define file if present
+//
+func
+cpyunion()
+{
+
+       if !lflag {
+               fmt.Fprintf(ftable, "\n//line %v %v\n", lineno, infile);
+       }
+       fmt.Fprintf(ftable, "type\tYYSTYPE\tstruct");
+
+       level := 0;
+
+    out:
+       for {
+               c := getrune(finput);
+               if c == EOF {
+                       error("EOF encountered while processing %%union");
+               }
+               putrune(ftable, c);
+               switch(c) {
+               case '\n':
+                       lineno++;
+               case '{':
+                       if level == 0 {
+                               fmt.Fprintf(ftable, "\n\tyys\tint;");
+                       }
+                       level++;
+               case '}':
+                       level--;
+                       if level == 0 {
+                               break out;
+                       }
+               }
+       }
+       fmt.Fprintf(ftable, "\n");
+       fmt.Fprintf(ftable, "var\tyylval\tYYSTYPE\n");
+       fmt.Fprintf(ftable, "var\tYYVAL\tYYSTYPE\n");
+       fmt.Fprintf(ftable, "var\tYYS\t[%v]YYSTYPE\n", stacksize);
+}
+
+//
+// saves code between %{ and %}
+//
+func
+cpycode()
+{
+       lno := lineno;
+
+       c := getrune(finput);
+       if c == '\n' {
+               c = getrune(finput);
+               lineno++;
+       }
+       if !lflag {
+               fmt.Fprintf(ftable, "\n//line %v %v\n", lineno, infile);
+       }
+       for c != EOF {
+               if c == '%' {
+                       c = getrune(finput);
+                       if c == '}' {
+                               return;
+                       }
+                       putrune(ftable, '%');
+               }
+               putrune(ftable, c);
+               if c == '\n' {
+                       lineno++;
+               }
+               c = getrune(finput);
+       }
+       lineno = lno;
+       error("eof before %%}");
+}
+
+//func
+//addcode(k int, s string)
+//{
+//     for i := 0; i < len(s); i++ {
+//             addcodec(k, int(s[i]));
+//     }
+//}
+
+//func
+//addcodec(k, c int)
+//{
+//     if codehead == nil || k != codetail.kind || codetail.ndata >= NCode {
+//             cd := new(Code);
+//             cd.kind = k;
+//             cd.data = make([]byte, NCode+UTFmax);
+//             cd.ndata = 0;
+//             cd.next = nil;
+//
+//             if codehead == nil {
+//                     codehead = cd;
+//             } else
+//                     codetail.next = cd;
+//             codetail = cd;
+//     }
+//
+////!! codetail.ndata += sys->char2byte(c, codetail.data, codetail.ndata);
+//}
+
+//func
+//dumpcode(til int)
+//{
+//     for ; codehead != nil; codehead = codehead.next {
+//             if codehead.kind == til {
+//                     return;
+//             }
+//             if write(ftable, codehead.data, codehead.ndata) != codehead.ndata {
+//                     error("can't write output file");
+//             }
+//     }
+//}
+
+//
+// write out the module declaration and any token info
+//
+//func
+//dumpmod()
+//{
+//
+//     for ; codehead != nil; codehead = codehead.next {
+//             if codehead.kind != CodeMod {
+//                     break;
+//             }
+//             if write(ftable, codehead.data, codehead.ndata) != codehead.ndata {
+//                     error("can't write output file");
+//             }
+//     }
+//
+//     for i:=TOKSTART; i<=ntokens; i++ {
+//             // non-literals
+//             c := tokset[i].name[0];
+//             if c != ' ' && c != '$' {
+//                     fmt.Fprintf(ftable, "vonst      %v      %v\n",
+//                             tokset[i].name, tokset[i].value);
+//             }
+//     }
+//
+//}
+
+//
+// skip over comments
+// skipcom is called after reading a '/'
+//
+func
+skipcom() int
+{
+       var c int;
+
+       c = getrune(finput);
+       if c == '/' {
+               for c != EOF {
+                       if c == '\n' {
+                               return 1;
+                       }
+                       c = getrune(finput);
+               }
+               error("EOF inside comment");
+               return 0;
+       }
+       if c != '*' {
+               error("illegal comment");
+       }
+
+       nl := 0;        // lines skipped
+       c = getrune(finput);
+
+    l1:
+       switch c {
+       case '*':
+               c = getrune(finput);
+               if c == '/' {
+                       break;
+               }
+               goto l1;
+
+       case '\n':
+               nl++;
+               fallthrough;
+
+       default:
+               c = getrune(finput);
+               goto l1;
+       }
+       return nl;
+}
+
+func
+dumpprod(curprod []int, max int)
+{
+       fmt.Printf("\n");
+       for i:=0; i<max; i++ {
+               p := curprod[i];
+               if p < 0 {
+                       fmt.Printf("[%v] %v\n", i, p);
+               } else
+                       fmt.Printf("[%v] %v\n", i, symnam(p));
+       }
+}
+
+//
+// copy action to the next ; or closing }
+//
+func
+cpyact(curprod []int, max int)
+{
+
+       if !lflag {
+               fmt.Fprintf(ftable, "\n//line %v %v\n", lineno, infile);
+       }
+
+       lno := lineno;
+       brac := 0;
+
+    loop:
+       for {
+               c := getrune(finput);
+
+           swt:
+               switch c {
+               case ';':
+                       if(brac == 0) {
+                               putrune(ftable, c);
+                               return;
+                       }
+       
+               case '{':
+                       if brac == 0 {
+                       }
+                               putrune(ftable, '\t');
+                       brac++;
+                       
+               case '$':
+                       s := 1;
+                       tok := -1;
+                       c = getrune(finput);
+       
+                       // type description
+                       if c == '<' {
+                               ungetrune(finput, c);
+                               if gettok() != TYPENAME {
+                                       error("bad syntax on $<ident> clause");
+                               }
+                               tok = numbval;
+                               c = getrune(finput);
+                       }
+                       if c == '$' {
+                               fmt.Fprintf(ftable, "YYVAL");
+       
+                               // put out the proper tag...
+                               if ntypes != 0 {
+                                       if tok < 0 {
+                                               tok = fdtype(curprod[0]);
+                                       }
+                                       fmt.Fprintf(ftable, ".%v", typeset[tok]);
+                               }
+                               continue loop;
+                       }
+                       if c == '-' {
+                               s = -s;
+                               c = getrune(finput);
+                       }
+                       j := 0;
+                       if isdigit(c) {
+                               for isdigit(c) {
+                                       j = j*10 + c-'0';
+                                       c = getrune(finput);
+                               }
+                               ungetrune(finput, c);
+                               j = j*s;
+                               if j >= max {
+                                       error("Illegal use of $%v", j);
+                               }
+                       } else
+                       if isword(c) || c == '_' || c == '.' {
+                               // look for $name
+                               ungetrune(finput, c);
+                               if gettok() != IDENTIFIER {
+                                       error("$ must be followed by an identifier");
+                               }
+                               tokn := chfind(2, tokname);
+                               fnd := -1;
+                               c = getrune(finput);
+                               if c != '@' {
+                                       ungetrune(finput, c);
+                               } else
+                               if gettok() != NUMBER {
+                                       error("@ must be followed by number");
+                               } else
+                                       fnd = numbval;
+                               for j=1; j<max; j++ {
+                                       if tokn == curprod[j] {
+                                               fnd--;
+                                               if fnd <= 0 {
+                                                       break;
+                                               }
+                                       }
+                               }
+                               if j >= max {
+                                       error("$name or $name@number not found");
+                               }
+                       } else {
+                               putrune(ftable, '$');
+                               if s < 0 {
+                                       putrune(ftable, '-');
+                               }
+                               ungetrune(finput, c);
+                               continue loop;
+                       }
+                       fmt.Fprintf(ftable, "YYS[yypt-%v]", max-j-1);
+       
+                       // put out the proper tag
+                       if ntypes != 0 {
+                               if j <= 0 && tok < 0 {
+                                       error("must specify type of $%v", j);
+                               }
+                               if tok < 0 {
+                                       tok = fdtype(curprod[j]);
+                               }
+                               fmt.Fprintf(ftable, ".%v", typeset[tok]);
+                       }
+                       continue loop;
+
+               case '}':
+                       brac--;
+                       if brac != 0 {
+                               break;
+                       }
+                       putrune(ftable, c);
+                       return;
+
+               case '/':
+                       // a comment
+                       putrune(ftable, c);
+                       c = getrune(finput);
+                       for c != EOF {
+                               if c == '\n' {
+                                       lineno++;
+                                       break swt;
+                               }
+                               putrune(ftable, c);
+                               c = getrune(finput);
+                       }
+                       error("EOF inside comment");
+
+               case '\'', '"':
+                       // character string or constant
+                       match := c;
+                       putrune(ftable, c);
+                       c = getrune(finput);
+                       for c != EOF {
+                               if c == '\\' {
+                                       putrune(ftable, c);
+                                       c = getrune(finput);
+                                       if c == '\n' {
+                                               lineno++;
+                                       }
+                               } else
+                               if c == match {
+                                       break swt;
+                               }
+                               if c == '\n' {
+                                       error("newline in string or char const");
+                               }
+                               putrune(ftable, c);
+                               c = getrune(finput);
+                       }
+                       error("EOF in string or character constant");
+
+               case EOF:
+                       lineno = lno;
+                       error("action does not terminate");
+
+               case '\n':
+                       lineno++;
+               }
+
+               putrune(ftable, c);
+       }
+}
+
+func
+openup()
+{
+       var buf string;
+
+       infile = flag.Arg(0);
+       finput = open(infile);
+       if(finput == nil) {
+               error("cannot open %v", infile);
+       }
+
+       foutput = nil;
+       if vflag != "" {
+               foutput = create(vflag, 0666);
+               if foutput == nil {
+                       error("can't create file %v", vflag);
+               }
+       }
+
+       ftable = nil;
+       if oflag == "" {
+               oflag = "y.go";
+       }
+       ftable = create(oflag, 0666);
+       if ftable == nil {
+               error("can't create file %v", oflag);
+       }
+
+}
+
+//
+// return a pointer to the name of symbol i
+//
+func
+symnam(i int) string
+{
+       var s string;
+
+       if i >= NTBASE {
+               s = nontrst[i-NTBASE].name;
+       } else
+               s = tokset[i].name;
+       if s[0] == ' ' {
+               s = s[1:len(s)];
+       }
+       return s;
+}
+
+//
+// set elements 0 through n-1 to c
+//
+func
+aryfil(v []int, n, c int)
+{
+       for i:=0; i<n; i++ {
+               v[i] = c;
+       }
+}
+
+//
+// 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
+//
+func
+cpres()
+{
+       pres = make([][][]int, nnonter+1);
+       curres := make([][]int, nprod);
+
+       if false {
+               for j:=0; j<=nnonter; j++ {
+                       fmt.Printf("nnonter[%v] = %v\n", j, nontrst[j].name);
+               }
+               for j:=0; j<nprod; j++ {
+                       fmt.Printf("prdptr[%v][0] = %v+NTBASE\n", j, prdptr[j][0]-NTBASE);
+               }
+       }
+
+       fatfl = 0;      // make undefined symbols nonfatal
+       for i:=0; i<=nnonter; i++ {
+               n := 0;
+               c := i+NTBASE;
+               for j:=0; j<nprod; j++ {
+                       if prdptr[j][0] == c {
+                               curres[n] = prdptr[j][1:len(prdptr[j])];
+                               n++;
+                       }
+               }
+               if n == 0 {
+                       error("nonterminal %v not defined", nontrst[i].name);
+                       continue;
+               }
+               pres[i] = make([][]int, n);
+               for ll:=0; ll<n; ll++ {
+                       pres[i][ll] = curres[ll];
+               }
+       }
+       fatfl = 1;
+       if nerrors != 0 {
+               summary();
+               exit(1);
+       }
+}
+
+func
+dumppres()
+{
+       for i := 0; i <= nnonter; i++ {
+               print("nonterm %d\n", i);
+               curres := pres[i];
+               for j := 0; j < len(curres); j++ {
+                       print("\tproduction %d:", j);
+                       prd := curres[j];
+                       for k := 0; k < len(prd); k++ {
+                               print(" %d", prd[k]);
+                       }
+                       print("\n");
+               }
+       }
+}
+
+//
+// mark nonterminals which derive the empty string
+// also, look for nonterminals which don't derive any token strings
+//
+func
+cempty()
+{
+       var i, p, np int;
+       var prd []int;
+
+       pempty = make([]int, nnonter+1);
+
+       // 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:
+       for {
+               for i=0; i<nprod; i++ {
+                       prd = prdptr[i];
+                       if pempty[prd[0] - NTBASE] != 0 {
+                               continue;
+                       }
+                       np = len(prd) - 1;
+                       for p = 1; p < np; p++ {
+                               if prd[p] >= NTBASE && pempty[prd[p]-NTBASE] == WHOKNOWS {
+                                       break;
+                               }
+                       }
+                       // production can be derived
+                       if p == np {
+                               pempty[prd[0]-NTBASE] = OK;
+                               continue more;
+                       }
+               }
+               break;
+       }
+
+       // now, look at the nonterminals, to see if they are all OK
+       for i=0; i<=nnonter; i++ {
+               // the added production rises or falls as the start symbol ...
+               if i == 0 {
+                       continue;
+               }
+               if pempty[i] != OK {
+                       fatfl = 0;
+                       error("nonterminal " + nontrst[i].name + " never derives any token string");
+               }
+       }
+
+       if nerrors != 0 {
+               summary();
+               exit(1);
+       }
+
+       // 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:
+       for {
+           next:
+               for i=1; i<nprod; i++ {
+                       // not known to be empty
+                       prd = prdptr[i];
+                       if pempty[prd[0]-NTBASE] != WHOKNOWS {
+                               continue;
+                       }
+                       np = len(prd) - 1;
+                       for p = 1; p < np; p++ {
+                               if prd[p] < NTBASE || pempty[prd[p]-NTBASE] != EMPTY {
+                                       continue next;
+                               }
+                       }
+
+                       // we have a nontrivially empty nonterminal
+                       pempty[prd[0]-NTBASE] = EMPTY;
+
+                       // got one ... try for another
+                       continue again;
+               }
+               return;
+       }
+}
+
+func
+dumpempty()
+{
+       for i := 0; i <= nnonter; i++ {
+               if pempty[i] == EMPTY {
+                       print("non-term %d %s matches empty\n", i, symnam(i+NTBASE));
+               }
+       }
+}
+
+//
+// compute an array with the first of nonterminals
+//
+func
+cpfir()
+{
+       var s, n, p, np, ch, i int;
+       var curres [][]int;
+       var prd []int;
+
+       wsets = make([]Wset, nnonter+WSETINC);
+       pfirst = make([]Lkset, nnonter+1);
+       for i=0; i<=nnonter; i++ {
+               wsets[i].ws = mkset();
+               pfirst[i] = mkset();
+               curres = pres[i];
+               n = len(curres);
+
+               // initially fill the sets
+               for s = 0; s < n; s++ {
+                       prd = curres[s];
+                       np = len(prd) - 1;
+                       for p = 0; p < np; p++ {
+                               ch = prd[p];
+                               if ch < NTBASE {
+                                       setbit(pfirst[i], ch);
+                                       break;
+                               }
+                               if pempty[ch-NTBASE] == 0 {
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       // now, reflect transitivity
+       changes := 1;
+       for changes != 0 {
+               changes = 0;
+               for i=0; i<=nnonter; i++ {
+                       curres = pres[i];
+                       n = len(curres);
+                       for s = 0; s < n; s++ {
+                               prd = curres[s];
+                               np = len(prd) - 1;
+                               for p = 0; p < np; p++ {
+                                       ch = prd[p] - NTBASE;
+                                       if ch < 0 {
+                                               break;
+                                       }
+                                       changes |= setunion(pfirst[i], pfirst[ch]);
+                                       if pempty[ch] == 0 {
+                                               break;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       if indebug == 0 {
+               return;
+       }
+       if foutput != nil {
+               for i=0; i<=nnonter; i++ {
+                       fmt.Fprintf(foutput, "\n%v: %v %v\n",
+                               nontrst[i].name, pfirst[i], pempty[i]);
+               }
+       }
+}
+
+//
+// generate the states
+//
+func
+stagen()
+{
+       // initialize
+       nstate = 0;
+       tstates = make([]int, ntokens+1);       // states generated by terminal gotos
+       ntstates = make([]int, nnonter+1);      // states generated by nonterminal gotos
+       amem = make([]int, ACTSIZE);
+       memp = 0;
+
+       clset = mkset();
+       pstate[0] = 0;
+       pstate[1] = 0;
+       aryfil(clset, tbitset, 0);
+       putitem(Pitem{prdptr[0], 0, 0, 0}, clset);
+       tystate[0] = MUSTDO;
+       nstate = 1;
+       pstate[2] = pstate[1];
+
+       //
+       // now, the main state generation loop
+       // first pass generates all of the states
+       // later passes fix up lookahead
+       // could be sped up a lot by remembering
+       // results of the first pass rather than recomputing
+       //
+       first := 1;
+       for more := 1; more != 0; first = 0 {
+               more = 0;
+               for i:=0; i<nstate; 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
+                       for p:=0; p<cwp; p++ {
+                               pi := wsets[p];
+                               if pi.flag != 0 {
+                                       continue;
+                               }
+                               wsets[p].flag = 1;
+                               c := pi.pitem.first;
+                               if c <= 1 {
+                                       if pstate[i+1]-pstate[i] <= p {
+                                               tystate[i] = MUSTLOOKAHEAD;
+                                       }
+                                       continue;
+                               }
+
+                               // do a goto on c
+                               putitem(wsets[p].pitem, wsets[p].ws);
+                               for q:=p+1; q<cwp; q++ {
+                                       // this item contributes to the goto
+                                       if c == wsets[q].pitem.first {
+                                               putitem(wsets[q].pitem, wsets[q].ws);
+                                               wsets[q].flag = 1;
+                                       }
+                               }
+
+                               if c < NTBASE {
+                                       state(c);       // register new state
+                               } else
+                                       temp1[c-NTBASE] = state(c);
+                       }
+
+                       if gsdebug != 0 && foutput != nil {
+                               fmt.Fprintf(foutput, "%v: ", i);
+                               for j:=0; j<=nnonter; j++ {
+                                       if temp1[j] != 0 {
+                                               fmt.Fprintf(foutput, "%v %v,", nontrst[j].name, temp1[j]);
+                                       }
+                               }
+                               fmt.Fprintf(foutput, "\n");
+                       }
+
+                       if first != 0 {
+                               indgo[i] = apack(temp1[1:len(temp1)], nnonter-1) - 1;
+                       }
+
+                       more++;
+               }
+       }
+}
+
+//
+// generate the closure of state i
+//
+func
+closure(i int)
+{
+       zzclose++;
+
+       // first, copy kernel of state i to wsets
+       cwp = 0;
+       q := pstate[i+1];
+       for p:=pstate[i]; p<q; p++ {
+               wsets[cwp].pitem = statemem[p].pitem;
+               wsets[cwp].flag = 1;                    // this item must get closed
+               for ll:=0; ll<len(wsets[cwp].ws); ll++ {
+                       wsets[cwp].ws[ll] = statemem[p].look[ll];
+               }
+               cwp++;
+       }
+
+       // now, go through the loop, closing each item
+       work := 1;
+       for work != 0 {
+               work = 0;
+               for u:=0; u<cwp; u++ {
+                       if wsets[u].flag == 0 {
+                               continue;
+                       }
+
+                       // dot is before c
+                       c := wsets[u].pitem.first;
+                       if c < NTBASE {
+                               wsets[u].flag = 0;
+                               // only interesting case is where . is before nonterminal
+                               continue;
+                       }
+
+                       // compute the lookahead
+                       aryfil(clset, tbitset, 0);
+
+                       // find items involving c
+                       for v:=u; v<cwp; v++ {
+                               if wsets[v].flag != 1 || wsets[v].pitem.first != c {
+                                       continue;
+                               }
+                               pi := wsets[v].pitem.prod;
+                               ipi := wsets[v].pitem.off + 1;
+                               
+                               wsets[v].flag = 0;
+                               if nolook != 0 {
+                                       continue;
+                               }
+
+                               ch := pi[ipi];
+                               ipi++;
+                               for ch > 0 {
+                                       // terminal symbol
+                                       if ch < NTBASE {
+                                               setbit(clset, ch);
+                                               break;
+                                       }
+
+                                       // nonterminal symbol
+                                       setunion(clset, pfirst[ch-NTBASE]);
+                                       if pempty[ch-NTBASE] == 0 {
+                                               break;
+                                       }
+                                       ch = pi[ipi];
+                                       ipi++;
+                               }
+                               if ch <= 0 {
+                                       setunion(clset, wsets[v].ws);
+                               }
+                       }
+
+                       //
+                       // now loop over productions derived from c
+                       //
+                       curres := pres[c-NTBASE];
+                       n := len(curres);
+
+                   nexts:
+                       // initially fill the sets
+                       for s := 0; s < n; s++ {
+                               prd := curres[s];
+
+                               //
+                               // put these items into the closure
+                               // is the item there
+                               //
+                               for v:=0; v<cwp; v++ {
+                                       // yes, it is there
+                                       if wsets[v].pitem.off == 0 &&
+                                          aryeq(wsets[v].pitem.prod, prd) != 0 {
+                                               if nolook == 0 &&
+                                                  setunion(wsets[v].ws, clset) != 0 {
+                                                       wsets[v].flag = 1;
+                                                       work = 1;
+                                               }
+                                               continue nexts;
+                                       }
+                               }
+
+                               //  not there; make a new entry
+                               if cwp >= len(wsets) {
+                                       awsets := make([]Wset, cwp+WSETINC);
+                                       for ll:=0; ll<len(wsets); ll++ {
+                                               awsets[ll] = wsets[ll];
+                                       }
+                                       wsets = awsets;
+                               }
+                               wsets[cwp].pitem = Pitem{prd, 0, prd[0], -prd[len(prd)-1]};
+                               wsets[cwp].flag = 1;
+                               wsets[cwp].ws = mkset();
+                               if nolook == 0 {
+                                       work = 1;
+                                       for ll:=0; ll<len(wsets[cwp].ws); ll++ {
+                                               wsets[cwp].ws[ll] = clset[ll];
+                                       }
+                               }
+                               cwp++;
+                       }
+               }
+       }
+
+       // have computed closure; flags are reset; return
+       if cldebug != 0 && foutput != nil {
+               fmt.Fprintf(foutput, "\nState %v, nolook = %v\n", i, nolook);
+               for u:=0; u<cwp; u++ {
+                       if wsets[u].flag != 0 {
+                               fmt.Fprintf(foutput, "flag set\n");
+                       }
+                       wsets[u].flag = 0;
+                       fmt.Fprintf(foutput, "\t%v", writem(wsets[u].pitem));
+                       prlook(wsets[u].ws);
+                       fmt.Fprintf(foutput, "\n");
+               }
+       }
+}
+
+//
+// sorts last state,and sees if it equals earlier ones. returns state number
+//
+func
+state(c int) int
+{
+       zzstate++;
+       p1 := pstate[nstate];
+       p2 := pstate[nstate+1];
+       if p1 == p2 {
+               return 0;       // null state
+       }
+
+       // sort the items
+       var k, l int;
+       for k = p1+1; k < p2; k++ {     // make k the biggest
+               for l = k; l > p1; l-- {
+                       if(statemem[l].pitem.prodno < statemem[l-1].pitem.prodno ||
+                          statemem[l].pitem.prodno == statemem[l-1].pitem.prodno &&
+                          statemem[l].pitem.off < statemem[l-1].pitem.off) {
+                               s := statemem[l];
+                               statemem[l] = statemem[l-1];
+                               statemem[l-1] = s;
+                       } else
+                               break;
+               }
+       }
+
+       size1 := p2 - p1;       // size of state
+
+       var i int;
+       if c >= NTBASE {
+               i = ntstates[c-NTBASE];
+       } else
+               i = tstates[c];
+
+    look:
+       for ; 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 aryeq(statemem[l].pitem.prod, statemem[k].pitem.prod) == 0 ||
+                          statemem[l].pitem.off != statemem[k].pitem.off {
+                               continue look;
+                       }
+                       k++;
+               }
+
+               // found it
+               pstate[nstate+1] = pstate[nstate];      // delete last state
+
+               // fix up lookaheads
+               if nolook != 0 {
+                       return i;
+               }
+               k = p1;
+               for l = q1; l < q2; l++ {
+                       if setunion(statemem[l].look, statemem[k].look) != 0 {
+                               tystate[i] = MUSTDO;
+                       }
+                       k++;
+               }
+               return i;
+       }
+
+       // state is new
+       zznewstate++;
+       if nolook != 0 {
+               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;
+       nstate++;
+       return nstate-1;
+}
+
+func
+putitem(p Pitem, set Lkset)
+{
+       p.off++;
+       p.first = p.prod[p.off];
+
+       if pidebug != 0 && foutput != nil {
+               fmt.Fprintf(foutput, "putitem(%v), state %v\n", writem(p), nstate);
+       }
+       j := pstate[nstate+1];
+       if j >= len(statemem) {
+               asm := make([]Item, j+STATEINC);
+               for ll:=0; ll<len(statemem); ll++ {
+                       asm[ll] = statemem[ll];
+               }
+               statemem = asm;
+       }
+       statemem[j].pitem = p;
+       if nolook == 0 {
+               s := mkset();
+               for ll:=0; ll<len(set); ll++ {
+                       s[ll] = set[ll];
+               }
+               statemem[j].look = s;
+       }
+       j++;
+       pstate[nstate+1] = j;
+}
+
+//
+// creates output string for item pointed to by pp
+//
+func
+writem(pp Pitem) string
+{
+       var i int;
+
+       p := pp.prod;
+       q := chcopy(nontrst[prdptr[pp.prodno][0]-NTBASE].name) + ": ";
+       npi := pp.off;
+
+       pi := aryeq(p, prdptr[pp.prodno]);
+
+       for {
+               c := ' ';
+               if pi == npi {
+                       c = '.';
+               }
+               q += string(c);
+
+               i = p[pi];
+               pi++;
+               if i <= 0 {
+                       break;
+               }
+               q += chcopy(symnam(i));
+       }
+
+       // an item calling for a reduction
+       i = p[npi];
+       if i < 0 {
+               q += fmt.Sprintf("    (%v)", -i);
+       }
+
+       return q;
+}
+
+//
+// pack state i from temp1 into amem
+//
+func
+apack(p []int, n int) int
+{
+       //
+       // 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
+       //
+       off := 0;
+       pp := 0;
+       for ; pp <= n && p[pp] == 0; pp++ {
+               off--;
+       }
+
+       // no actions
+       if pp > n {
+               return 0;
+       }
+       for ; n > pp && p[n] == 0; n-- {
+       }
+       p = p[pp:n+1];
+
+       // now, find a place for the elements from p to q, inclusive
+       r := len(amem) - len(p);
+
+    nextk:
+       for rr := 0; rr <= r; rr++ {
+               qq := rr;
+               for pp = 0; pp < len(p); pp++ {
+                       if p[pp] != 0 {
+                               if p[pp] != amem[qq] && amem[qq] != 0 {
+                                       continue nextk;
+                               }
+                       }
+                       qq++;
+               }
+
+               // we have found an acceptable k
+               if pkdebug != 0 && foutput != nil {
+                       fmt.Fprintf(foutput, "off = %v, k = %v\n", off+rr, rr);
+               }
+               qq = rr;
+               for pp = 0; pp < len(p); pp++ {
+                       if p[pp] != 0 {
+                               if qq > memp {
+                                       memp = qq;
+                               }
+                               amem[qq] = p[pp];
+                       }
+                       qq++;
+               }
+               if pkdebug != 0 && foutput != nil {
+                       for pp = 0; pp <= memp; pp += 10 {
+                               fmt.Fprintf(foutput, "\n");
+                               for qq = pp; qq <= pp+9; qq++ {
+                                       fmt.Fprintf(foutput, "%v ", amem[qq]);
+                               }
+                               fmt.Fprintf(foutput, "\n");
+                       }
+               }
+               return off + rr;
+       }
+       error("no space in action table");
+       return 0;
+}
+
+//
+// print the output for the states
+//
+func
+output()
+{
+       var c, u, v int;
+
+       fmt.Fprintf(ftable, "var\tYYEXCA = []int {\n");
+
+       noset := mkset();
+
+       // output the stuff for state i
+       for i:=0; i<nstate; i++ {
+               nolook = 0;
+               if tystate[i] != MUSTLOOKAHEAD {
+                       nolook = 1;
+               }
+               closure(i);
+
+               // output actions
+               nolook = 1;
+               aryfil(temp1, ntokens+nnonter+1, 0);
+               for u=0; u<cwp; u++ {
+                       c = wsets[u].pitem.first;
+                       if c > 1 && c < NTBASE && temp1[c] == 0 {
+                               for v=u; v<cwp; v++ {
+                                       if c == wsets[v].pitem.first {
+                                               putitem(wsets[v].pitem, noset);
+                                       }
+                               }
+                               temp1[c] = state(c);
+                       } else
+                       if c > NTBASE {
+                               c -= NTBASE;
+                               if temp1[c + 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;
+               for u=0; u<cwp; u++ {
+                       c = wsets[u].pitem.first;
+
+                       // reduction
+                       if c > 0 {
+                               continue;
+                       }
+                       lastred = -c;
+                       us := wsets[u].ws;
+                       for k:=0; k<=ntokens; k++ {
+                               if bitset(us, k) == 0 {
+                                       continue;
+                               }
+                               if temp1[k] == 0 {
+                                       temp1[k] = c;
+                               } else
+                               if temp1[k] < 0 { // reduce/reduce conflict
+                                       if foutput != nil {
+                                               fmt.Fprintf(foutput, 
+                                                       "\n %v: reduce/reduce conflict  (red'ns "
+                                                       "%v and %v) on %v",
+                                                       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);
+       }
+
+       fmt.Fprintf(ftable, "}\n");
+       fmt.Fprintf(ftable, "const\tYYNPROD\t= %v\n", nprod);
+       fmt.Fprintf(ftable, "const\tYYPRIVATE\t= %v\n", PRIVATE);
+       fmt.Fprintf(ftable, "var\tYYTOKENNAMES []string\n");
+       fmt.Fprintf(ftable, "var\tYYSTATES\n[]string\n");
+}
+
+//
+// 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
+//
+func
+precftn(r, t, s int)
+{
+       var action int;
+
+       lp := levprd[r];
+       lt := toklev[t];
+       if PLEVEL(lt) == 0 || PLEVEL(lp) == 0 {
+               // conflict
+               if foutput != nil {
+                       fmt.Fprintf(foutput, 
+                               "\n%v: shift/reduce conflict (shift %v(%v), red'n %v(%v)) on %v",
+                               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;
+       case LASC:  // reduce
+               temp1[t] = -r;
+       }
+}
+
+//
+// output state i
+// temp1 has the actions, lastred the default
+//
+func
+wract(i int)
+{
+       var p, p1 int;
+
+       // find the best choice for lastred
+       lastred = 0;
+       ntimes := 0;
+       for j:=0; j<=ntokens; 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;
+               for p=0; p<=ntokens; 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
+       // count entries in optst table
+       n := 0;
+       for p=0; p<=ntokens; p++ {
+               p1 = temp1[p];
+               if p1+lastred == 0 {
+                       temp1[p] = 0;
+                       p1 = 0;
+               }
+               if p1 > 0 && p1 != ACCEPTCODE && p1 != ERRCODE {
+                       n++;
+               }
+       }
+
+       wrstate(i);
+       defact[i] = lastred;
+       flag := 0;
+       os := make([]int, n*2);
+       n = 0;
+       for p=0; p<=ntokens; p++ {
+               p1 = temp1[p];
+               if p1 != 0 {
+                       if p1 < 0 {
+                               p1 = -p1;
+                       } else
+                       if p1 == ACCEPTCODE {
+                               p1 = -1;
+                       } else
+                       if p1 == ERRCODE {
+                               p1 = 0;
+                       } else {
+                               os[n] = p;
+                               n++;
+                               os[n] = p1;
+                               n++;
+                               zzacent++;
+                               continue;
+                       }
+                       if flag == 0 {
+                               fmt.Fprintf(ftable, "-1, %v,\n", i);
+                       }
+                       flag++;
+                       fmt.Fprintf(ftable, "\t%v, %v,\n", p, p1);
+                       zzexcp++;
+               }
+       }
+       if flag != 0 {
+               defact[i] = -2;
+               fmt.Fprintf(ftable, "\t-2, %v,\n", lastred);
+       }
+       optst[i] = os;
+}
+
+//
+// writes state i
+//
+func
+wrstate(i int)
+{
+       var j0, j1, u int;
+       var pp, qq int;
+
+       if foutput == nil {
+               return;
+       }
+       fmt.Fprintf(foutput, "\nstate %v\n", i);
+       qq = pstate[i+1];
+       for pp=pstate[i]; pp<qq; pp++ {
+               fmt.Fprintf(foutput, "\t%v\n", writem(statemem[pp].pitem));
+       }
+       if tystate[i] == MUSTLOOKAHEAD {
+               // print out empty productions in closure
+               for u = pstate[i+1] - pstate[i]; u < cwp; u++ {
+                       if wsets[u].pitem.first < 0 {
+                               fmt.Fprintf(foutput, "\t%v\n", writem(wsets[u].pitem));
+                       }
+               }
+       }
+
+       // check for state equal to another
+       for j0=0; j0<=ntokens; j0++ {
+               j1 = temp1[j0];
+               if j1 != 0 {
+                       fmt.Fprintf(foutput, "\n\t%v  ", symnam(j0));
+
+                       // shift, error, or accept
+                       if j1 > 0 {
+                               if j1 == ACCEPTCODE {
+                                       fmt.Fprintf(foutput, "accept");
+                               } else
+                               if j1 == ERRCODE {
+                                       fmt.Fprintf(foutput, "error");
+                               } else
+                                       fmt.Fprintf(foutput, "shift %v", j1);
+                       } else
+                               fmt.Fprintf(foutput, "reduce %v (src line %v)", -j1, rlines[-j1]);
+               }
+       }
+
+       // output the final production
+       if lastred != 0 {
+               fmt.Fprintf(foutput, "\n\t.  reduce %v (src line %v)\n\n",
+                       lastred, rlines[lastred]);
+       } else
+               fmt.Fprintf(foutput, "\n\t.  error\n\n");
+
+       // now, output nonterminal actions
+       j1 = ntokens;
+       for j0 = 1; j0 <= nnonter; j0++ {
+               j1++;
+               if temp1[j1] != 0 {
+                       fmt.Fprintf(foutput, "\t%v  goto %v\n", symnam(j0+NTBASE), temp1[j1]);
+               }
+       }
+}
+
+//
+// output the gotos for the nontermninals
+//
+func
+go2out()
+{
+       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;
+               n := 0;
+               for j := 0; j < nstate; j++ {
+                       if tystate[j] != 0 && tystate[j] != best {
+                               n++;
+                       }
+               }
+               goent := make([]int, 2*n+1);
+               n = 0;
+               for j := 0; j < nstate; j++ {
+                       if tystate[j] != 0 && tystate[j] != best {
+                               goent[n] = j;
+                               n++;
+                               goent[n] = tystate[j];
+                               n++;
+                               zzgoent++;
+                       }
+               }
+
+               // now, the default
+               if best == -1 {
+                       best = 0;
+               }
+
+               zzgoent++;
+               goent[n] = best;
+               yypgo[i] = goent;
+       }
+}
+
+//
+// output the gotos for nonterminal c
+//
+func
+go2gen(c int)
+{
+       var i, cc, p, q int;
+
+       // first, find nonterminals with gotos on c
+       aryfil(temp1, nnonter+1, 0);
+       temp1[c] = 1;
+       work := 1;
+       for work != 0 {
+               work = 0;
+               for i=0; i<nprod; i++ {
+                       // cc is a nonterminal with a goto on c
+                       cc = prdptr[i][1]-NTBASE;
+                       if cc >= 0 && temp1[cc] != 0 {
+                               // thus, the left side of production i does too
+                               cc = prdptr[i][0]-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 != 0 && foutput != nil {
+               fmt.Fprintf(foutput, "%v: gotos on ", nontrst[c].name);
+               for i=0; i<=nnonter; i++ {
+                       if temp1[i] != 0 {
+                               fmt.Fprintf(foutput, "%v ", nontrst[i].name);
+                       }
+               }
+               fmt.Fprintf(foutput, "\n");
+       }
+
+       // now, go through and put gotos into tystate
+       aryfil(tystate, nstate, 0);
+       for i=0; i<nstate; i++ {
+               q = pstate[i+1];
+               for p=pstate[i]; p<q; p++ {
+                       cc = statemem[p].pitem.first;
+                       if cc >= NTBASE {
+                               // goto on c is possible
+                               if temp1[cc-NTBASE] != 0 {
+                                       tystate[i] = amem[indgo[i]+c];
+                                       break;
+                               }
+                       }
+               }
+       }
+}
+
+//
+// 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.
+//
+func
+hideprod()
+{
+       nred := 0;
+       levprd[0] = 0;
+       for i:=1; i<nprod; i++ {
+               if (levprd[i] & REDFLAG) == 0 {
+                       if foutput != nil {
+                               fmt.Fprintf(foutput, "Rule not reduced: %v\n",
+                                       writem(Pitem{prdptr[i], 0, 0, i}));
+                       }
+                       fmt.Printf("rule %v never reduced\n", writem(Pitem{prdptr[i], 0, 0, i}));
+                       nred++;
+               }
+               levprd[i] = prdptr[i][0] - NTBASE;
+       }
+       if nred != 0 {
+               fmt.Printf("%v rules never reduced\n", nred);
+       }
+}
+
+func
+callopt()
+{
+       var j, k, p, q, i int;
+       var v []int;
+
+       pgo = make([]int, nnonter+1);
+       pgo[0] = 0;
+       maxoff = 0;
+       maxspr = 0;
+       for i = 0; i < nstate; i++ {
+               k = 32000;
+               j = 0;
+               v = optst[i];
+               q = len(v);
+               for p = 0; p < q; p += 2 {
+                       if v[p] > j {
+                               j = v[p];
+                       }
+                       if v[p] < k {
+                               k = v[p];
+                       }
+               }
+
+               // nontrivial situation
+               if k <= j {
+                       // j is now the range
+//                     j -= k;                 // call scj
+                       if k > maxoff {
+                               maxoff = k;
+                       }
+               }
+               tystate[i] = q + 2*j;
+               if j > maxspr {
+                       maxspr = j;
+               }
+       }
+
+       // initialize ggreed table
+       ggreed = make([]int, nnonter+1);
+       for i = 1; i <= nnonter; i++ {
+               ggreed[i] = 1;
+               j = 0;
+
+               // minimum entry index is always 0
+               v = yypgo[i];
+               q = len(v) - 1;
+               for p = 0; p < q ; p += 2 {
+                       ggreed[i] += 2;
+                       if v[p] > j {
+                               j = v[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 = 0;
+       for i = 0; i < nstate; i++ {
+               if tystate[i] == 0 && adb > 1 {
+                       fmt.Fprintf(ftable, "State %v: null\n", i);
+               }
+               indgo[i] = YYFLAG;
+       }
+
+       i = nxti();
+       for i != NOMORE {
+               if i >= 0 {
+                       stin(i);
+               } else
+                       gin(-i);
+               i = nxti();
+       }
+
+       // print amem array
+       if adb > 2 {
+               for p = 0; p <= maxa; p += 10 {
+                       fmt.Fprintf(ftable, "%v  ", p);
+                       for i = 0; i < 10; i++ {
+                               fmt.Fprintf(ftable, "%v  ", amem[p+i]);
+                       }
+                       putrune(ftable, '\n');
+               }
+       }
+
+       aoutput();
+       osummary();
+}
+
+//
+// finds the next i
+//
+func
+nxti() int
+{
+       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 max == 0 {
+               return NOMORE;
+       }
+       return maxi;
+}
+
+func
+gin(i int)
+{
+       var s int;
+
+       // enter gotos on nonterminal i into array amem
+       ggreed[i] = 0;
+
+       q := yypgo[i];
+       nq := len(q) - 1;
+
+       // now, find amem place for it
+    nextgp:
+       for p := 0; p < ACTSIZE; p++ {
+               if amem[p] != 0 {
+                       continue;
+               }
+               for r := 0; r < nq; r += 2 {
+                       s = p + q[r] + 1;
+                       if s > maxa {
+                               maxa = s;
+                               if maxa >= ACTSIZE {
+                                       error("a array overflow");
+                               }
+                       }
+                       if amem[s] != 0 {
+                               continue nextgp;
+                       }
+               }
+
+               // we have found amem spot
+               amem[p] = q[nq];
+               if p > maxa {
+                       maxa = p;
+               }
+               for r := 0; r < nq; r += 2 {
+                       s = p + q[r] + 1;
+                       amem[s] = q[r+1];
+               }
+               pgo[i] = p;
+               if adb > 1 {
+                       fmt.Fprintf(ftable, "Nonterminal %v, entry at %v\n", i, pgo[i]);
+               }
+               return;
+       }
+       error("cannot place goto %v\n", i);
+}
+
+func
+stin(i int)
+{
+       var s int;
+
+       tystate[i] = 0;
+
+       // enter state i into the amem array
+       q := optst[i];
+       nq := len(q);
+
+    nextn:
+       // find an acceptable place
+       for n := -maxoff; n < ACTSIZE; n++ {
+               flag := 0;
+               for r := 0; r < nq; r += 2 {
+                       s = q[r] + n;
+                       if s < 0 || s > ACTSIZE {
+                               continue nextn;
+                       }
+                       if amem[s] == 0 {
+                               flag++;
+                       } else
+                       if amem[s] != q[r+1] {
+                               continue nextn;
+                       }
+               }
+
+               // check 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 != 0 {
+                                       continue nextn;
+                               }
+                               if nq == len(optst[j]) {
+
+                                       // states are equal
+                                       indgo[i] = n;
+                                       if adb > 1 {
+                                               fmt.Fprintf(ftable, "State %v: entry at"
+                                                       "%v equals state %v\n", i, n, j);
+                                       }
+                                       return;
+                               }
+
+                               // we have some disagreement
+                               continue nextn;
+                       }
+               }
+
+               for r := 0; r < nq; r += 2 {
+                       s = q[r] + n;
+                       if s > maxa {
+                               maxa = s;
+                       }
+                       if amem[s] != 0 && amem[s] != q[r+1] {
+                               error("clobber of a array, pos'n %v, by %v", s, q[r+1]);
+                       }
+                       amem[s] = q[r+1];
+               }
+               indgo[i] = n;
+               if adb > 1 {
+                       fmt.Fprintf(ftable, "State %v: entry at %v\n", i, indgo[i]);
+               }
+               return;
+       }
+       error("Error; failure to place state %v", i);
+}
+
+//
+// this version is for limbo
+// write out the optimized parser
+//
+func
+aoutput()
+{
+       fmt.Fprintf(ftable, "const\tYYLAST\t= %v\n",maxa+1);
+       arout("YYACT", amem, maxa+1);
+       arout("YYPACT", indgo, nstate);
+       arout("YYPGO", pgo, nnonter+1);
+}
+
+//
+// put out other arrays, copy the parsers
+//
+func
+others()
+{
+       var i, j int;
+
+       arout("YYR1", levprd, nprod);
+       aryfil(temp1, nprod, 0);
+
+       //
+       //yyr2 is the number of rules for each production
+       //
+       for i=1; i<nprod; i++ {
+               temp1[i] = len(prdptr[i]) - 2;
+       }
+       arout("YYR2", temp1, nprod);
+
+       aryfil(temp1, nstate, -1000);
+       for i=0; i<=ntokens; i++ {
+               for j:=tstates[i]; j!=0; j=mstates[j] {
+                       temp1[j] = i;
+               }
+       }
+       for i=0; i<=nnonter; i++ {
+               for j=ntstates[i]; j!=0; j=mstates[j] {
+                       temp1[j] = -i;
+               }
+       }
+       arout("YYCHK", temp1, nstate);
+       arout("YYDEF", defact, nstate);
+
+       // put out token translation tables
+       // table 1 has 0-256
+       aryfil(temp1, 256, 0);
+       c := 0;
+       for i=1; i<=ntokens; i++ {
+               j = tokset[i].value;
+               if j >= 0 && j < 256 {
+                       if temp1[j] != 0 {
+                               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;
+                       }
+               }
+       }
+       for i = 0; i <= c; i++ {
+               if temp1[i] == 0 {
+                       temp1[i] = YYLEXUNK;
+               }
+       }
+       arout("YYTOK1", temp1, c+1);
+
+       // table 2 has PRIVATE-PRIVATE+256
+       aryfil(temp1, 256, 0);
+       c = 0;
+       for i=1; i<=ntokens; i++ {
+               j = tokset[i].value - PRIVATE;
+               if j >= 0 && j < 256 {
+                       if temp1[j] != 0 {
+                               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;
+                       }
+               }
+       }
+       arout("YYTOK2", temp1, c+1);
+
+       // table 3 has everything else
+       fmt.Fprintf(ftable, "var\tYYTOK3\t= []int {\n");
+       c = 0;
+       for i=1; i<=ntokens; i++ {
+               j = tokset[i].value;
+               if j >= 0 && j < 256 {
+                       continue;
+               }
+               if j >= PRIVATE && j < 256+PRIVATE {
+                       continue;
+               }
+
+               fmt.Fprintf(ftable, "%4d,%4d,", j, i);
+               c++;
+               if c%5 == 0 {
+                       putrune(ftable, '\n');
+               }
+       }
+       fmt.Fprintf(ftable, "%4d\n };\n", 0);
+
+       // copy parser text
+       c = getrune(finput);
+       for c != EOF {
+               putrune(ftable, c);
+               c = getrune(finput);
+       }
+
+       // copy yaccpar
+       fmt.Fprintf(ftable, "%v", yaccpar);
+}
+
+func
+arout(s string, v []int, n int)
+{
+       fmt.Fprintf(ftable, "var\t%v\t= []int {\n", s);
+       for i := 0; i < n; i++ {
+               if i%10 == 0 {
+                       putrune(ftable, '\n');
+               }
+               fmt.Fprintf(ftable, "%4d", v[i]);
+               putrune(ftable, ',');
+       }
+       fmt.Fprintf(ftable, "\n};\n");
+}
+
+//
+// output the summary on y.output
+//
+func
+summary()
+{
+       if(foutput != nil) {
+               fmt.Fprintf(foutput, "\n%v terminals, %v nonterminals\n", ntokens, nnonter+1);
+               fmt.Fprintf(foutput, "%v grammar rules, %v/%v states\n", nprod, nstate, NSTATES);
+               fmt.Fprintf(foutput, "%v shift/reduce, %v reduce/reduce conflicts reported\n", zzsrconf, zzrrconf);
+               fmt.Fprintf(foutput, "%v working sets used\n", len(wsets));
+               fmt.Fprintf(foutput, "memory: parser %v/%v\n", memp, ACTSIZE);
+               fmt.Fprintf(foutput, "%v extra closures\n", zzclose - 2*nstate);
+               fmt.Fprintf(foutput, "%v shift entries, %v exceptions\n", zzacent, zzexcp);
+               fmt.Fprintf(foutput, "%v goto entries\n", zzgoent);
+               fmt.Fprintf(foutput, "%v entries saved by goto default\n", zzgobest);
+       }
+       if zzsrconf != 0 || zzrrconf != 0 {
+               fmt.Printf("\nconflicts: ");
+               if zzsrconf != 0 {
+                       fmt.Printf("%v shift/reduce", zzsrconf);
+               }
+               if zzsrconf != 0 && zzrrconf != 0 {
+                       fmt.Printf(", ");
+               }
+               if zzrrconf != 0 {
+                       fmt.Printf("%v reduce/reduce", zzrrconf);
+               }
+               fmt.Printf("\n");
+       }
+}
+
+//
+// write optimizer summary
+//
+func
+osummary()
+{
+       if foutput == nil {
+               return;
+       }
+       i := 0;
+       for p := maxa; p >= 0; p-- {
+               if amem[p] == 0 {
+                       i++;
+               }
+       }
+
+       fmt.Fprintf(foutput, "Optimizer space used: output %v/%v\n", maxa+1, ACTSIZE);
+       fmt.Fprintf(foutput, "%v table entries, %v zero\n", maxa+1, i);
+       fmt.Fprintf(foutput, "maximum spread: %v, maximum offset: %v\n", maxspr, maxoff);
+}
+
+//
+// copies and protects "'s in q
+//
+func
+chcopy(q string) string
+{
+       s := "";
+       i := 0;
+       j := 0;
+       for i = 0; i < len(q); i++ {
+               if q[i] == '"' {
+                       s += q[j:i] + "\\";
+                       j = i;
+               }
+       }
+       return s + q[j:i];
+}
+
+func
+usage()
+{
+       fmt.Fprintf(stderr, "usage: gacc [-o output] [-v parsetable] input\n");
+       exit(1);
+}
+
+func
+bitset(set Lkset, bit int) int
+{
+       return set[bit>>5] & (1<<uint(bit&31));
+}
+
+func
+setbit(set Lkset, bit int)
+{
+       set[bit>>5] |= (1<<uint(bit&31));
+}
+
+func
+mkset() Lkset
+{
+       return make([]int, tbitset);
+}
+
+//
+// set a to the union of a and b
+// return 1 if b is not a subset of a, 0 otherwise
+//
+func
+setunion(a, b []int) int
+{
+       sub := 0;
+       for i:=0; i<tbitset; i++ {
+               x := a[i];
+               y := x | b[i];
+               a[i] = y;
+               if y != x {
+                       sub = 1;
+               }
+       }
+       return sub;
+}
+
+func
+prlook(p Lkset)
+{
+       if p == nil {
+               fmt.Fprintf(foutput, "\tNULL");
+               return;
+       }
+       fmt.Fprintf(foutput, " { ");
+       for j:=0; j<=ntokens; j++ {
+               if bitset(p, j) != 0 {
+                       fmt.Fprintf(foutput, "%v ", symnam(j));
+               }
+       }
+       fmt.Fprintf(foutput, "}");
+}
+
+//
+// utility routines
+//
+var    peekrune        int;
+
+func
+isdigit(c int) bool
+{
+       return c >= '0' && c <= '9';
+}
+
+func
+isword(c int) bool
+{
+       return c >= 0xa0 || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
+}
+
+func
+mktemp(t string) string
+{
+       return t;
+}
+
+//
+// return 1 if 2 arrays are equal
+// return 0 if not equal
+//
+func
+aryeq(a []int, b[]int) int
+{
+       n := len(a);
+       if len(b) != n {
+               return 0;
+       }
+       for ll:=0; ll<n; ll++ {
+               if a[ll] != b[ll] {
+                       return 0;
+               }
+       }
+       return 1;
+}
+
+func
+putrune(f *bufio.Writer, c int)
+{
+       s := string(c);
+       for i:=0; i<len(s); i++ {
+               f.WriteByte(s[i]);
+       }
+}
+
+func
+getrune(f *bufio.Reader) int
+{
+       var r int;
+
+       if peekrune != 0 {
+               if peekrune == EOF {
+                       return EOF;
+               }
+               r = peekrune;
+               peekrune = 0;
+               return r;
+       }
+
+       c,n,err := f.ReadRune();
+       if n == 0 {
+               return EOF;
+       }
+       if err != nil {
+               error("read error: %v", err);
+       }
+//fmt.Printf("rune = %v n=%v\n", string(c), n);
+       return c;
+}
+
+func
+ungetrune(f *bufio.Reader, c int)
+{
+       if f != finput {
+               panic("ungetc - not finput");
+       }
+       if peekrune != 0 {
+               panic("ungetc - 2nd unget");
+       }
+       peekrune = c;
+}
+
+func
+write(f *bufio.Writer, b []byte, n int) int
+{
+       println("write");
+       return 0;
+}
+
+func
+open(s string) *bufio.Reader
+{
+       fi,err := os.Open(s, os.O_RDONLY, 0);
+       if err != nil {
+               error("error opening %v: %v", s, err);
+       }
+//fmt.Printf("open %v\n", s);
+       return bufio.NewReader(fi);
+}
+
+func
+create(s string, m int) *bufio.Writer
+{
+       fo,err := os.Open(s, os.O_WRONLY|os.O_CREAT|os.O_TRUNC, m);
+       if err != nil {
+               error("error opening %v: %v", s, err);
+       }
+//fmt.Printf("create %v mode %v\n", s, m);
+       return bufio.NewWriter(fo);
+}
+
+//
+// write out error comment
+//
+func
+error(s string, v ...)
+{
+       nerrors++;
+       fmt.Fprintf(stderr, s, v);
+       fmt.Fprintf(stderr, ": %v:%v\n", infile, lineno);
+       if fatfl != 0 {
+               summary();
+               exit(1);
+       }
+}
+
+func
+exit(status int)
+{
+       if ftable != nil {
+               ftable.Flush();
+               ftable = nil;
+       }
+       if foutput != nil {
+               foutput.Flush();
+               foutput = nil;
+       }
+       if stderr != nil {
+               stderr.Flush();
+               stderr = nil;
+       }
+       os.Exit(status);
+}
+
+var    yaccpar =
+// from here to the end of the file is
+// a single string containing the old yaccpar file
+`
+/*     parser for yacc output  */
+
+var    Nerrs           = 0             /* number of errors */
+var    Errflag         = 0             /* error recovery flag */
+var    Debug           = 0
+const  YYFLAG          = -1000
+
+func
+Tokname(yyc int) string
+{
+       if yyc > 0 && yyc <= len(Toknames) {
+               if Toknames[yyc-1] != "" {
+                       return Toknames[yyc-1];
+               }
+       }
+       return fmt.Sprintf("tok-%v", yyc);
+}
+
+func
+Statname(yys int) string
+{
+       if yys >= 0 && yys < len(Statenames) {
+               if Statenames[yys] != "" {
+                       return Statenames[yys];
+               }
+       }
+       return fmt.Sprintf("state-%v", yys);
+}
+
+func
+lex1() int
+{
+       var yychar int;
+       var c int;
+
+       yychar = Lex();
+       if yychar <= 0 {
+               c = YYTOK1[0];
+               goto out;
+       }
+       if yychar < len(YYTOK1) {
+               c = YYTOK1[yychar];
+               goto out;
+       }
+       if yychar >= YYPRIVATE {
+               if yychar < YYPRIVATE+len(YYTOK2) {
+                       c = YYTOK2[yychar-YYPRIVATE];
+                       goto out;
+               }
+       }
+       for i:=0; i<len(YYTOK3); i+=2 {
+               c = YYTOK3[i+0];
+               if c == yychar {
+                       c = YYTOK3[i+1];
+                       goto out;
+               }
+       }
+       c = 0;
+
+out:
+       if c == 0 {
+               c = YYTOK2[1];  /* unknown char */
+       }
+       if Debug >= 3 {
+               fmt.Printf("lex %.4lux %s\n", yychar, Tokname(c));
+       }
+       return c;
+}
+
+func
+Parse() int
+{
+       var yyj, yystate, yyn, yyg, yyxi, yyp int;
+       var yychar int;
+       var yypt, yynt int;
+
+       yystate = 0;
+       yychar = -1;
+       Nerrs = 0;
+       Errflag = 0;
+       yyp = -1;
+       goto yystack;
+
+ret0:
+       return 0;
+
+ret1:
+       return 1;
+
+yystack:
+       /* put a state and value onto the stack */
+       if Debug >= 4 {
+               fmt.Printf("char %v in %v", Tokname(yychar), Statname(yystate));
+       }
+
+       yyp++;
+       if yyp >= len(YYS) {
+               Error("yacc stack overflow");
+               goto ret1;
+       }
+       YYS[yyp] = YYVAL;
+       YYS[yyp].yys = yystate;
+
+yynewstate:
+       yyn = YYPACT[yystate];
+       if yyn <= YYFLAG {
+               goto yydefault; /* simple state */
+       }
+       if yychar < 0 {
+               yychar = lex1();
+       }
+       yyn += yychar;
+       if yyn < 0 || yyn >= YYLAST {
+               goto yydefault;
+       }
+       yyn = YYACT[yyn];
+       if YYCHK[yyn] == yychar { /* valid shift */
+               yychar = -1;
+               YYVAL = yylval;
+               yystate = yyn;
+               if Errflag > 0 {
+                       Errflag--;
+               }
+               goto yystack;
+       }
+
+yydefault:
+       /* default state action */
+       yyn = YYDEF[yystate];
+       if yyn == -2 {
+               if yychar < 0 {
+                       yychar = lex1();
+               }
+
+               /* look through exception table */
+               for yyxi=0;; yyxi+=2 {
+                       if YYEXCA[yyxi+0] == -1 && YYEXCA[yyxi+1] == yystate {
+                               break;
+                       }
+               }
+               for yyxi += 2;; yyxi += 2 {
+                       yyn = YYEXCA[yyxi+0];
+                       if yyn < 0 || yyn == yychar {
+                               break;
+                       }
+               }
+               yyn = YYEXCA[yyxi+1];
+               if yyn < 0 {
+                       goto ret0;
+               }
+       }
+       if yyn == 0 {
+               /* error ... attempt to resume parsing */
+               switch Errflag {
+               case 0:   /* brand new error */
+                       Error("syntax error");
+                       Nerrs++;
+                       if Debug >= 1 {
+                               fmt.Printf("%s", Statname(yystate));
+                               fmt.Printf("saw %s\n", Tokname(yychar));
+                       }
+                       fallthrough;
+
+               case 1,2: /* incompletely recovered error ... try again */
+                       Errflag = 3;
+
+                       /* find a state where "error" is a legal shift action */
+                       for yyp >= len(YYS) {
+                               yyn = YYPACT[YYS[yyp].yys] + YYERRCODE;
+                               if yyn >= 0 && yyn < YYLAST {
+                                       yystate = YYACT[yyn];  /* simulate a shift of "error" */
+                                       if YYCHK[yystate] == YYERRCODE {
+                                               goto yystack;
+                                       }
+                               }
+
+                               /* the current yyp has no shift onn "error", pop stack */
+                               if Debug >= 2 {
+                                       fmt.Printf("error recovery pops state %d, uncovers %d\n",
+                                               YYS[yyp].yys, YYS[yyp-1].yys );
+                               }
+                               yyp--;
+                       }
+                       /* there is no state on the stack with an error shift ... abort */
+                       goto ret1;
+
+               case 3:  /* no shift yet; clobber input char */
+                       if Debug >= 2 {
+                               fmt.Printf("error recovery discards %s\n", Tokname(yychar));
+                       }
+                       if yychar == YYEOFCODE {
+                               goto ret1;
+                       }
+                       yychar = -1;
+                       goto yynewstate;   /* try again in the same state */
+               }
+       }
+
+       /* reduction by production yyn */
+       if Debug >= 2 {
+               fmt.Printf("reduce %v in:\n\t%v", yyn, Statname(yystate));
+       }
+
+       yynt = yyn;
+       yypt = yyp;
+
+       yyp -= YYR2[yyn];
+       YYVAL = YYS[yyp+1];
+
+       /* consult goto table to find next state */
+       yyn = YYR1[yyn];
+       yyg = YYPGO[yyn];
+       yyj = yyg + YYS[yyp].yys + 1;
+
+       if yyj >= YYLAST {
+               yystate = YYACT[yyg];
+       } else {
+               yystate = YYACT[yyj];
+               if YYCHK[yystate] != -yyn {
+                       yystate = YYACT[yyg];
+               }
+       }
+
+       yyrun(yynt, yypt);
+       goto yystack;  /* stack new state and value */
+}
+`