--- /dev/null
+/*
+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 */
+}
+`