|  | /* | 
|  | 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 ( | 
|  | "bufio" | 
|  | "bytes" | 
|  | "flag" | 
|  | "fmt" | 
|  | "go/format" | 
|  | "io/ioutil" | 
|  | "os" | 
|  | "strconv" | 
|  | "strings" | 
|  | "unicode" | 
|  | ) | 
|  |  | 
|  | // the following are adjustable | 
|  | // according to memory size | 
|  | const ( | 
|  | ACTSIZE  = 240000 | 
|  | NSTATES  = 16000 | 
|  | TEMPSIZE = 16000 | 
|  |  | 
|  | 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 | 
|  |  | 
|  | 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 | 
|  | ERROR | 
|  | ) | 
|  |  | 
|  | 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 fcode = &bytes.Buffer{} // saved code | 
|  | var foutput *bufio.Writer   // y.output file | 
|  |  | 
|  | var fmtImported bool // output file has recorded an import of "fmt" | 
|  |  | 
|  | 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 prefix string // name prefix for identifiers, default yy | 
|  |  | 
|  | func init() { | 
|  | flag.StringVar(&oflag, "o", "y.go", "parser output") | 
|  | flag.StringVar(&prefix, "p", "yy", "name prefix to use in generated code") | 
|  | flag.StringVar(&vflag, "v", "y.output", "create parsing tables") | 
|  | flag.BoolVar(&lflag, "l", false, "disable line directives") | 
|  | } | 
|  |  | 
|  | var initialstacksize = 16 | 
|  |  | 
|  | // 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 | 
|  | noconst bool | 
|  | value   int | 
|  | } | 
|  |  | 
|  | type Wset struct { | 
|  | pitem Pitem | 
|  | flag  int | 
|  | ws    Lkset | 
|  | } | 
|  |  | 
|  | // storage of types | 
|  | var ntypes int                     // number of types defined | 
|  | var typeset = make(map[int]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 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{ | 
|  | {"binary", BINARY}, | 
|  | {"left", LEFT}, | 
|  | {"nonassoc", BINARY}, | 
|  | {"prec", PREC}, | 
|  | {"right", RIGHT}, | 
|  | {"start", START}, | 
|  | {"term", TERM}, | 
|  | {"token", TERM}, | 
|  | {"type", TYPEDEF}, | 
|  | {"union", UNION}, | 
|  | {"struct", UNION}, | 
|  | {"error", ERROR}, | 
|  | } | 
|  |  | 
|  | type Error struct { | 
|  | lineno int | 
|  | tokens []string | 
|  | msg    string | 
|  | } | 
|  |  | 
|  | var errors []Error | 
|  |  | 
|  | type Row struct { | 
|  | actions       []int | 
|  | defaultAction int | 
|  | } | 
|  |  | 
|  | var stateTable []Row | 
|  |  | 
|  | var zznewstate = 0 | 
|  |  | 
|  | const EOF = -1 | 
|  |  | 
|  | 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.Stderr) | 
|  | foutput = nil | 
|  |  | 
|  | flag.Parse() | 
|  | if flag.NArg() != 1 { | 
|  | usage() | 
|  | } | 
|  | if initialstacksize < 1 { | 
|  | // never set so cannot happen | 
|  | fmt.Fprintf(stderr, "yacc: stack size too small\n") | 
|  | usage() | 
|  | } | 
|  | yaccpar = strings.Replace(yaccpartext, "$$", prefix, -1) | 
|  | openup() | 
|  |  | 
|  | fmt.Fprintf(ftable, "// Code generated by goyacc %s. DO NOT EDIT.\n", strings.Join(os.Args[1:], " ")) | 
|  |  | 
|  | 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: | 
|  | errorf("syntax error tok=%v", t-PRIVATE) | 
|  |  | 
|  | case MARK, ENDFILE: | 
|  | break outer | 
|  |  | 
|  | case ';': | 
|  | // Do nothing. | 
|  |  | 
|  | case START: | 
|  | t = gettok() | 
|  | if t != IDENTIFIER { | 
|  | errorf("bad %%start construction") | 
|  | } | 
|  | start = chfind(1, tokname) | 
|  |  | 
|  | case ERROR: | 
|  | lno := lineno | 
|  | var tokens []string | 
|  | for { | 
|  | t := gettok() | 
|  | if t == ':' { | 
|  | break | 
|  | } | 
|  | if t != IDENTIFIER && t != IDENTCOLON { | 
|  | errorf("bad syntax in %%error") | 
|  | } | 
|  | tokens = append(tokens, tokname) | 
|  | if t == IDENTCOLON { | 
|  | break | 
|  | } | 
|  | } | 
|  | if gettok() != IDENTIFIER { | 
|  | errorf("bad syntax in %%error") | 
|  | } | 
|  | errors = append(errors, Error{lno, tokens, tokname}) | 
|  |  | 
|  | case TYPEDEF: | 
|  | t = gettok() | 
|  | if t != TYPENAME { | 
|  | errorf("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 { | 
|  | errorf("type redeclaration of token %s", | 
|  | tokset[t].name) | 
|  | } else { | 
|  | toklev[t] = SETTYPE(toklev[t], ty) | 
|  | } | 
|  | } else { | 
|  | j = nontrst[t-NTBASE].value | 
|  | if j != 0 && j != ty { | 
|  | errorf("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 ';': | 
|  | // Do nothing. | 
|  |  | 
|  | case IDENTIFIER: | 
|  | j = chfind(0, tokname) | 
|  | if j >= NTBASE { | 
|  | errorf("%v defined earlier as nonterminal", tokname) | 
|  | } | 
|  | if lev != 0 { | 
|  | if ASSOC(toklev[j]) != 0 { | 
|  | errorf("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 { | 
|  | errorf("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 { | 
|  | errorf("unexpected EOF before %%") | 
|  | } | 
|  |  | 
|  | fmt.Fprintf(fcode, "switch %snt {\n", prefix) | 
|  |  | 
|  | moreprod() | 
|  | prdptr[0] = []int{NTBASE, start, 1, 0} | 
|  |  | 
|  | nprod = 1 | 
|  | curprod := make([]int, RULEINC) | 
|  | t = gettok() | 
|  | if t != IDENTCOLON { | 
|  | errorf("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 | 
|  | // followed by -nprod | 
|  |  | 
|  | for t != MARK && t != ENDFILE { | 
|  | mem := 0 | 
|  |  | 
|  | // process a rule | 
|  | rlines[nprod] = lineno | 
|  | ruleline := lineno | 
|  | if t == '|' { | 
|  | curprod[mem] = prdptr[nprod-1][0] | 
|  | mem++ | 
|  | } else if t == IDENTCOLON { | 
|  | curprod[mem] = chfind(1, tokname) | 
|  | if curprod[mem] < NTBASE { | 
|  | lerrorf(ruleline, "token illegal on LHS of grammar rule") | 
|  | } | 
|  | mem++ | 
|  | } else { | 
|  | lerrorf(ruleline, "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) | 
|  | copy(ncurprod, curprod) | 
|  | curprod = ncurprod | 
|  | } | 
|  | t = gettok() | 
|  | } | 
|  | if t == PREC { | 
|  | if gettok() != IDENTIFIER { | 
|  | lerrorf(ruleline, "illegal %%prec syntax") | 
|  | } | 
|  | j = chfind(2, tokname) | 
|  | if j >= NTBASE { | 
|  | lerrorf(ruleline, "nonterminal "+nontrst[j-NTBASE].name+" illegal after %%prec") | 
|  | } | 
|  | levprd[nprod] = toklev[j] | 
|  | t = gettok() | 
|  | } | 
|  | if t != '=' { | 
|  | break | 
|  | } | 
|  | levprd[nprod] |= ACTFLAG | 
|  | fmt.Fprintf(fcode, "\n\tcase %v:", nprod) | 
|  | fmt.Fprintf(fcode, "\n\t\t%sDollar = %sS[%spt-%v:%spt+1]", prefix, prefix, prefix, mem-1, prefix) | 
|  | 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) | 
|  | copy(ncurprod, curprod) | 
|  | 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 { | 
|  | lerrorf(ruleline, "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 { | 
|  | lerrorf(ruleline, "default action causes potential type clash") | 
|  | } | 
|  | } | 
|  | moreprod() | 
|  | prdptr[nprod] = make([]int, mem) | 
|  | copy(prdptr[nprod], curprod) | 
|  | nprod++ | 
|  | moreprod() | 
|  | levprd[nprod] = 0 | 
|  | } | 
|  |  | 
|  | if TEMPSIZE < ntokens+nnonter+1 { | 
|  | errorf("too many tokens (%d) or non-terminals (%d)", ntokens, nnonter) | 
|  | } | 
|  |  | 
|  | // | 
|  | // end of all rules | 
|  | // dump out the prefix code | 
|  | // | 
|  |  | 
|  | fmt.Fprintf(fcode, "\n\t}") | 
|  |  | 
|  | // put out non-literal terminals | 
|  | for i := TOKSTART; i <= ntokens; i++ { | 
|  | // non-literals | 
|  | if !tokset[i].noconst { | 
|  | fmt.Fprintf(ftable, "const %v = %v\n", tokset[i].name, tokset[i].value) | 
|  | } | 
|  | } | 
|  |  | 
|  | // put out names of tokens | 
|  | ftable.WriteRune('\n') | 
|  | fmt.Fprintf(ftable, "var %sToknames = [...]string{\n", prefix) | 
|  | for i := 1; i <= ntokens; i++ { | 
|  | fmt.Fprintf(ftable, "\t%q,\n", tokset[i].name) | 
|  | } | 
|  | fmt.Fprintf(ftable, "}\n") | 
|  |  | 
|  | // put out names of states. | 
|  | // commented out to avoid a huge table just for debugging. | 
|  | // re-enable to have the names in the binary. | 
|  | ftable.WriteRune('\n') | 
|  | fmt.Fprintf(ftable, "var %sStatenames = [...]string{\n", prefix) | 
|  | //	for i:=TOKSTART; i<=ntokens; i++ { | 
|  | //		fmt.Fprintf(ftable, "\t%q,\n", tokset[i].name); | 
|  | //	} | 
|  | fmt.Fprintf(ftable, "}\n") | 
|  |  | 
|  | ftable.WriteRune('\n') | 
|  | fmt.Fprintf(ftable, "const %sEofCode = 1\n", prefix) | 
|  | fmt.Fprintf(ftable, "const %sErrCode = 2\n", prefix) | 
|  | fmt.Fprintf(ftable, "const %sInitialStackSize = %v\n", prefix, initialstacksize) | 
|  |  | 
|  | // | 
|  | // 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 | 
|  | } | 
|  | ftable.WriteRune(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) | 
|  |  | 
|  | copy(aprod, prdptr) | 
|  | copy(alevprd, levprd) | 
|  | copy(arlines, rlines) | 
|  |  | 
|  | prdptr = aprod | 
|  | levprd = alevprd | 
|  | rlines = arlines | 
|  | } | 
|  | } | 
|  |  | 
|  | // | 
|  | // define s to be a terminal if nt==0 | 
|  | // or a nonterminal if nt==1 | 
|  | // | 
|  | func defin(nt int, s string) int { | 
|  | val := 0 | 
|  | if nt != 0 { | 
|  | nnonter++ | 
|  | if nnonter >= len(nontrst) { | 
|  | anontrst := make([]Symb, nnonter+SYMINC) | 
|  | copy(anontrst, nontrst) | 
|  | nontrst = anontrst | 
|  | } | 
|  | nontrst[nnonter] = Symb{name: s} | 
|  | return NTBASE + nnonter | 
|  | } | 
|  |  | 
|  | // must be a token | 
|  | ntokens++ | 
|  | if ntokens >= len(tokset) { | 
|  | nn := ntokens + SYMINC | 
|  | atokset := make([]Symb, nn) | 
|  | atoklev := make([]int, nn) | 
|  |  | 
|  | copy(atoklev, toklev) | 
|  | copy(atokset, tokset) | 
|  |  | 
|  | tokset = atokset | 
|  | toklev = atoklev | 
|  | } | 
|  | tokset[ntokens].name = s | 
|  | toklev[ntokens] = 0 | 
|  |  | 
|  | // establish value for token | 
|  | // single character literal | 
|  | if s[0] == '\'' || s[0] == '"' { | 
|  | q, err := strconv.Unquote(s) | 
|  | if err != nil { | 
|  | errorf("invalid token: %s", err) | 
|  | } | 
|  | rq := []rune(q) | 
|  | if len(rq) != 1 { | 
|  | errorf("character token too long: %s", s) | 
|  | } | 
|  | val = int(rq[0]) | 
|  | if val == 0 { | 
|  | errorf("token value 0 is illegal") | 
|  | } | 
|  | tokset[ntokens].noconst = true | 
|  | } else { | 
|  | val = extval | 
|  | extval++ | 
|  | if s[0] == '$' { | 
|  | tokset[ntokens].noconst = true | 
|  | } | 
|  | } | 
|  |  | 
|  | tokset[ntokens].value = val | 
|  | return ntokens | 
|  | } | 
|  |  | 
|  | var peekline = 0 | 
|  |  | 
|  | func gettok() int { | 
|  | var i int | 
|  | var match, c rune | 
|  |  | 
|  | 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 != '>' { | 
|  | errorf("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 = string(c) | 
|  | for { | 
|  | c = getrune(finput) | 
|  | if c == '\n' || c == EOF { | 
|  | errorf("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) | 
|  | } | 
|  | tokname += string(c) | 
|  | 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 i := range resrv { | 
|  | if tokname == resrv[i].name { | 
|  | if tokflag { | 
|  | fmt.Printf(">>> %%%v %v %v\n", tokname, | 
|  | resrv[i].value-PRIVATE, lineno) | 
|  | } | 
|  | return resrv[i].value | 
|  | } | 
|  | } | 
|  | errorf("invalid escape, or illegal reserved word: %v", tokname) | 
|  |  | 
|  | case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': | 
|  | numbval = int(c - '0') | 
|  | for { | 
|  | c = getrune(finput) | 
|  | if !isdigit(c) { | 
|  | break | 
|  | } | 
|  | numbval = numbval*10 + int(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 int(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 rune) { | 
|  | tokname = "" | 
|  | for isword(c) || isdigit(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 { | 
|  | errorf("must specify type for %v", s) | 
|  | } | 
|  | return v | 
|  | } | 
|  |  | 
|  | func chfind(t int, s string) int { | 
|  | if s[0] == '"' || 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 { | 
|  | errorf("%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", infile, lineno) | 
|  | } | 
|  | fmt.Fprintf(ftable, "type %sSymType struct", prefix) | 
|  |  | 
|  | level := 0 | 
|  |  | 
|  | out: | 
|  | for { | 
|  | c := getrune(finput) | 
|  | if c == EOF { | 
|  | errorf("EOF encountered while processing %%union") | 
|  | } | 
|  | ftable.WriteRune(c) | 
|  | switch c { | 
|  | case '\n': | 
|  | lineno++ | 
|  | case '{': | 
|  | if level == 0 { | 
|  | fmt.Fprintf(ftable, "\n\tyys int") | 
|  | } | 
|  | level++ | 
|  | case '}': | 
|  | level-- | 
|  | if level == 0 { | 
|  | break out | 
|  | } | 
|  | } | 
|  | } | 
|  | fmt.Fprintf(ftable, "\n\n") | 
|  | } | 
|  |  | 
|  | // | 
|  | // saves code between %{ and %} | 
|  | // adds an import for __fmt__ the first time | 
|  | // | 
|  | func cpycode() { | 
|  | lno := lineno | 
|  |  | 
|  | c := getrune(finput) | 
|  | if c == '\n' { | 
|  | c = getrune(finput) | 
|  | lineno++ | 
|  | } | 
|  | if !lflag { | 
|  | fmt.Fprintf(ftable, "\n//line %v:%v\n", infile, lineno) | 
|  | } | 
|  | // accumulate until %} | 
|  | code := make([]rune, 0, 1024) | 
|  | for c != EOF { | 
|  | if c == '%' { | 
|  | c = getrune(finput) | 
|  | if c == '}' { | 
|  | emitcode(code, lno+1) | 
|  | return | 
|  | } | 
|  | code = append(code, '%') | 
|  | } | 
|  | code = append(code, c) | 
|  | if c == '\n' { | 
|  | lineno++ | 
|  | } | 
|  | c = getrune(finput) | 
|  | } | 
|  | lineno = lno | 
|  | errorf("eof before %%}") | 
|  | } | 
|  |  | 
|  | // | 
|  | // emits code saved up from between %{ and %} | 
|  | // called by cpycode | 
|  | // adds an import for __yyfmt__ after the package clause | 
|  | // | 
|  | func emitcode(code []rune, lineno int) { | 
|  | for i, line := range lines(code) { | 
|  | writecode(line) | 
|  | if !fmtImported && isPackageClause(line) { | 
|  | fmt.Fprintln(ftable, `import __yyfmt__ "fmt"`) | 
|  | if !lflag { | 
|  | fmt.Fprintf(ftable, "//line %v:%v\n\t\t", infile, lineno+i) | 
|  | } | 
|  | fmtImported = true | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // | 
|  | // does this line look like a package clause?  not perfect: might be confused by early comments. | 
|  | // | 
|  | func isPackageClause(line []rune) bool { | 
|  | line = skipspace(line) | 
|  |  | 
|  | // must be big enough. | 
|  | if len(line) < len("package X\n") { | 
|  | return false | 
|  | } | 
|  |  | 
|  | // must start with "package" | 
|  | for i, r := range []rune("package") { | 
|  | if line[i] != r { | 
|  | return false | 
|  | } | 
|  | } | 
|  | line = skipspace(line[len("package"):]) | 
|  |  | 
|  | // must have another identifier. | 
|  | if len(line) == 0 || (!unicode.IsLetter(line[0]) && line[0] != '_') { | 
|  | return false | 
|  | } | 
|  | for len(line) > 0 { | 
|  | if !unicode.IsLetter(line[0]) && !unicode.IsDigit(line[0]) && line[0] != '_' { | 
|  | break | 
|  | } | 
|  | line = line[1:] | 
|  | } | 
|  | line = skipspace(line) | 
|  |  | 
|  | // eol, newline, or comment must follow | 
|  | if len(line) == 0 { | 
|  | return true | 
|  | } | 
|  | if line[0] == '\r' || line[0] == '\n' { | 
|  | return true | 
|  | } | 
|  | if len(line) >= 2 { | 
|  | return line[0] == '/' && (line[1] == '/' || line[1] == '*') | 
|  | } | 
|  | return false | 
|  | } | 
|  |  | 
|  | // | 
|  | // skip initial spaces | 
|  | // | 
|  | func skipspace(line []rune) []rune { | 
|  | for len(line) > 0 { | 
|  | if line[0] != ' ' && line[0] != '\t' { | 
|  | break | 
|  | } | 
|  | line = line[1:] | 
|  | } | 
|  | return line | 
|  | } | 
|  |  | 
|  | // | 
|  | // break code into lines | 
|  | // | 
|  | func lines(code []rune) [][]rune { | 
|  | l := make([][]rune, 0, 100) | 
|  | for len(code) > 0 { | 
|  | // one line per loop | 
|  | var i int | 
|  | for i = range code { | 
|  | if code[i] == '\n' { | 
|  | break | 
|  | } | 
|  | } | 
|  | l = append(l, code[:i+1]) | 
|  | code = code[i+1:] | 
|  | } | 
|  | return l | 
|  | } | 
|  |  | 
|  | // | 
|  | // writes code to ftable | 
|  | // | 
|  | func writecode(code []rune) { | 
|  | for _, r := range code { | 
|  | ftable.WriteRune(r) | 
|  | } | 
|  | } | 
|  |  | 
|  | // | 
|  | // skip over comments | 
|  | // skipcom is called after reading a '/' | 
|  | // | 
|  | func skipcom() int { | 
|  | c := getrune(finput) | 
|  | if c == '/' { | 
|  | for c != EOF { | 
|  | if c == '\n' { | 
|  | return 1 | 
|  | } | 
|  | c = getrune(finput) | 
|  | } | 
|  | errorf("EOF inside comment") | 
|  | return 0 | 
|  | } | 
|  | if c != '*' { | 
|  | errorf("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 | 
|  | } | 
|  |  | 
|  | // | 
|  | // copy action to the next ; or closing } | 
|  | // | 
|  | func cpyact(curprod []int, max int) { | 
|  |  | 
|  | if !lflag { | 
|  | fmt.Fprintf(fcode, "\n//line %v:%v", infile, lineno) | 
|  | } | 
|  | fmt.Fprint(fcode, "\n\t\t") | 
|  |  | 
|  | lno := lineno | 
|  | brac := 0 | 
|  |  | 
|  | loop: | 
|  | for { | 
|  | c := getrune(finput) | 
|  |  | 
|  | swt: | 
|  | switch c { | 
|  | case ';': | 
|  | if brac == 0 { | 
|  | fcode.WriteRune(c) | 
|  | return | 
|  | } | 
|  |  | 
|  | case '{': | 
|  | brac++ | 
|  |  | 
|  | case '$': | 
|  | s := 1 | 
|  | tok := -1 | 
|  | c = getrune(finput) | 
|  |  | 
|  | // type description | 
|  | if c == '<' { | 
|  | ungetrune(finput, c) | 
|  | if gettok() != TYPENAME { | 
|  | errorf("bad syntax on $<ident> clause") | 
|  | } | 
|  | tok = numbval | 
|  | c = getrune(finput) | 
|  | } | 
|  | if c == '$' { | 
|  | fmt.Fprintf(fcode, "%sVAL", prefix) | 
|  |  | 
|  | // put out the proper tag... | 
|  | if ntypes != 0 { | 
|  | if tok < 0 { | 
|  | tok = fdtype(curprod[0]) | 
|  | } | 
|  | fmt.Fprintf(fcode, ".%v", typeset[tok]) | 
|  | } | 
|  | continue loop | 
|  | } | 
|  | if c == '-' { | 
|  | s = -s | 
|  | c = getrune(finput) | 
|  | } | 
|  | j := 0 | 
|  | if isdigit(c) { | 
|  | for isdigit(c) { | 
|  | j = j*10 + int(c-'0') | 
|  | c = getrune(finput) | 
|  | } | 
|  | ungetrune(finput, c) | 
|  | j = j * s | 
|  | if j >= max { | 
|  | errorf("Illegal use of $%v", j) | 
|  | } | 
|  | } else if isword(c) || c == '.' { | 
|  | // look for $name | 
|  | ungetrune(finput, c) | 
|  | if gettok() != IDENTIFIER { | 
|  | errorf("$ must be followed by an identifier") | 
|  | } | 
|  | tokn := chfind(2, tokname) | 
|  | fnd := -1 | 
|  | c = getrune(finput) | 
|  | if c != '@' { | 
|  | ungetrune(finput, c) | 
|  | } else if gettok() != NUMBER { | 
|  | errorf("@ 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 { | 
|  | errorf("$name or $name@number not found") | 
|  | } | 
|  | } else { | 
|  | fcode.WriteRune('$') | 
|  | if s < 0 { | 
|  | fcode.WriteRune('-') | 
|  | } | 
|  | ungetrune(finput, c) | 
|  | continue loop | 
|  | } | 
|  | fmt.Fprintf(fcode, "%sDollar[%v]", prefix, j) | 
|  |  | 
|  | // put out the proper tag | 
|  | if ntypes != 0 { | 
|  | if j <= 0 && tok < 0 { | 
|  | errorf("must specify type of $%v", j) | 
|  | } | 
|  | if tok < 0 { | 
|  | tok = fdtype(curprod[j]) | 
|  | } | 
|  | fmt.Fprintf(fcode, ".%v", typeset[tok]) | 
|  | } | 
|  | continue loop | 
|  |  | 
|  | case '}': | 
|  | brac-- | 
|  | if brac != 0 { | 
|  | break | 
|  | } | 
|  | fcode.WriteRune(c) | 
|  | return | 
|  |  | 
|  | case '/': | 
|  | nc := getrune(finput) | 
|  | if nc != '/' && nc != '*' { | 
|  | ungetrune(finput, nc) | 
|  | break | 
|  | } | 
|  | // a comment | 
|  | fcode.WriteRune(c) | 
|  | fcode.WriteRune(nc) | 
|  | c = getrune(finput) | 
|  | for c != EOF { | 
|  | switch { | 
|  | case c == '\n': | 
|  | lineno++ | 
|  | if nc == '/' { // end of // comment | 
|  | break swt | 
|  | } | 
|  | case c == '*' && nc == '*': // end of /* comment? | 
|  | nnc := getrune(finput) | 
|  | if nnc == '/' { | 
|  | fcode.WriteRune('*') | 
|  | fcode.WriteRune('/') | 
|  | continue loop | 
|  | } | 
|  | ungetrune(finput, nnc) | 
|  | } | 
|  | fcode.WriteRune(c) | 
|  | c = getrune(finput) | 
|  | } | 
|  | errorf("EOF inside comment") | 
|  |  | 
|  | case '\'', '"': | 
|  | // character string or constant | 
|  | match := c | 
|  | fcode.WriteRune(c) | 
|  | c = getrune(finput) | 
|  | for c != EOF { | 
|  | if c == '\\' { | 
|  | fcode.WriteRune(c) | 
|  | c = getrune(finput) | 
|  | if c == '\n' { | 
|  | lineno++ | 
|  | } | 
|  | } else if c == match { | 
|  | break swt | 
|  | } | 
|  | if c == '\n' { | 
|  | errorf("newline in string or char const") | 
|  | } | 
|  | fcode.WriteRune(c) | 
|  | c = getrune(finput) | 
|  | } | 
|  | errorf("EOF in string or character constant") | 
|  |  | 
|  | case EOF: | 
|  | lineno = lno | 
|  | errorf("action does not terminate") | 
|  |  | 
|  | case '\n': | 
|  | fmt.Fprint(fcode, "\n\t") | 
|  | lineno++ | 
|  | continue loop | 
|  | } | 
|  |  | 
|  | fcode.WriteRune(c) | 
|  | } | 
|  | } | 
|  |  | 
|  | func openup() { | 
|  | infile = flag.Arg(0) | 
|  | finput = open(infile) | 
|  | if finput == nil { | 
|  | errorf("cannot open %v", infile) | 
|  | } | 
|  |  | 
|  | foutput = nil | 
|  | if vflag != "" { | 
|  | foutput = create(vflag) | 
|  | if foutput == nil { | 
|  | errorf("can't create file %v", vflag) | 
|  | } | 
|  | } | 
|  |  | 
|  | ftable = nil | 
|  | if oflag == "" { | 
|  | oflag = "y.go" | 
|  | } | 
|  | ftable = create(oflag) | 
|  | if ftable == nil { | 
|  | errorf("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 | 
|  | } | 
|  | 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:] | 
|  | n++ | 
|  | } | 
|  | } | 
|  | if n == 0 { | 
|  | errorf("nonterminal %v not defined", nontrst[i].name) | 
|  | continue | 
|  | } | 
|  | pres[i] = make([][]int, n) | 
|  | copy(pres[i], curres) | 
|  | } | 
|  | fatfl = 1 | 
|  | if nerrors != 0 { | 
|  | summary() | 
|  | exit(1) | 
|  | } | 
|  | } | 
|  |  | 
|  | // | 
|  | // 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 | 
|  | errorf("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 | 
|  | } | 
|  | } | 
|  |  | 
|  | // | 
|  | // 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:], 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 | 
|  | copy(wsets[cwp].ws, statemem[p].look) | 
|  | 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) | 
|  | copy(awsets, wsets) | 
|  | 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 | 
|  | copy(wsets[cwp].ws, clset) | 
|  | } | 
|  | 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 { | 
|  | errorf("yacc state/nolook error") | 
|  | } | 
|  | pstate[nstate+2] = p2 | 
|  | if nstate+1 >= NSTATES { | 
|  | errorf("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) | 
|  | copy(asm, statemem) | 
|  | statemem = asm | 
|  | } | 
|  | statemem[j].pitem = p | 
|  | if nolook == 0 { | 
|  | s := mkset() | 
|  | copy(s, set) | 
|  | 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 | 
|  | } | 
|  | errorf("no space in action table") | 
|  | return 0 | 
|  | } | 
|  |  | 
|  | // | 
|  | // print the output for the states | 
|  | // | 
|  | func output() { | 
|  | var c, u, v int | 
|  |  | 
|  | if !lflag { | 
|  | fmt.Fprintf(ftable, "\n//line yacctab:1") | 
|  | } | 
|  | fmt.Fprintf(ftable, "\nvar %sExca = [...]int{\n", prefix) | 
|  |  | 
|  | if len(errors) > 0 { | 
|  | stateTable = make([]Row, nstate) | 
|  | } | 
|  |  | 
|  | 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") | 
|  | ftable.WriteRune('\n') | 
|  | fmt.Fprintf(ftable, "const %sPrivate = %v\n", prefix, PRIVATE) | 
|  | } | 
|  |  | 
|  | // | 
|  | // 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) { | 
|  | action := NOASC | 
|  |  | 
|  | 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, "\t-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 len(errors) > 0 { | 
|  | actions := append([]int(nil), temp1...) | 
|  | defaultAction := ERRCODE | 
|  | if lastred != 0 { | 
|  | defaultAction = -lastred | 
|  | } | 
|  | stateTable[i] = Row{actions, defaultAction} | 
|  | } | 
|  |  | 
|  | 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]) | 
|  | } | 
|  | ftable.WriteRune('\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 { | 
|  | errorf("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 | 
|  | } | 
|  | errorf("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] { | 
|  | errorf("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 | 
|  | } | 
|  | errorf("Error; failure to place state %v", i) | 
|  | } | 
|  |  | 
|  | // | 
|  | // this version is for limbo | 
|  | // write out the optimized parser | 
|  | // | 
|  | func aoutput() { | 
|  | ftable.WriteRune('\n') | 
|  | fmt.Fprintf(ftable, "const %sLast = %v\n", prefix, maxa+1) | 
|  | arout("Act", amem, maxa+1) | 
|  | arout("Pact", indgo, nstate) | 
|  | arout("Pgo", pgo, nnonter+1) | 
|  | } | 
|  |  | 
|  | // | 
|  | // put out other arrays, copy the parsers | 
|  | // | 
|  | func others() { | 
|  | var i, j int | 
|  |  | 
|  | arout("R1", 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("R2", 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("Chk", temp1, nstate) | 
|  | arout("Def", 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 { | 
|  | fmt.Print("yacc bug -- cannot have 2 different Ts with same value\n") | 
|  | fmt.Printf("	%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("Tok1", 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 { | 
|  | fmt.Print("yacc bug -- cannot have 2 different Ts with same value\n") | 
|  | fmt.Printf("	%s and %s\n", tokset[i].name, tokset[temp1[j]].name) | 
|  | nerrors++ | 
|  | } | 
|  | temp1[j] = i | 
|  | if j > c { | 
|  | c = j | 
|  | } | 
|  | } | 
|  | } | 
|  | arout("Tok2", temp1, c+1) | 
|  |  | 
|  | // table 3 has everything else | 
|  | ftable.WriteRune('\n') | 
|  | fmt.Fprintf(ftable, "var %sTok3 = [...]int{\n\t", prefix) | 
|  | 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 | 
|  | } | 
|  |  | 
|  | if c%5 != 0 { | 
|  | ftable.WriteRune(' ') | 
|  | } | 
|  | fmt.Fprintf(ftable, "%d, %d,", j, i) | 
|  | c++ | 
|  | if c%5 == 0 { | 
|  | fmt.Fprint(ftable, "\n\t") | 
|  | } | 
|  | } | 
|  | if c%5 != 0 { | 
|  | ftable.WriteRune(' ') | 
|  | } | 
|  | fmt.Fprintf(ftable, "%d,\n}\n", 0) | 
|  |  | 
|  | // Custom error messages. | 
|  | fmt.Fprintf(ftable, "\n") | 
|  | fmt.Fprintf(ftable, "var %sErrorMessages = [...]struct {\n", prefix) | 
|  | fmt.Fprintf(ftable, "\tstate int\n") | 
|  | fmt.Fprintf(ftable, "\ttoken int\n") | 
|  | fmt.Fprintf(ftable, "\tmsg   string\n") | 
|  | fmt.Fprintf(ftable, "}{\n") | 
|  | for _, error := range errors { | 
|  | lineno = error.lineno | 
|  | state, token := runMachine(error.tokens) | 
|  | fmt.Fprintf(ftable, "\t{%v, %v, %s},\n", state, token, error.msg) | 
|  | } | 
|  | fmt.Fprintf(ftable, "}\n") | 
|  |  | 
|  | // copy parser text | 
|  | ch := getrune(finput) | 
|  | for ch != EOF { | 
|  | ftable.WriteRune(ch) | 
|  | ch = getrune(finput) | 
|  | } | 
|  |  | 
|  | // copy yaccpar | 
|  | if !lflag { | 
|  | fmt.Fprintf(ftable, "\n//line yaccpar:1\n") | 
|  | } | 
|  |  | 
|  | parts := strings.SplitN(yaccpar, prefix+"run()", 2) | 
|  | fmt.Fprintf(ftable, "%v", parts[0]) | 
|  | ftable.Write(fcode.Bytes()) | 
|  | fmt.Fprintf(ftable, "%v", parts[1]) | 
|  | } | 
|  |  | 
|  | func runMachine(tokens []string) (state, token int) { | 
|  | var stack []int | 
|  | i := 0 | 
|  | token = -1 | 
|  |  | 
|  | Loop: | 
|  | if token < 0 { | 
|  | token = chfind(2, tokens[i]) | 
|  | i++ | 
|  | } | 
|  |  | 
|  | row := stateTable[state] | 
|  |  | 
|  | c := token | 
|  | if token >= NTBASE { | 
|  | c = token - NTBASE + ntokens | 
|  | } | 
|  | action := row.actions[c] | 
|  | if action == 0 { | 
|  | action = row.defaultAction | 
|  | } | 
|  |  | 
|  | switch { | 
|  | case action == ACCEPTCODE: | 
|  | errorf("tokens are accepted") | 
|  | return | 
|  | case action == ERRCODE: | 
|  | if token >= NTBASE { | 
|  | errorf("error at non-terminal token %s", symnam(token)) | 
|  | } | 
|  | return | 
|  | case action > 0: | 
|  | // Shift to state action. | 
|  | stack = append(stack, state) | 
|  | state = action | 
|  | token = -1 | 
|  | goto Loop | 
|  | default: | 
|  | // Reduce by production -action. | 
|  | prod := prdptr[-action] | 
|  | if rhsLen := len(prod) - 2; rhsLen > 0 { | 
|  | n := len(stack) - rhsLen | 
|  | state = stack[n] | 
|  | stack = stack[:n] | 
|  | } | 
|  | if token >= 0 { | 
|  | i-- | 
|  | } | 
|  | token = prod[0] | 
|  | goto Loop | 
|  | } | 
|  | } | 
|  |  | 
|  | func arout(s string, v []int, n int) { | 
|  | s = prefix + s | 
|  | ftable.WriteRune('\n') | 
|  | fmt.Fprintf(ftable, "var %v = [...]int{", s) | 
|  | for i := 0; i < n; i++ { | 
|  | if i%10 == 0 { | 
|  | fmt.Fprintf(ftable, "\n\t") | 
|  | } else { | 
|  | ftable.WriteRune(' ') | 
|  | } | 
|  | fmt.Fprintf(ftable, "%d,", v[i]) | 
|  | } | 
|  | 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: yacc [-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 rune | 
|  |  | 
|  | func isdigit(c rune) bool { return c >= '0' && c <= '9' } | 
|  |  | 
|  | func isword(c rune) bool { | 
|  | return c >= 0xa0 || c == '_' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') | 
|  | } | 
|  |  | 
|  | // | 
|  | // 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 getrune(f *bufio.Reader) rune { | 
|  | var r rune | 
|  |  | 
|  | 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 { | 
|  | errorf("read error: %v", err) | 
|  | } | 
|  | //fmt.Printf("rune = %v n=%v\n", string(c), n); | 
|  | return c | 
|  | } | 
|  |  | 
|  | func ungetrune(f *bufio.Reader, c rune) { | 
|  | if f != finput { | 
|  | panic("ungetc - not finput") | 
|  | } | 
|  | if peekrune != 0 { | 
|  | panic("ungetc - 2nd unget") | 
|  | } | 
|  | peekrune = c | 
|  | } | 
|  |  | 
|  | func open(s string) *bufio.Reader { | 
|  | fi, err := os.Open(s) | 
|  | if err != nil { | 
|  | errorf("error opening %v: %v", s, err) | 
|  | } | 
|  | //fmt.Printf("open %v\n", s); | 
|  | return bufio.NewReader(fi) | 
|  | } | 
|  |  | 
|  | func create(s string) *bufio.Writer { | 
|  | fo, err := os.Create(s) | 
|  | if err != nil { | 
|  | errorf("error creating %v: %v", s, err) | 
|  | } | 
|  | //fmt.Printf("create %v mode %v\n", s); | 
|  | return bufio.NewWriter(fo) | 
|  | } | 
|  |  | 
|  | // | 
|  | // write out error comment | 
|  | // | 
|  | func lerrorf(lineno int, s string, v ...interface{}) { | 
|  | nerrors++ | 
|  | fmt.Fprintf(stderr, s, v...) | 
|  | fmt.Fprintf(stderr, ": %v:%v\n", infile, lineno) | 
|  | if fatfl != 0 { | 
|  | summary() | 
|  | exit(1) | 
|  | } | 
|  | } | 
|  |  | 
|  | func errorf(s string, v ...interface{}) { | 
|  | lerrorf(lineno, s, v...) | 
|  | } | 
|  |  | 
|  | func exit(status int) { | 
|  | if ftable != nil { | 
|  | ftable.Flush() | 
|  | ftable = nil | 
|  | gofmt() | 
|  | } | 
|  | if foutput != nil { | 
|  | foutput.Flush() | 
|  | foutput = nil | 
|  | } | 
|  | if stderr != nil { | 
|  | stderr.Flush() | 
|  | stderr = nil | 
|  | } | 
|  | os.Exit(status) | 
|  | } | 
|  |  | 
|  | func gofmt() { | 
|  | src, err := ioutil.ReadFile(oflag) | 
|  | if err != nil { | 
|  | return | 
|  | } | 
|  | src, err = format.Source(src) | 
|  | if err != nil { | 
|  | return | 
|  | } | 
|  | ioutil.WriteFile(oflag, src, 0666) | 
|  | } | 
|  |  | 
|  | var yaccpar string // will be processed version of yaccpartext: s/$$/prefix/g | 
|  | var yaccpartext = ` | 
|  | /*	parser for yacc output	*/ | 
|  |  | 
|  | var ( | 
|  | $$Debug        = 0 | 
|  | $$ErrorVerbose = false | 
|  | ) | 
|  |  | 
|  | type $$Lexer interface { | 
|  | Lex(lval *$$SymType) int | 
|  | Error(s string) | 
|  | } | 
|  |  | 
|  | type $$Parser interface { | 
|  | Parse($$Lexer) int | 
|  | Lookahead() int | 
|  | } | 
|  |  | 
|  | type $$ParserImpl struct { | 
|  | lval  $$SymType | 
|  | stack [$$InitialStackSize]$$SymType | 
|  | char  int | 
|  | } | 
|  |  | 
|  | func (p *$$ParserImpl) Lookahead() int { | 
|  | return p.char | 
|  | } | 
|  |  | 
|  | func $$NewParser() $$Parser { | 
|  | return &$$ParserImpl{} | 
|  | } | 
|  |  | 
|  | const $$Flag = -1000 | 
|  |  | 
|  | func $$Tokname(c int) string { | 
|  | if c >= 1 && c-1 < len($$Toknames) { | 
|  | if $$Toknames[c-1] != "" { | 
|  | return $$Toknames[c-1] | 
|  | } | 
|  | } | 
|  | return __yyfmt__.Sprintf("tok-%v", c) | 
|  | } | 
|  |  | 
|  | func $$Statname(s int) string { | 
|  | if s >= 0 && s < len($$Statenames) { | 
|  | if $$Statenames[s] != "" { | 
|  | return $$Statenames[s] | 
|  | } | 
|  | } | 
|  | return __yyfmt__.Sprintf("state-%v", s) | 
|  | } | 
|  |  | 
|  | func $$ErrorMessage(state, lookAhead int) string { | 
|  | const TOKSTART = 4 | 
|  |  | 
|  | if !$$ErrorVerbose { | 
|  | return "syntax error" | 
|  | } | 
|  |  | 
|  | for _, e := range $$ErrorMessages { | 
|  | if e.state == state && e.token == lookAhead { | 
|  | return "syntax error: " + e.msg | 
|  | } | 
|  | } | 
|  |  | 
|  | res := "syntax error: unexpected " + $$Tokname(lookAhead) | 
|  |  | 
|  | // To match Bison, suggest at most four expected tokens. | 
|  | expected := make([]int, 0, 4) | 
|  |  | 
|  | // Look for shiftable tokens. | 
|  | base := $$Pact[state] | 
|  | for tok := TOKSTART; tok-1 < len($$Toknames); tok++ { | 
|  | if n := base + tok; n >= 0 && n < $$Last && $$Chk[$$Act[n]] == tok { | 
|  | if len(expected) == cap(expected) { | 
|  | return res | 
|  | } | 
|  | expected = append(expected, tok) | 
|  | } | 
|  | } | 
|  |  | 
|  | if $$Def[state] == -2 { | 
|  | i := 0 | 
|  | for $$Exca[i] != -1 || $$Exca[i+1] != state { | 
|  | i += 2 | 
|  | } | 
|  |  | 
|  | // Look for tokens that we accept or reduce. | 
|  | for i += 2; $$Exca[i] >= 0; i += 2 { | 
|  | tok := $$Exca[i] | 
|  | if tok < TOKSTART || $$Exca[i+1] == 0 { | 
|  | continue | 
|  | } | 
|  | if len(expected) == cap(expected) { | 
|  | return res | 
|  | } | 
|  | expected = append(expected, tok) | 
|  | } | 
|  |  | 
|  | // If the default action is to accept or reduce, give up. | 
|  | if $$Exca[i+1] != 0 { | 
|  | return res | 
|  | } | 
|  | } | 
|  |  | 
|  | for i, tok := range expected { | 
|  | if i == 0 { | 
|  | res += ", expecting " | 
|  | } else { | 
|  | res += " or " | 
|  | } | 
|  | res += $$Tokname(tok) | 
|  | } | 
|  | return res | 
|  | } | 
|  |  | 
|  | func $$lex1(lex $$Lexer, lval *$$SymType) (char, token int) { | 
|  | token = 0 | 
|  | char = lex.Lex(lval) | 
|  | if char <= 0 { | 
|  | token = $$Tok1[0] | 
|  | goto out | 
|  | } | 
|  | if char < len($$Tok1) { | 
|  | token = $$Tok1[char] | 
|  | goto out | 
|  | } | 
|  | if char >= $$Private { | 
|  | if char < $$Private+len($$Tok2) { | 
|  | token = $$Tok2[char-$$Private] | 
|  | goto out | 
|  | } | 
|  | } | 
|  | for i := 0; i < len($$Tok3); i += 2 { | 
|  | token = $$Tok3[i+0] | 
|  | if token == char { | 
|  | token = $$Tok3[i+1] | 
|  | goto out | 
|  | } | 
|  | } | 
|  |  | 
|  | out: | 
|  | if token == 0 { | 
|  | token = $$Tok2[1] /* unknown char */ | 
|  | } | 
|  | if $$Debug >= 3 { | 
|  | __yyfmt__.Printf("lex %s(%d)\n", $$Tokname(token), uint(char)) | 
|  | } | 
|  | return char, token | 
|  | } | 
|  |  | 
|  | func $$Parse($$lex $$Lexer) int { | 
|  | return $$NewParser().Parse($$lex) | 
|  | } | 
|  |  | 
|  | func ($$rcvr *$$ParserImpl) Parse($$lex $$Lexer) int { | 
|  | var $$n int | 
|  | var $$VAL $$SymType | 
|  | var $$Dollar []$$SymType | 
|  | _ = $$Dollar // silence set and not used | 
|  | $$S := $$rcvr.stack[:] | 
|  |  | 
|  | Nerrs := 0   /* number of errors */ | 
|  | Errflag := 0 /* error recovery flag */ | 
|  | $$state := 0 | 
|  | $$rcvr.char = -1 | 
|  | $$token := -1 // $$rcvr.char translated into internal numbering | 
|  | defer func() { | 
|  | // Make sure we report no lookahead when not parsing. | 
|  | $$state = -1 | 
|  | $$rcvr.char = -1 | 
|  | $$token = -1 | 
|  | }() | 
|  | $$p := -1 | 
|  | goto $$stack | 
|  |  | 
|  | ret0: | 
|  | return 0 | 
|  |  | 
|  | ret1: | 
|  | return 1 | 
|  |  | 
|  | $$stack: | 
|  | /* put a state and value onto the stack */ | 
|  | if $$Debug >= 4 { | 
|  | __yyfmt__.Printf("char %v in %v\n", $$Tokname($$token), $$Statname($$state)) | 
|  | } | 
|  |  | 
|  | $$p++ | 
|  | if $$p >= len($$S) { | 
|  | nyys := make([]$$SymType, len($$S)*2) | 
|  | copy(nyys, $$S) | 
|  | $$S = nyys | 
|  | } | 
|  | $$S[$$p] = $$VAL | 
|  | $$S[$$p].yys = $$state | 
|  |  | 
|  | $$newstate: | 
|  | $$n = $$Pact[$$state] | 
|  | if $$n <= $$Flag { | 
|  | goto $$default /* simple state */ | 
|  | } | 
|  | if $$rcvr.char < 0 { | 
|  | $$rcvr.char, $$token = $$lex1($$lex, &$$rcvr.lval) | 
|  | } | 
|  | $$n += $$token | 
|  | if $$n < 0 || $$n >= $$Last { | 
|  | goto $$default | 
|  | } | 
|  | $$n = $$Act[$$n] | 
|  | if $$Chk[$$n] == $$token { /* valid shift */ | 
|  | $$rcvr.char = -1 | 
|  | $$token = -1 | 
|  | $$VAL = $$rcvr.lval | 
|  | $$state = $$n | 
|  | if Errflag > 0 { | 
|  | Errflag-- | 
|  | } | 
|  | goto $$stack | 
|  | } | 
|  |  | 
|  | $$default: | 
|  | /* default state action */ | 
|  | $$n = $$Def[$$state] | 
|  | if $$n == -2 { | 
|  | if $$rcvr.char < 0 { | 
|  | $$rcvr.char, $$token = $$lex1($$lex, &$$rcvr.lval) | 
|  | } | 
|  |  | 
|  | /* look through exception table */ | 
|  | xi := 0 | 
|  | for { | 
|  | if $$Exca[xi+0] == -1 && $$Exca[xi+1] == $$state { | 
|  | break | 
|  | } | 
|  | xi += 2 | 
|  | } | 
|  | for xi += 2; ; xi += 2 { | 
|  | $$n = $$Exca[xi+0] | 
|  | if $$n < 0 || $$n == $$token { | 
|  | break | 
|  | } | 
|  | } | 
|  | $$n = $$Exca[xi+1] | 
|  | if $$n < 0 { | 
|  | goto ret0 | 
|  | } | 
|  | } | 
|  | if $$n == 0 { | 
|  | /* error ... attempt to resume parsing */ | 
|  | switch Errflag { | 
|  | case 0: /* brand new error */ | 
|  | $$lex.Error($$ErrorMessage($$state, $$token)) | 
|  | Nerrs++ | 
|  | if $$Debug >= 1 { | 
|  | __yyfmt__.Printf("%s", $$Statname($$state)) | 
|  | __yyfmt__.Printf(" saw %s\n", $$Tokname($$token)) | 
|  | } | 
|  | fallthrough | 
|  |  | 
|  | case 1, 2: /* incompletely recovered error ... try again */ | 
|  | Errflag = 3 | 
|  |  | 
|  | /* find a state where "error" is a legal shift action */ | 
|  | for $$p >= 0 { | 
|  | $$n = $$Pact[$$S[$$p].yys] + $$ErrCode | 
|  | if $$n >= 0 && $$n < $$Last { | 
|  | $$state = $$Act[$$n] /* simulate a shift of "error" */ | 
|  | if $$Chk[$$state] == $$ErrCode { | 
|  | goto $$stack | 
|  | } | 
|  | } | 
|  |  | 
|  | /* the current p has no shift on "error", pop stack */ | 
|  | if $$Debug >= 2 { | 
|  | __yyfmt__.Printf("error recovery pops state %d\n", $$S[$$p].yys) | 
|  | } | 
|  | $$p-- | 
|  | } | 
|  | /* 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 { | 
|  | __yyfmt__.Printf("error recovery discards %s\n", $$Tokname($$token)) | 
|  | } | 
|  | if $$token == $$EofCode { | 
|  | goto ret1 | 
|  | } | 
|  | $$rcvr.char = -1 | 
|  | $$token = -1 | 
|  | goto $$newstate /* try again in the same state */ | 
|  | } | 
|  | } | 
|  |  | 
|  | /* reduction by production $$n */ | 
|  | if $$Debug >= 2 { | 
|  | __yyfmt__.Printf("reduce %v in:\n\t%v\n", $$n, $$Statname($$state)) | 
|  | } | 
|  |  | 
|  | $$nt := $$n | 
|  | $$pt := $$p | 
|  | _ = $$pt // guard against "declared and not used" | 
|  |  | 
|  | $$p -= $$R2[$$n] | 
|  | // $$p is now the index of $0. Perform the default action. Iff the | 
|  | // reduced production is ε, $1 is possibly out of range. | 
|  | if $$p+1 >= len($$S) { | 
|  | nyys := make([]$$SymType, len($$S)*2) | 
|  | copy(nyys, $$S) | 
|  | $$S = nyys | 
|  | } | 
|  | $$VAL = $$S[$$p+1] | 
|  |  | 
|  | /* consult goto table to find next state */ | 
|  | $$n = $$R1[$$n] | 
|  | $$g := $$Pgo[$$n] | 
|  | $$j := $$g + $$S[$$p].yys + 1 | 
|  |  | 
|  | if $$j >= $$Last { | 
|  | $$state = $$Act[$$g] | 
|  | } else { | 
|  | $$state = $$Act[$$j] | 
|  | if $$Chk[$$state] != -$$n { | 
|  | $$state = $$Act[$$g] | 
|  | } | 
|  | } | 
|  | // dummy call; replaced with literal code | 
|  | $$run() | 
|  | goto $$stack /* stack new state and value */ | 
|  | } | 
|  | ` |