2 Derived from Inferno's utils/iyacc/yacc.c
3 http://code.google.com/p/inferno-os/source/browse/utils/iyacc/yacc.c
5 This copyright NOTICE applies to all files in this directory and
6 subdirectories, unless another copyright notice appears in a given
7 file or subdirectory. If you take substantial code from this software to use in
8 other programs, you must somehow include with it an appropriate
9 copyright notice that includes the copyright notice and the other
10 notices below. It is fine (and often tidier) to do that in a separate
11 file such as NOTICE, LICENCE or COPYING.
13 Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
14 Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
15 Portions Copyright © 1997-1999 Vita Nuova Limited
16 Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
17 Portions Copyright © 2004,2006 Bruce Ellis
18 Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
19 Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
20 Portions Copyright © 2009 The Go Authors. All rights reserved.
22 Permission is hereby granted, free of charge, to any person obtaining a copy
23 of this software and associated documentation files (the "Software"), to deal
24 in the Software without restriction, including without limitation the rights
25 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
26 copies of the Software, and to permit persons to whom the Software is
27 furnished to do so, subject to the following conditions:
29 The above copyright notice and this permission notice shall be included in
30 all copies or substantial portions of the Software.
32 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
44 // major difference is lack of stem ("y" variable)
60 // the following are adjustable
61 // according to memory size
67 SYMINC = 50 // increase for non-term or term
68 RULEINC = 50 // increase for max rule length prodptr[i]
69 PRODINC = 100 // increase for productions prodptr
70 WSETINC = 50 // increase for working sets wsets
71 STATEINC = 200 // increase for states statemem
77 PRIVATE = 0xE000 // unicode private use
79 // relationships which must hold:
80 // TEMPSIZE >= NTERMS + NNONTERM + 1;
81 // TEMPSIZE >= NSTATES;
88 TOKSTART = 4 //index of first defined token
91 // no, left, right, binary assoc.
99 // flags for state generation
106 // flags for a rule having an action, and being reduced
108 ACTFLAG = 1 << (iota + 2)
112 // output parser flags
117 IDENTIFIER = PRIVATE + iota
140 // macros for getting associativity and precedence levels
141 func ASSOC(i int) int { return i & 3 }
143 func PLEVEL(i int) int { return (i >> 4) & 077 }
145 func TYPE(i int) int { return (i >> 10) & 077 }
147 // macros for setting associativity and precedence levels
148 func SETASC(i, j int) int { return i | j }
150 func SETPLEV(i, j int) int { return i | (j << 4) }
152 func SETTYPE(i, j int) int { return i | (j << 10) }
155 var finput *bufio.Reader // input file
156 var stderr *bufio.Writer
157 var ftable *bufio.Writer // y.go file
158 var fcode = &bytes.Buffer{} // saved code
159 var foutput *bufio.Writer // y.output file
161 var fmtImported bool // output file has recorded an import of "fmt"
163 var oflag string // -o [y.go] - y.go file
164 var vflag string // -v [y.output] - y.output file
165 var lflag bool // -l - disable line directives
166 var prefix string // name prefix for identifiers, default yy
169 flag.StringVar(&oflag, "o", "y.go", "parser output")
170 flag.StringVar(&prefix, "p", "yy", "name prefix to use in generated code")
171 flag.StringVar(&vflag, "v", "y.output", "create parsing tables")
172 flag.BoolVar(&lflag, "l", false, "disable line directives")
175 var initialstacksize = 16
177 // communication variables between various I/O routines
178 var infile string // input file name
179 var numbval int // value of an input number
180 var tokname string // input token name, slop for runes and 0
183 // structure declarations
188 off int // offset within the production
189 first int // first term or non-term in item
190 prodno int // production number for sorting
211 var ntypes int // number of types defined
212 var typeset [NTYPES]string // pointers to type tags
216 var ntokens = 0 // number of tokens
218 var toklev []int // vector with the precedence of the terminals
220 // nonterminal information
222 var nnonter = -1 // the number of nonterminals
224 var start int // start symbol
228 var nstate = 0 // number of states
229 var pstate = make([]int, NSTATES+2) // index into statemem to the descriptions of the states
231 var tystate = make([]int, NSTATES) // contains type information about the states
232 var tstates []int // states generated by terminal gotos
233 var ntstates []int // states generated by nonterminal gotos
234 var mstates = make([]int, NSTATES) // chain of overflows of term/nonterm generation lists
235 var lastred int // number of last reduction of a state
236 var defact = make([]int, NSTATES) // default actions of states
238 // lookahead set information
240 var nolook = 0 // flag to turn off lookahead computations
241 var tbitset = 0 // size of lookahead sets
242 var clset Lkset // temporary storage for lookahead computations
244 // working set information
249 // storage for action table
251 var amem []int // action table storage
252 var memp int // next free action table position
253 var indgo = make([]int, NSTATES) // index to the stored goto table
255 // temporary vector, indexable by states, terms, or ntokens
257 var temp1 = make([]int, TEMPSIZE) // temporary storage, indexed by terms + ntokens or states
258 var lineno = 1 // current input line number
259 var fatfl = 1 // if on, error is fatal
260 var nerrors = 0 // number of errors
262 // assigned token type values
266 // grammar rule information
268 var nprod = 1 // number of productions
269 var prdptr [][]int // pointers to descriptions of productions
270 var levprd []int // precedence levels for the productions
271 var rlines []int // line number for this rule
273 // statistics collection variables
291 var maxspr int // maximum spread of any entry
292 var maxoff int // maximum offset into a array
295 // storage for information about the nonterminals
297 var pres [][][]int // vector of pointers to productions yielding each nonterminal
299 var pempty []int // vector of nonterminals nontrivially deriving e
301 // random stuff picked out from between functions
303 var indebug = 0 // debugging flag for cpfir
304 var pidebug = 0 // debugging flag for putitem
305 var gsdebug = 0 // debugging flag for stagen
306 var cldebug = 0 // debugging flag for closure
307 var pkdebug = 0 // debugging flag for apack
308 var g2debug = 0 // debugging for go2gen
309 var adb = 0 // debugging for callopt
319 {"nonassoc", BINARY},
352 setup() // initialize and read productions
354 tbitset = (ntokens + 32) / 32
355 cpres() // make table of which productions yield a given nonterminal
356 cempty() // make a table of which nonterminals can match the empty string
357 cpfir() // make a table of firsts of nonterminals
359 stagen() // generate the states
361 yypgo = make([][]int, nnonter+1)
362 optst = make([][]int, nstate)
363 output() // write the states and the tables
379 stderr = bufio.NewWriter(os.Stderr)
383 if flag.NArg() != 1 {
386 if initialstacksize < 1 {
387 // never set so cannot happen
388 fmt.Fprintf(stderr, "yacc: stack size too small\n")
391 yaccpar = strings.Replace(yaccpartext, "$$", prefix, -1)
395 extval = PRIVATE // tokens start in unicode 'private use'
407 errorf("syntax error tok=%v", t-PRIVATE)
417 errorf("bad %%start construction")
419 start = chfind(1, tokname)
429 if t != IDENTIFIER && t != IDENTCOLON {
430 errorf("bad syntax in %%error")
432 tokens = append(tokens, tokname)
437 if gettok() != IDENTIFIER {
438 errorf("bad syntax in %%error")
440 errors = append(errors, Error{lno, tokens, tokname})
445 errorf("bad syntax in %%type")
452 t = chfind(1, tokname)
455 if j != 0 && j != ty {
456 errorf("type redeclaration of token %s",
459 toklev[t] = SETTYPE(toklev[t], ty)
462 j = nontrst[t-NTBASE].value
463 if j != 0 && j != ty {
464 errorf("type redeclaration of nonterminal %v",
465 nontrst[t-NTBASE].name)
467 nontrst[t-NTBASE].value = ty
482 case LEFT, BINARY, RIGHT, TERM:
483 // nonzero means new prec. and assoc.
490 // get identifiers so defined
493 // there is a type defined
508 j = chfind(0, tokname)
510 errorf("%v defined earlier as nonterminal", tokname)
513 if ASSOC(toklev[j]) != 0 {
514 errorf("redeclaration of precedence of %v", tokname)
516 toklev[j] = SETASC(toklev[j], lev)
517 toklev[j] = SETPLEV(toklev[j], i)
520 if TYPE(toklev[j]) != 0 {
521 errorf("redeclaration of type of %v", tokname)
523 toklev[j] = SETTYPE(toklev[j], ty)
527 tokset[j].value = numbval
544 errorf("unexpected EOF before %%")
547 fmt.Fprintf(fcode, "switch %snt {\n", prefix)
550 prdptr[0] = []int{NTBASE, start, 1, 0}
553 curprod := make([]int, RULEINC)
556 errorf("bad syntax on first rule")
560 prdptr[0][1] = chfind(1, tokname)
564 // put into prdptr array in the format
566 // followed by id's of terminals and non-terminals
567 // followed by -nprod
569 for t != MARK && t != ENDFILE {
573 rlines[nprod] = lineno
576 curprod[mem] = prdptr[nprod-1][0]
578 } else if t == IDENTCOLON {
579 curprod[mem] = chfind(1, tokname)
580 if curprod[mem] < NTBASE {
581 lerrorf(ruleline, "token illegal on LHS of grammar rule")
585 lerrorf(ruleline, "illegal rule: missing semicolon or | ?")
591 for t == IDENTIFIER {
592 curprod[mem] = chfind(1, tokname)
593 if curprod[mem] < NTBASE {
594 levprd[nprod] = toklev[curprod[mem]]
597 if mem >= len(curprod) {
598 ncurprod := make([]int, mem+RULEINC)
599 copy(ncurprod, curprod)
605 if gettok() != IDENTIFIER {
606 lerrorf(ruleline, "illegal %%prec syntax")
608 j = chfind(2, tokname)
610 lerrorf(ruleline, "nonterminal "+nontrst[j-NTBASE].name+" illegal after %%prec")
612 levprd[nprod] = toklev[j]
618 levprd[nprod] |= ACTFLAG
619 fmt.Fprintf(fcode, "\n\tcase %v:", nprod)
620 fmt.Fprintf(fcode, "\n\t\t%sDollar = %sS[%spt-%v:%spt+1]", prefix, prefix, prefix, mem-1, prefix)
623 // action within rule...
626 // make it a nonterminal
627 j = chfind(1, fmt.Sprintf("$$%v", nprod))
630 // the current rule will become rule number nprod+1
631 // enter null production for action
633 prdptr[nprod] = make([]int, 2)
635 prdptr[nprod][1] = -nprod
637 // update the production information
640 levprd[nprod] = levprd[nprod-1] & ^ACTFLAG
641 levprd[nprod-1] = ACTFLAG
642 rlines[nprod] = lineno
644 // make the action appear in the original rule
647 if mem >= len(curprod) {
648 ncurprod := make([]int, mem+RULEINC)
649 copy(ncurprod, curprod)
658 curprod[mem] = -nprod
661 // check that default action is reasonable
662 if ntypes != 0 && (levprd[nprod]&ACTFLAG) == 0 &&
663 nontrst[curprod[0]-NTBASE].value != 0 {
664 // no explicit action, LHS has value
667 lerrorf(ruleline, "must return a value, since LHS has a type")
669 if tempty >= NTBASE {
670 tempty = nontrst[tempty-NTBASE].value
672 tempty = TYPE(toklev[tempty])
674 if tempty != nontrst[curprod[0]-NTBASE].value {
675 lerrorf(ruleline, "default action causes potential type clash")
679 prdptr[nprod] = make([]int, mem)
680 copy(prdptr[nprod], curprod)
688 // dump out the prefix code
691 fmt.Fprintf(fcode, "\n\t}")
693 // put out non-literal terminals
694 for i := TOKSTART; i <= ntokens; i++ {
696 if !tokset[i].noconst {
697 fmt.Fprintf(ftable, "const %v = %v\n", tokset[i].name, tokset[i].value)
701 // put out names of tokens
702 ftable.WriteRune('\n')
703 fmt.Fprintf(ftable, "var %sToknames = [...]string{\n", prefix)
704 for i := 1; i <= ntokens; i++ {
705 fmt.Fprintf(ftable, "\t%q,\n", tokset[i].name)
707 fmt.Fprintf(ftable, "}\n")
709 // put out names of states.
710 // commented out to avoid a huge table just for debugging.
711 // re-enable to have the names in the binary.
712 fmt.Fprintf(ftable, "var %sStatenames = [...]string{", prefix)
713 // for i:=TOKSTART; i<=ntokens; i++ {
714 // fmt.Fprintf(ftable, "\t%q,\n", tokset[i].name);
716 fmt.Fprintf(ftable, "}\n")
718 ftable.WriteRune('\n')
719 fmt.Fprintf(ftable, "const %sEofCode = 1\n", prefix)
720 fmt.Fprintf(ftable, "const %sErrCode = 2\n", prefix)
721 fmt.Fprintf(ftable, "const %sInitialStackSize = %v\n", prefix, initialstacksize)
724 // copy any postfix code
728 fmt.Fprintf(ftable, "\n//line %v:%v\n", infile, lineno)
741 // allocate enough room to hold another production
747 aprod := make([][]int, nn)
748 alevprd := make([]int, nn)
749 arlines := make([]int, nn)
752 copy(alevprd, levprd)
753 copy(arlines, rlines)
762 // define s to be a terminal if nt==0
763 // or a nonterminal if nt==1
765 func defin(nt int, s string) int {
769 if nnonter >= len(nontrst) {
770 anontrst := make([]Symb, nnonter+SYMINC)
771 copy(anontrst, nontrst)
774 nontrst[nnonter] = Symb{name: s}
775 return NTBASE + nnonter
780 if ntokens >= len(tokset) {
781 nn := ntokens + SYMINC
782 atokset := make([]Symb, nn)
783 atoklev := make([]int, nn)
785 copy(atoklev, toklev)
786 copy(atokset, tokset)
791 tokset[ntokens].name = s
794 // establish value for token
795 // single character literal
796 if s[0] == '\'' || s[0] == '"' {
797 q, err := strconv.Unquote(s)
799 errorf("invalid token: %s", err)
803 errorf("character token too long: %s", s)
807 errorf("token value 0 is illegal")
809 tokset[ntokens].noconst = true
814 tokset[ntokens].noconst = true
818 tokset[ntokens].value = val
833 for c == ' ' || c == '\n' || c == '\t' || c == '\v' || c == '\r' {
840 // skip comment -- fix
850 fmt.Printf(">>> ENDFILE %v\n", lineno)
857 fmt.Printf(">>> ={ %v\n", lineno)
862 // get, and look up, a type name (union member name)
864 for c != '>' && c != EOF && c != '\n' {
870 errorf("unterminated < ... > clause")
873 for i = 1; i <= ntypes; i++ {
874 if typeset[i] == tokname {
877 fmt.Printf(">>> TYPENAME old <%v> %v\n", tokname, lineno)
884 typeset[numbval] = tokname
886 fmt.Printf(">>> TYPENAME new <%v> %v\n", tokname, lineno)
895 if c == '\n' || c == EOF {
896 errorf("illegal or missing ' or \"")
899 tokname += string('\\')
901 } else if c == match {
903 fmt.Printf(">>> IDENTIFIER \"%v\" %v\n", tokname, lineno)
916 fmt.Printf(">>> MARK %%%% %v\n", lineno)
921 fmt.Printf(">>> PREC %%= %v\n", lineno)
926 fmt.Printf(">>> LCURLY %%{ %v\n", lineno)
932 // find a reserved word
933 for i := range resrv {
934 if tokname == resrv[i].name {
936 fmt.Printf(">>> %%%v %v %v\n", tokname,
937 resrv[i].value-PRIVATE, lineno)
939 return resrv[i].value
942 errorf("invalid escape, or illegal reserved word: %v", tokname)
944 case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
945 numbval = int(c - '0')
951 numbval = numbval*10 + int(c-'0')
955 fmt.Printf(">>> NUMBER %v %v\n", numbval, lineno)
960 if isword(c) || c == '.' || c == '$' {
965 fmt.Printf(">>> OPERATOR %v %v\n", string(c), lineno)
970 // look ahead to distinguish IDENTIFIER from IDENTCOLON
972 for c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\r' || c == '/' {
978 peekline += skipcom()
984 fmt.Printf(">>> IDENTCOLON %v: %v\n", tokname, lineno)
991 fmt.Printf(">>> IDENTIFIER %v %v\n", tokname, lineno)
996 func getword(c rune) {
998 for isword(c) || isdigit(c) || c == '.' || c == '$' {
1002 ungetrune(finput, c)
1006 // determine the type of a symbol
1008 func fdtype(t int) int {
1013 v = nontrst[t-NTBASE].value
1014 s = nontrst[t-NTBASE].name
1020 errorf("must specify type for %v", s)
1025 func chfind(t int, s string) int {
1026 if s[0] == '"' || s[0] == '\'' {
1029 for i := 0; i <= ntokens; i++ {
1030 if s == tokset[i].name {
1034 for i := 0; i <= nnonter; i++ {
1035 if s == nontrst[i].name {
1042 errorf("%v should have been defined earlier", s)
1048 // copy the union declaration to the output, and the define file if present
1053 fmt.Fprintf(ftable, "\n//line %v:%v\n", infile, lineno)
1055 fmt.Fprintf(ftable, "type %sSymType struct", prefix)
1061 c := getrune(finput)
1063 errorf("EOF encountered while processing %%union")
1071 fmt.Fprintf(ftable, "\n\tyys int")
1081 fmt.Fprintf(ftable, "\n\n")
1085 // saves code between %{ and %}
1086 // adds an import for __fmt__ the first time
1091 c := getrune(finput)
1097 fmt.Fprintf(ftable, "\n//line %v:%v\n", infile, lineno)
1099 // accumulate until %}
1100 code := make([]rune, 0, 1024)
1105 emitcode(code, lno+1)
1108 code = append(code, '%')
1110 code = append(code, c)
1117 errorf("eof before %%}")
1121 // emits code saved up from between %{ and %}
1122 // called by cpycode
1123 // adds an import for __yyfmt__ after the package clause
1125 func emitcode(code []rune, lineno int) {
1126 for i, line := range lines(code) {
1128 if !fmtImported && isPackageClause(line) {
1129 fmt.Fprintln(ftable, `import __yyfmt__ "fmt"`)
1131 fmt.Fprintf(ftable, "//line %v:%v\n\t\t", infile, lineno+i)
1139 // does this line look like a package clause? not perfect: might be confused by early comments.
1141 func isPackageClause(line []rune) bool {
1142 line = skipspace(line)
1144 // must be big enough.
1145 if len(line) < len("package X\n") {
1149 // must start with "package"
1150 for i, r := range []rune("package") {
1155 line = skipspace(line[len("package"):])
1157 // must have another identifier.
1158 if len(line) == 0 || (!unicode.IsLetter(line[0]) && line[0] != '_') {
1162 if !unicode.IsLetter(line[0]) && !unicode.IsDigit(line[0]) && line[0] != '_' {
1167 line = skipspace(line)
1169 // eol, newline, or comment must follow
1173 if line[0] == '\r' || line[0] == '\n' {
1177 return line[0] == '/' && (line[1] == '/' || line[1] == '*')
1183 // skip initial spaces
1185 func skipspace(line []rune) []rune {
1187 if line[0] != ' ' && line[0] != '\t' {
1196 // break code into lines
1198 func lines(code []rune) [][]rune {
1199 l := make([][]rune, 0, 100)
1201 // one line per loop
1203 for i = range code {
1204 if code[i] == '\n' {
1208 l = append(l, code[:i+1])
1215 // writes code to ftable
1217 func writecode(code []rune) {
1218 for _, r := range code {
1224 // skip over comments
1225 // skipcom is called after reading a '/'
1227 func skipcom() int {
1238 errorf("EOF inside comment")
1242 errorf("illegal comment")
1245 nl := 0 // lines skipped
1268 func dumpprod(curprod []int, max int) {
1270 for i := 0; i < max; i++ {
1273 fmt.Printf("[%v] %v\n", i, p)
1275 fmt.Printf("[%v] %v\n", i, symnam(p))
1281 // copy action to the next ; or closing }
1283 func cpyact(curprod []int, max int) {
1286 fmt.Fprintf(fcode, "\n\t\t//line %v:%v", infile, lineno)
1288 fmt.Fprint(fcode, "\n\t\t")
1295 c := getrune(finput)
1317 ungetrune(finput, c)
1318 if gettok() != TYPENAME {
1319 errorf("bad syntax on $<ident> clause")
1325 fmt.Fprintf(fcode, "%sVAL", prefix)
1327 // put out the proper tag...
1330 tok = fdtype(curprod[0])
1332 fmt.Fprintf(fcode, ".%v", typeset[tok])
1343 j = j*10 + int(c-'0')
1346 ungetrune(finput, c)
1349 errorf("Illegal use of $%v", j)
1351 } else if isword(c) || c == '.' {
1353 ungetrune(finput, c)
1354 if gettok() != IDENTIFIER {
1355 errorf("$ must be followed by an identifier")
1357 tokn := chfind(2, tokname)
1361 ungetrune(finput, c)
1362 } else if gettok() != NUMBER {
1363 errorf("@ must be followed by number")
1367 for j = 1; j < max; j++ {
1368 if tokn == curprod[j] {
1376 errorf("$name or $name@number not found")
1379 fcode.WriteRune('$')
1381 fcode.WriteRune('-')
1383 ungetrune(finput, c)
1386 fmt.Fprintf(fcode, "%sDollar[%v]", prefix, j)
1388 // put out the proper tag
1390 if j <= 0 && tok < 0 {
1391 errorf("must specify type of $%v", j)
1394 tok = fdtype(curprod[j])
1396 fmt.Fprintf(fcode, ".%v", typeset[tok])
1409 nc := getrune(finput)
1410 if nc != '/' && nc != '*' {
1411 ungetrune(finput, nc)
1422 if nc == '/' { // end of // comment
1425 case c == '*' && nc == '*': // end of /* comment?
1426 nnc := getrune(finput)
1428 fcode.WriteRune('*')
1429 fcode.WriteRune('/')
1433 ungetrune(finput, nnc)
1438 errorf("EOF inside comment")
1441 // character string or constant
1452 } else if c == match {
1456 errorf("newline in string or char const")
1461 errorf("EOF in string or character constant")
1465 errorf("action does not terminate")
1468 fmt.Fprint(fcode, "\n\t")
1478 infile = flag.Arg(0)
1479 finput = open(infile)
1481 errorf("cannot open %v", infile)
1486 foutput = create(vflag)
1488 errorf("can't create file %v", vflag)
1496 ftable = create(oflag)
1498 errorf("can't create file %v", oflag)
1504 // return a pointer to the name of symbol i
1506 func symnam(i int) string {
1510 s = nontrst[i-NTBASE].name
1518 // set elements 0 through n-1 to c
1520 func aryfil(v []int, n, c int) {
1521 for i := 0; i < n; i++ {
1527 // compute an array with the beginnings of productions yielding given nonterminals
1528 // The array pres points to these lists
1529 // the array pyield has the lists: the total size is only NPROD+1
1532 pres = make([][][]int, nnonter+1)
1533 curres := make([][]int, nprod)
1536 for j := 0; j <= nnonter; j++ {
1537 fmt.Printf("nnonter[%v] = %v\n", j, nontrst[j].name)
1539 for j := 0; j < nprod; j++ {
1540 fmt.Printf("prdptr[%v][0] = %v+NTBASE\n", j, prdptr[j][0]-NTBASE)
1544 fatfl = 0 // make undefined symbols nonfatal
1545 for i := 0; i <= nnonter; i++ {
1548 for j := 0; j < nprod; j++ {
1549 if prdptr[j][0] == c {
1550 curres[n] = prdptr[j][1:]
1555 errorf("nonterminal %v not defined", nontrst[i].name)
1558 pres[i] = make([][]int, n)
1559 copy(pres[i], curres)
1569 for i := 0; i <= nnonter; i++ {
1570 fmt.Printf("nonterm %d\n", i)
1572 for j := 0; j < len(curres); j++ {
1573 fmt.Printf("\tproduction %d:", j)
1575 for k := 0; k < len(prd); k++ {
1576 fmt.Printf(" %d", prd[k])
1584 // mark nonterminals which derive the empty string
1585 // also, look for nonterminals which don't derive any token strings
1591 pempty = make([]int, nnonter+1)
1593 // first, use the array pempty to detect productions that can never be reduced
1594 // set pempty to WHONOWS
1595 aryfil(pempty, nnonter+1, WHOKNOWS)
1597 // now, look at productions, marking nonterminals which derive something
1600 for i = 0; i < nprod; i++ {
1602 if pempty[prd[0]-NTBASE] != 0 {
1606 for p = 1; p < np; p++ {
1607 if prd[p] >= NTBASE && pempty[prd[p]-NTBASE] == WHOKNOWS {
1611 // production can be derived
1613 pempty[prd[0]-NTBASE] = OK
1620 // now, look at the nonterminals, to see if they are all OK
1621 for i = 0; i <= nnonter; i++ {
1622 // the added production rises or falls as the start symbol ...
1626 if pempty[i] != OK {
1628 errorf("nonterminal " + nontrst[i].name + " never derives any token string")
1637 // now, compute the pempty array, to see which nonterminals derive the empty string
1638 // set pempty to WHOKNOWS
1639 aryfil(pempty, nnonter+1, WHOKNOWS)
1641 // loop as long as we keep finding empty nonterminals
1646 for i = 1; i < nprod; i++ {
1647 // not known to be empty
1649 if pempty[prd[0]-NTBASE] != WHOKNOWS {
1653 for p = 1; p < np; p++ {
1654 if prd[p] < NTBASE || pempty[prd[p]-NTBASE] != EMPTY {
1659 // we have a nontrivially empty nonterminal
1660 pempty[prd[0]-NTBASE] = EMPTY
1662 // got one ... try for another
1670 for i := 0; i <= nnonter; i++ {
1671 if pempty[i] == EMPTY {
1672 fmt.Printf("non-term %d %s matches empty\n", i, symnam(i+NTBASE))
1678 // compute an array with the first of nonterminals
1681 var s, n, p, np, ch, i int
1685 wsets = make([]Wset, nnonter+WSETINC)
1686 pfirst = make([]Lkset, nnonter+1)
1687 for i = 0; i <= nnonter; i++ {
1688 wsets[i].ws = mkset()
1693 // initially fill the sets
1694 for s = 0; s < n; s++ {
1697 for p = 0; p < np; p++ {
1700 setbit(pfirst[i], ch)
1703 if pempty[ch-NTBASE] == 0 {
1710 // now, reflect transitivity
1714 for i = 0; i <= nnonter; i++ {
1717 for s = 0; s < n; s++ {
1720 for p = 0; p < np; p++ {
1721 ch = prd[p] - NTBASE
1725 changes |= setunion(pfirst[i], pfirst[ch])
1726 if pempty[ch] == 0 {
1738 for i = 0; i <= nnonter; i++ {
1739 fmt.Fprintf(foutput, "\n%v: %v %v\n",
1740 nontrst[i].name, pfirst[i], pempty[i])
1746 // generate the states
1751 tstates = make([]int, ntokens+1) // states generated by terminal gotos
1752 ntstates = make([]int, nnonter+1) // states generated by nonterminal gotos
1753 amem = make([]int, ACTSIZE)
1759 aryfil(clset, tbitset, 0)
1760 putitem(Pitem{prdptr[0], 0, 0, 0}, clset)
1763 pstate[2] = pstate[1]
1766 // now, the main state generation loop
1767 // first pass generates all of the states
1768 // later passes fix up lookahead
1769 // could be sped up a lot by remembering
1770 // results of the first pass rather than recomputing
1773 for more := 1; more != 0; first = 0 {
1775 for i := 0; i < nstate; i++ {
1776 if tystate[i] != MUSTDO {
1781 aryfil(temp1, nnonter+1, 0)
1783 // take state i, close it, and do gotos
1787 for p := 0; p < cwp; p++ {
1795 if pstate[i+1]-pstate[i] <= p {
1796 tystate[i] = MUSTLOOKAHEAD
1802 putitem(wsets[p].pitem, wsets[p].ws)
1803 for q := p + 1; q < cwp; q++ {
1804 // this item contributes to the goto
1805 if c == wsets[q].pitem.first {
1806 putitem(wsets[q].pitem, wsets[q].ws)
1812 state(c) // register new state
1814 temp1[c-NTBASE] = state(c)
1818 if gsdebug != 0 && foutput != nil {
1819 fmt.Fprintf(foutput, "%v: ", i)
1820 for j := 0; j <= nnonter; j++ {
1822 fmt.Fprintf(foutput, "%v %v,", nontrst[j].name, temp1[j])
1825 fmt.Fprintf(foutput, "\n")
1829 indgo[i] = apack(temp1[1:], nnonter-1) - 1
1838 // generate the closure of state i
1840 func closure(i int) {
1843 // first, copy kernel of state i to wsets
1846 for p := pstate[i]; p < q; p++ {
1847 wsets[cwp].pitem = statemem[p].pitem
1848 wsets[cwp].flag = 1 // this item must get closed
1849 copy(wsets[cwp].ws, statemem[p].look)
1853 // now, go through the loop, closing each item
1857 for u := 0; u < cwp; u++ {
1858 if wsets[u].flag == 0 {
1863 c := wsets[u].pitem.first
1866 // only interesting case is where . is before nonterminal
1870 // compute the lookahead
1871 aryfil(clset, tbitset, 0)
1873 // find items involving c
1874 for v := u; v < cwp; v++ {
1875 if wsets[v].flag != 1 || wsets[v].pitem.first != c {
1878 pi := wsets[v].pitem.prod
1879 ipi := wsets[v].pitem.off + 1
1895 // nonterminal symbol
1896 setunion(clset, pfirst[ch-NTBASE])
1897 if pempty[ch-NTBASE] == 0 {
1904 setunion(clset, wsets[v].ws)
1909 // now loop over productions derived from c
1911 curres := pres[c-NTBASE]
1915 // initially fill the sets
1916 for s := 0; s < n; s++ {
1920 // put these items into the closure
1921 // is the item there
1923 for v := 0; v < cwp; v++ {
1925 if wsets[v].pitem.off == 0 &&
1926 aryeq(wsets[v].pitem.prod, prd) != 0 {
1928 setunion(wsets[v].ws, clset) != 0 {
1936 // not there; make a new entry
1937 if cwp >= len(wsets) {
1938 awsets := make([]Wset, cwp+WSETINC)
1942 wsets[cwp].pitem = Pitem{prd, 0, prd[0], -prd[len(prd)-1]}
1944 wsets[cwp].ws = mkset()
1947 copy(wsets[cwp].ws, clset)
1954 // have computed closure; flags are reset; return
1955 if cldebug != 0 && foutput != nil {
1956 fmt.Fprintf(foutput, "\nState %v, nolook = %v\n", i, nolook)
1957 for u := 0; u < cwp; u++ {
1958 if wsets[u].flag != 0 {
1959 fmt.Fprintf(foutput, "flag set\n")
1962 fmt.Fprintf(foutput, "\t%v", writem(wsets[u].pitem))
1964 fmt.Fprintf(foutput, "\n")
1970 // sorts last state,and sees if it equals earlier ones. returns state number
1972 func state(c int) int {
1974 p1 := pstate[nstate]
1975 p2 := pstate[nstate+1]
1977 return 0 // null state
1982 for k = p1 + 1; k < p2; k++ { // make k the biggest
1983 for l = k; l > p1; l-- {
1984 if statemem[l].pitem.prodno < statemem[l-1].pitem.prodno ||
1985 statemem[l].pitem.prodno == statemem[l-1].pitem.prodno &&
1986 statemem[l].pitem.off < statemem[l-1].pitem.off {
1988 statemem[l] = statemem[l-1]
1996 size1 := p2 - p1 // size of state
2000 i = ntstates[c-NTBASE]
2006 for ; i != 0; i = mstates[i] {
2015 for l = q1; l < q2; l++ {
2016 if aryeq(statemem[l].pitem.prod, statemem[k].pitem.prod) == 0 ||
2017 statemem[l].pitem.off != statemem[k].pitem.off {
2024 pstate[nstate+1] = pstate[nstate] // delete last state
2026 // fix up lookaheads
2031 for l = q1; l < q2; l++ {
2032 if setunion(statemem[l].look, statemem[k].look) != 0 {
2043 errorf("yacc state/nolook error")
2045 pstate[nstate+2] = p2
2046 if nstate+1 >= NSTATES {
2047 errorf("too many states")
2050 mstates[nstate] = ntstates[c-NTBASE]
2051 ntstates[c-NTBASE] = nstate
2053 mstates[nstate] = tstates[c]
2056 tystate[nstate] = MUSTDO
2061 func putitem(p Pitem, set Lkset) {
2063 p.first = p.prod[p.off]
2065 if pidebug != 0 && foutput != nil {
2066 fmt.Fprintf(foutput, "putitem(%v), state %v\n", writem(p), nstate)
2068 j := pstate[nstate+1]
2069 if j >= len(statemem) {
2070 asm := make([]Item, j+STATEINC)
2074 statemem[j].pitem = p
2078 statemem[j].look = s
2081 pstate[nstate+1] = j
2085 // creates output string for item pointed to by pp
2087 func writem(pp Pitem) string {
2091 q := chcopy(nontrst[prdptr[pp.prodno][0]-NTBASE].name) + ": "
2094 pi := aryeq(p, prdptr[pp.prodno])
2108 q += chcopy(symnam(i))
2111 // an item calling for a reduction
2114 q += fmt.Sprintf(" (%v)", -i)
2121 // pack state i from temp1 into amem
2123 func apack(p []int, n int) int {
2125 // we don't need to worry about checking because
2126 // we will only look at entries known to be there...
2127 // eliminate leading and trailing 0's
2131 for ; pp <= n && p[pp] == 0; pp++ {
2139 for ; n > pp && p[n] == 0; n-- {
2143 // now, find a place for the elements from p to q, inclusive
2144 r := len(amem) - len(p)
2147 for rr := 0; rr <= r; rr++ {
2149 for pp = 0; pp < len(p); pp++ {
2151 if p[pp] != amem[qq] && amem[qq] != 0 {
2158 // we have found an acceptable k
2159 if pkdebug != 0 && foutput != nil {
2160 fmt.Fprintf(foutput, "off = %v, k = %v\n", off+rr, rr)
2163 for pp = 0; pp < len(p); pp++ {
2172 if pkdebug != 0 && foutput != nil {
2173 for pp = 0; pp <= memp; pp += 10 {
2174 fmt.Fprintf(foutput, "\n")
2175 for qq = pp; qq <= pp+9; qq++ {
2176 fmt.Fprintf(foutput, "%v ", amem[qq])
2178 fmt.Fprintf(foutput, "\n")
2183 errorf("no space in action table")
2188 // print the output for the states
2194 fmt.Fprintf(ftable, "\n//line yacctab:1")
2196 fmt.Fprintf(ftable, "\nvar %sExca = [...]int{\n", prefix)
2198 if len(errors) > 0 {
2199 stateTable = make([]Row, nstate)
2204 // output the stuff for state i
2205 for i := 0; i < nstate; i++ {
2207 if tystate[i] != MUSTLOOKAHEAD {
2214 aryfil(temp1, ntokens+nnonter+1, 0)
2215 for u = 0; u < cwp; u++ {
2216 c = wsets[u].pitem.first
2217 if c > 1 && c < NTBASE && temp1[c] == 0 {
2218 for v = u; v < cwp; v++ {
2219 if c == wsets[v].pitem.first {
2220 putitem(wsets[v].pitem, noset)
2224 } else if c > NTBASE {
2226 if temp1[c+ntokens] == 0 {
2227 temp1[c+ntokens] = amem[indgo[i]+c]
2232 temp1[1] = ACCEPTCODE
2235 // now, we have the shifts; look at the reductions
2237 for u = 0; u < cwp; u++ {
2238 c = wsets[u].pitem.first
2246 for k := 0; k <= ntokens; k++ {
2247 if bitset(us, k) == 0 {
2252 } else if temp1[k] < 0 { // reduce/reduce conflict
2254 fmt.Fprintf(foutput,
2255 "\n %v: reduce/reduce conflict (red'ns "+
2257 i, -temp1[k], lastred, symnam(k))
2259 if -temp1[k] > lastred {
2264 // potential shift/reduce conflict
2265 precftn(lastred, k, i)
2272 fmt.Fprintf(ftable, "}\n")
2273 ftable.WriteRune('\n')
2274 fmt.Fprintf(ftable, "const %sNprod = %v\n", prefix, nprod)
2275 fmt.Fprintf(ftable, "const %sPrivate = %v\n", prefix, PRIVATE)
2276 ftable.WriteRune('\n')
2277 fmt.Fprintf(ftable, "var %sTokenNames []string\n", prefix)
2278 fmt.Fprintf(ftable, "var %sStates []string\n", prefix)
2282 // decide a shift/reduce conflict by precedence.
2283 // r is a rule number, t a token number
2284 // the conflict is in state s
2285 // temp1[t] is changed to reflect the action
2287 func precftn(r, t, s int) {
2292 if PLEVEL(lt) == 0 || PLEVEL(lp) == 0 {
2295 fmt.Fprintf(foutput,
2296 "\n%v: shift/reduce conflict (shift %v(%v), red'n %v(%v)) on %v",
2297 s, temp1[t], PLEVEL(lt), r, PLEVEL(lp), symnam(t))
2302 if PLEVEL(lt) == PLEVEL(lp) {
2304 } else if PLEVEL(lt) > PLEVEL(lp) {
2305 action = RASC // shift
2310 case BASC: // error action
2312 case LASC: // reduce
2319 // temp1 has the actions, lastred the default
2324 // find the best choice for lastred
2327 for j := 0; j <= ntokens; j++ {
2331 if temp1[j]+lastred == 0 {
2334 // count the number of appearances of temp1[j]
2337 levprd[tred] |= REDFLAG
2338 for p = 0; p <= ntokens; p++ {
2339 if temp1[p]+tred == 0 {
2350 // for error recovery, arrange that, if there is a shift on the
2351 // error recovery token, `error', that the default be the error action
2357 // clear out entries in temp1 which equal lastred
2358 // count entries in optst table
2360 for p = 0; p <= ntokens; p++ {
2362 if p1+lastred == 0 {
2366 if p1 > 0 && p1 != ACCEPTCODE && p1 != ERRCODE {
2374 os := make([]int, n*2)
2376 for p = 0; p <= ntokens; p++ {
2381 } else if p1 == ACCEPTCODE {
2383 } else if p1 == ERRCODE {
2394 fmt.Fprintf(ftable, "\t-1, %v,\n", i)
2397 fmt.Fprintf(ftable, "\t%v, %v,\n", p, p1)
2403 fmt.Fprintf(ftable, "\t-2, %v,\n", lastred)
2411 func wrstate(i int) {
2415 if len(errors) > 0 {
2416 actions := append([]int(nil), temp1...)
2417 defaultAction := ERRCODE
2419 defaultAction = -lastred
2421 stateTable[i] = Row{actions, defaultAction}
2427 fmt.Fprintf(foutput, "\nstate %v\n", i)
2429 for pp = pstate[i]; pp < qq; pp++ {
2430 fmt.Fprintf(foutput, "\t%v\n", writem(statemem[pp].pitem))
2432 if tystate[i] == MUSTLOOKAHEAD {
2433 // print out empty productions in closure
2434 for u = pstate[i+1] - pstate[i]; u < cwp; u++ {
2435 if wsets[u].pitem.first < 0 {
2436 fmt.Fprintf(foutput, "\t%v\n", writem(wsets[u].pitem))
2441 // check for state equal to another
2442 for j0 = 0; j0 <= ntokens; j0++ {
2445 fmt.Fprintf(foutput, "\n\t%v ", symnam(j0))
2447 // shift, error, or accept
2449 if j1 == ACCEPTCODE {
2450 fmt.Fprintf(foutput, "accept")
2451 } else if j1 == ERRCODE {
2452 fmt.Fprintf(foutput, "error")
2454 fmt.Fprintf(foutput, "shift %v", j1)
2457 fmt.Fprintf(foutput, "reduce %v (src line %v)", -j1, rlines[-j1])
2462 // output the final production
2464 fmt.Fprintf(foutput, "\n\t. reduce %v (src line %v)\n\n",
2465 lastred, rlines[lastred])
2467 fmt.Fprintf(foutput, "\n\t. error\n\n")
2470 // now, output nonterminal actions
2472 for j0 = 1; j0 <= nnonter; j0++ {
2475 fmt.Fprintf(foutput, "\t%v goto %v\n", symnam(j0+NTBASE), temp1[j1])
2481 // output the gotos for the nontermninals
2484 for i := 1; i <= nnonter; i++ {
2487 // find the best one to make default
2491 // is j the most frequent
2492 for j := 0; j < nstate; j++ {
2493 if tystate[j] == 0 {
2496 if tystate[j] == best {
2500 // is tystate[j] the most frequent
2503 for k := j; k < nstate; k++ {
2504 if tystate[k] == cbest {
2514 // best is now the default entry
2515 zzgobest += times - 1
2517 for j := 0; j < nstate; j++ {
2518 if tystate[j] != 0 && tystate[j] != best {
2522 goent := make([]int, 2*n+1)
2524 for j := 0; j < nstate; j++ {
2525 if tystate[j] != 0 && tystate[j] != best {
2528 goent[n] = tystate[j]
2546 // output the gotos for nonterminal c
2548 func go2gen(c int) {
2551 // first, find nonterminals with gotos on c
2552 aryfil(temp1, nnonter+1, 0)
2557 for i = 0; i < nprod; i++ {
2558 // cc is a nonterminal with a goto on c
2559 cc = prdptr[i][1] - NTBASE
2560 if cc >= 0 && temp1[cc] != 0 {
2561 // thus, the left side of production i does too
2562 cc = prdptr[i][0] - NTBASE
2571 // now, we have temp1[c] = 1 if a goto on c in closure of cc
2572 if g2debug != 0 && foutput != nil {
2573 fmt.Fprintf(foutput, "%v: gotos on ", nontrst[c].name)
2574 for i = 0; i <= nnonter; i++ {
2576 fmt.Fprintf(foutput, "%v ", nontrst[i].name)
2579 fmt.Fprintf(foutput, "\n")
2582 // now, go through and put gotos into tystate
2583 aryfil(tystate, nstate, 0)
2584 for i = 0; i < nstate; i++ {
2586 for p = pstate[i]; p < q; p++ {
2587 cc = statemem[p].pitem.first
2589 // goto on c is possible
2590 if temp1[cc-NTBASE] != 0 {
2591 tystate[i] = amem[indgo[i]+c]
2600 // in order to free up the mem and amem arrays for the optimizer,
2601 // and still be able to output yyr1, etc., after the sizes of
2602 // the action array is known, we hide the nonterminals
2603 // derived by productions in levprd.
2608 for i := 1; i < nprod; i++ {
2609 if (levprd[i] & REDFLAG) == 0 {
2611 fmt.Fprintf(foutput, "Rule not reduced: %v\n",
2612 writem(Pitem{prdptr[i], 0, 0, i}))
2614 fmt.Printf("rule %v never reduced\n", writem(Pitem{prdptr[i], 0, 0, i}))
2617 levprd[i] = prdptr[i][0] - NTBASE
2620 fmt.Printf("%v rules never reduced\n", nred)
2625 var j, k, p, q, i int
2628 pgo = make([]int, nnonter+1)
2632 for i = 0; i < nstate; i++ {
2637 for p = 0; p < q; p += 2 {
2646 // nontrivial situation
2648 // j is now the range
2649 // j -= k; // call scj
2654 tystate[i] = q + 2*j
2660 // initialize ggreed table
2661 ggreed = make([]int, nnonter+1)
2662 for i = 1; i <= nnonter; i++ {
2666 // minimum entry index is always 0
2669 for p = 0; p < q; p += 2 {
2675 ggreed[i] = ggreed[i] + 2*j
2681 // now, prepare to put the shift actions into the amem array
2682 for i = 0; i < ACTSIZE; i++ {
2686 for i = 0; i < nstate; i++ {
2687 if tystate[i] == 0 && adb > 1 {
2688 fmt.Fprintf(ftable, "State %v: null\n", i)
2705 for p = 0; p <= maxa; p += 10 {
2706 fmt.Fprintf(ftable, "%v ", p)
2707 for i = 0; i < 10; i++ {
2708 fmt.Fprintf(ftable, "%v ", amem[p+i])
2710 ftable.WriteRune('\n')
2724 for i := 1; i <= nnonter; i++ {
2725 if ggreed[i] >= max {
2730 for i := 0; i < nstate; i++ {
2731 if tystate[i] >= max {
2745 // enter gotos on nonterminal i into array amem
2751 // now, find amem place for it
2753 for p := 0; p < ACTSIZE; p++ {
2757 for r := 0; r < nq; r += 2 {
2761 if maxa >= ACTSIZE {
2762 errorf("a array overflow")
2770 // we have found amem spot
2775 for r := 0; r < nq; r += 2 {
2781 fmt.Fprintf(ftable, "Nonterminal %v, entry at %v\n", i, pgo[i])
2785 errorf("cannot place goto %v\n", i)
2793 // enter state i into the amem array
2798 // find an acceptable place
2799 for n := -maxoff; n < ACTSIZE; n++ {
2801 for r := 0; r < nq; r += 2 {
2803 if s < 0 || s > ACTSIZE {
2808 } else if amem[s] != q[r+1] {
2813 // check the position equals another only if the states are identical
2814 for j := 0; j < nstate; j++ {
2817 // we have some disagreement
2821 if nq == len(optst[j]) {
2826 fmt.Fprintf(ftable, "State %v: entry at"+
2827 "%v equals state %v\n",
2833 // we have some disagreement
2838 for r := 0; r < nq; r += 2 {
2843 if amem[s] != 0 && amem[s] != q[r+1] {
2844 errorf("clobber of a array, pos'n %v, by %v", s, q[r+1])
2850 fmt.Fprintf(ftable, "State %v: entry at %v\n", i, indgo[i])
2854 errorf("Error; failure to place state %v", i)
2858 // this version is for limbo
2859 // write out the optimized parser
2862 ftable.WriteRune('\n')
2863 fmt.Fprintf(ftable, "const %sLast = %v\n\n", prefix, maxa+1)
2864 arout("Act", amem, maxa+1)
2865 arout("Pact", indgo, nstate)
2866 arout("Pgo", pgo, nnonter+1)
2870 // put out other arrays, copy the parsers
2875 arout("R1", levprd, nprod)
2876 aryfil(temp1, nprod, 0)
2879 //yyr2 is the number of rules for each production
2881 for i = 1; i < nprod; i++ {
2882 temp1[i] = len(prdptr[i]) - 2
2884 arout("R2", temp1, nprod)
2886 aryfil(temp1, nstate, -1000)
2887 for i = 0; i <= ntokens; i++ {
2888 for j := tstates[i]; j != 0; j = mstates[j] {
2892 for i = 0; i <= nnonter; i++ {
2893 for j = ntstates[i]; j != 0; j = mstates[j] {
2897 arout("Chk", temp1, nstate)
2898 arout("Def", defact, nstate)
2900 // put out token translation tables
2901 // table 1 has 0-256
2902 aryfil(temp1, 256, 0)
2904 for i = 1; i <= ntokens; i++ {
2906 if j >= 0 && j < 256 {
2908 fmt.Print("yacc bug -- cannot have 2 different Ts with same value\n")
2909 fmt.Printf(" %s and %s\n", tokset[i].name, tokset[temp1[j]].name)
2918 for i = 0; i <= c; i++ {
2923 arout("Tok1", temp1, c+1)
2925 // table 2 has PRIVATE-PRIVATE+256
2926 aryfil(temp1, 256, 0)
2928 for i = 1; i <= ntokens; i++ {
2929 j = tokset[i].value - PRIVATE
2930 if j >= 0 && j < 256 {
2932 fmt.Print("yacc bug -- cannot have 2 different Ts with same value\n")
2933 fmt.Printf(" %s and %s\n", tokset[i].name, tokset[temp1[j]].name)
2942 arout("Tok2", temp1, c+1)
2944 // table 3 has everything else
2945 fmt.Fprintf(ftable, "var %sTok3 = [...]int{\n\t", prefix)
2947 for i = 1; i <= ntokens; i++ {
2949 if j >= 0 && j < 256 {
2952 if j >= PRIVATE && j < 256+PRIVATE {
2957 ftable.WriteRune(' ')
2959 fmt.Fprintf(ftable, "%d, %d,", j, i)
2962 fmt.Fprint(ftable, "\n\t")
2966 ftable.WriteRune(' ')
2968 fmt.Fprintf(ftable, "%d,\n}\n", 0)
2970 // Custom error messages.
2971 fmt.Fprintf(ftable, "\n")
2972 fmt.Fprintf(ftable, "var %sErrorMessages = [...]struct {\n", prefix)
2973 fmt.Fprintf(ftable, "\tstate int\n")
2974 fmt.Fprintf(ftable, "\ttoken int\n")
2975 fmt.Fprintf(ftable, "\tmsg string\n")
2976 fmt.Fprintf(ftable, "}{\n")
2977 for _, error := range errors {
2978 lineno = error.lineno
2979 state, token := runMachine(error.tokens)
2980 fmt.Fprintf(ftable, "\t{%v, %v, %s},\n", state, token, error.msg)
2982 fmt.Fprintf(ftable, "}\n")
2985 ch := getrune(finput)
2987 ftable.WriteRune(ch)
2988 ch = getrune(finput)
2993 fmt.Fprintf(ftable, "\n//line yaccpar:1\n")
2996 parts := strings.SplitN(yaccpar, prefix+"run()", 2)
2997 fmt.Fprintf(ftable, "%v", parts[0])
2998 ftable.Write(fcode.Bytes())
2999 fmt.Fprintf(ftable, "%v", parts[1])
3002 func runMachine(tokens []string) (state, token int) {
3009 token = chfind(2, tokens[i])
3013 row := stateTable[state]
3016 if token >= NTBASE {
3017 c = token - NTBASE + ntokens
3019 action := row.actions[c]
3021 action = row.defaultAction
3025 case action == ACCEPTCODE:
3026 errorf("tokens are accepted")
3028 case action == ERRCODE:
3029 if token >= NTBASE {
3030 errorf("error at non-terminal token %s", symnam(token))
3034 // Shift to state action.
3035 stack = append(stack, state)
3040 // Reduce by production -action.
3041 prod := prdptr[-action]
3042 if rhsLen := len(prod) - 2; rhsLen > 0 {
3043 n := len(stack) - rhsLen
3055 func arout(s string, v []int, n int) {
3057 fmt.Fprintf(ftable, "var %v = [...]int{\n", s)
3058 for i := 0; i < n; i++ {
3060 fmt.Fprintf(ftable, "\n\t")
3062 ftable.WriteRune(' ')
3064 fmt.Fprintf(ftable, "%d,", v[i])
3066 fmt.Fprintf(ftable, "\n}\n")
3070 // output the summary on y.output
3074 fmt.Fprintf(foutput, "\n%v terminals, %v nonterminals\n", ntokens, nnonter+1)
3075 fmt.Fprintf(foutput, "%v grammar rules, %v/%v states\n", nprod, nstate, NSTATES)
3076 fmt.Fprintf(foutput, "%v shift/reduce, %v reduce/reduce conflicts reported\n", zzsrconf, zzrrconf)
3077 fmt.Fprintf(foutput, "%v working sets used\n", len(wsets))
3078 fmt.Fprintf(foutput, "memory: parser %v/%v\n", memp, ACTSIZE)
3079 fmt.Fprintf(foutput, "%v extra closures\n", zzclose-2*nstate)
3080 fmt.Fprintf(foutput, "%v shift entries, %v exceptions\n", zzacent, zzexcp)
3081 fmt.Fprintf(foutput, "%v goto entries\n", zzgoent)
3082 fmt.Fprintf(foutput, "%v entries saved by goto default\n", zzgobest)
3084 if zzsrconf != 0 || zzrrconf != 0 {
3085 fmt.Printf("\nconflicts: ")
3087 fmt.Printf("%v shift/reduce", zzsrconf)
3089 if zzsrconf != 0 && zzrrconf != 0 {
3093 fmt.Printf("%v reduce/reduce", zzrrconf)
3100 // write optimizer summary
3107 for p := maxa; p >= 0; p-- {
3113 fmt.Fprintf(foutput, "Optimizer space used: output %v/%v\n", maxa+1, ACTSIZE)
3114 fmt.Fprintf(foutput, "%v table entries, %v zero\n", maxa+1, i)
3115 fmt.Fprintf(foutput, "maximum spread: %v, maximum offset: %v\n", maxspr, maxoff)
3119 // copies and protects "'s in q
3121 func chcopy(q string) string {
3125 for i = 0; i < len(q); i++ {
3135 fmt.Fprintf(stderr, "usage: yacc [-o output] [-v parsetable] input\n")
3139 func bitset(set Lkset, bit int) int { return set[bit>>5] & (1 << uint(bit&31)) }
3141 func setbit(set Lkset, bit int) { set[bit>>5] |= (1 << uint(bit&31)) }
3143 func mkset() Lkset { return make([]int, tbitset) }
3146 // set a to the union of a and b
3147 // return 1 if b is not a subset of a, 0 otherwise
3149 func setunion(a, b []int) int {
3151 for i := 0; i < tbitset; i++ {
3162 func prlook(p Lkset) {
3164 fmt.Fprintf(foutput, "\tNULL")
3167 fmt.Fprintf(foutput, " { ")
3168 for j := 0; j <= ntokens; j++ {
3169 if bitset(p, j) != 0 {
3170 fmt.Fprintf(foutput, "%v ", symnam(j))
3173 fmt.Fprintf(foutput, "}")
3181 func isdigit(c rune) bool { return c >= '0' && c <= '9' }
3183 func isword(c rune) bool {
3184 return c >= 0xa0 || c == '_' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
3188 // return 1 if 2 arrays are equal
3189 // return 0 if not equal
3191 func aryeq(a []int, b []int) int {
3196 for ll := 0; ll < n; ll++ {
3204 func getrune(f *bufio.Reader) rune {
3208 if peekrune == EOF {
3216 c, n, err := f.ReadRune()
3221 errorf("read error: %v", err)
3223 //fmt.Printf("rune = %v n=%v\n", string(c), n);
3227 func ungetrune(f *bufio.Reader, c rune) {
3229 panic("ungetc - not finput")
3232 panic("ungetc - 2nd unget")
3237 func write(f *bufio.Writer, b []byte, n int) int {
3241 func open(s string) *bufio.Reader {
3242 fi, err := os.Open(s)
3244 errorf("error opening %v: %v", s, err)
3246 //fmt.Printf("open %v\n", s);
3247 return bufio.NewReader(fi)
3250 func create(s string) *bufio.Writer {
3251 fo, err := os.Create(s)
3253 errorf("error creating %v: %v", s, err)
3255 //fmt.Printf("create %v mode %v\n", s);
3256 return bufio.NewWriter(fo)
3260 // write out error comment
3262 func lerrorf(lineno int, s string, v ...interface{}) {
3264 fmt.Fprintf(stderr, s, v...)
3265 fmt.Fprintf(stderr, ": %v:%v\n", infile, lineno)
3272 func errorf(s string, v ...interface{}) {
3273 lerrorf(lineno, s, v...)
3276 func exit(status int) {
3294 src, err := ioutil.ReadFile(oflag)
3298 src, err = format.Source(src)
3302 ioutil.WriteFile(oflag, src, 0666)
3305 var yaccpar string // will be processed version of yaccpartext: s/$$/prefix/g
3307 /* parser for yacc output */
3311 $$ErrorVerbose = false
3314 type $$Lexer interface {
3315 Lex(lval *$$SymType) int
3319 type $$Parser interface {
3324 type $$ParserImpl struct {
3326 stack [$$InitialStackSize]$$SymType
3330 func (p *$$ParserImpl) Lookahead() int {
3334 func $$NewParser() $$Parser {
3335 return &$$ParserImpl{}
3338 const $$Flag = -1000
3340 func $$Tokname(c int) string {
3341 if c >= 1 && c-1 < len($$Toknames) {
3342 if $$Toknames[c-1] != "" {
3343 return $$Toknames[c-1]
3346 return __yyfmt__.Sprintf("tok-%v", c)
3349 func $$Statname(s int) string {
3350 if s >= 0 && s < len($$Statenames) {
3351 if $$Statenames[s] != "" {
3352 return $$Statenames[s]
3355 return __yyfmt__.Sprintf("state-%v", s)
3358 func $$ErrorMessage(state, lookAhead int) string {
3361 if !$$ErrorVerbose {
3362 return "syntax error"
3365 for _, e := range $$ErrorMessages {
3366 if e.state == state && e.token == lookAhead {
3367 return "syntax error: " + e.msg
3371 res := "syntax error: unexpected " + $$Tokname(lookAhead)
3373 // To match Bison, suggest at most four expected tokens.
3374 expected := make([]int, 0, 4)
3376 // Look for shiftable tokens.
3377 base := $$Pact[state]
3378 for tok := TOKSTART; tok-1 < len($$Toknames); tok++ {
3379 if n := base + tok; n >= 0 && n < $$Last && $$Chk[$$Act[n]] == tok {
3380 if len(expected) == cap(expected) {
3383 expected = append(expected, tok)
3387 if $$Def[state] == -2 {
3389 for $$Exca[i] != -1 || $$Exca[i+1] != state {
3393 // Look for tokens that we accept or reduce.
3394 for i += 2; $$Exca[i] >= 0; i += 2 {
3396 if tok < TOKSTART || $$Exca[i+1] == 0 {
3399 if len(expected) == cap(expected) {
3402 expected = append(expected, tok)
3405 // If the default action is to accept or reduce, give up.
3406 if $$Exca[i+1] != 0 {
3411 for i, tok := range expected {
3413 res += ", expecting "
3417 res += $$Tokname(tok)
3422 func $$lex1(lex $$Lexer, lval *$$SymType) (char, token int) {
3424 char = lex.Lex(lval)
3429 if char < len($$Tok1) {
3430 token = $$Tok1[char]
3433 if char >= $$Private {
3434 if char < $$Private+len($$Tok2) {
3435 token = $$Tok2[char-$$Private]
3439 for i := 0; i < len($$Tok3); i += 2 {
3449 token = $$Tok2[1] /* unknown char */
3452 __yyfmt__.Printf("lex %s(%d)\n", $$Tokname(token), uint(char))
3457 func $$Parse($$lex $$Lexer) int {
3458 return $$NewParser().Parse($$lex)
3461 func ($$rcvr *$$ParserImpl) Parse($$lex $$Lexer) int {
3464 var $$Dollar []$$SymType
3465 _ = $$Dollar // silence set and not used
3466 $$S := $$rcvr.stack[:]
3468 Nerrs := 0 /* number of errors */
3469 Errflag := 0 /* error recovery flag */
3472 $$token := -1 // $$rcvr.char translated into internal numbering
3474 // Make sure we report no lookahead when not parsing.
3489 /* put a state and value onto the stack */
3491 __yyfmt__.Printf("char %v in %v\n", $$Tokname($$token), $$Statname($$state))
3495 if $$p >= len($$S) {
3496 nyys := make([]$$SymType, len($$S)*2)
3501 $$S[$$p].yys = $$state
3504 $$n = $$Pact[$$state]
3506 goto $$default /* simple state */
3508 if $$rcvr.char < 0 {
3509 $$rcvr.char, $$token = $$lex1($$lex, &$$rcvr.lval)
3512 if $$n < 0 || $$n >= $$Last {
3516 if $$Chk[$$n] == $$token { /* valid shift */
3528 /* default state action */
3529 $$n = $$Def[$$state]
3531 if $$rcvr.char < 0 {
3532 $$rcvr.char, $$token = $$lex1($$lex, &$$rcvr.lval)
3535 /* look through exception table */
3538 if $$Exca[xi+0] == -1 && $$Exca[xi+1] == $$state {
3543 for xi += 2; ; xi += 2 {
3545 if $$n < 0 || $$n == $$token {
3555 /* error ... attempt to resume parsing */
3557 case 0: /* brand new error */
3558 $$lex.Error($$ErrorMessage($$state, $$token))
3561 __yyfmt__.Printf("%s", $$Statname($$state))
3562 __yyfmt__.Printf(" saw %s\n", $$Tokname($$token))
3566 case 1, 2: /* incompletely recovered error ... try again */
3569 /* find a state where "error" is a legal shift action */
3571 $$n = $$Pact[$$S[$$p].yys] + $$ErrCode
3572 if $$n >= 0 && $$n < $$Last {
3573 $$state = $$Act[$$n] /* simulate a shift of "error" */
3574 if $$Chk[$$state] == $$ErrCode {
3579 /* the current p has no shift on "error", pop stack */
3581 __yyfmt__.Printf("error recovery pops state %d\n", $$S[$$p].yys)
3585 /* there is no state on the stack with an error shift ... abort */
3588 case 3: /* no shift yet; clobber input char */
3590 __yyfmt__.Printf("error recovery discards %s\n", $$Tokname($$token))
3592 if $$token == $$EofCode {
3597 goto $$newstate /* try again in the same state */
3601 /* reduction by production $$n */
3603 __yyfmt__.Printf("reduce %v in:\n\t%v\n", $$n, $$Statname($$state))
3608 _ = $$pt // guard against "declared and not used"
3611 // $$p is now the index of $0. Perform the default action. Iff the
3612 // reduced production is ε, $1 is possibly out of range.
3613 if $$p+1 >= len($$S) {
3614 nyys := make([]$$SymType, len($$S)*2)
3620 /* consult goto table to find next state */
3623 $$j := $$g + $$S[$$p].yys + 1
3626 $$state = $$Act[$$g]
3628 $$state = $$Act[$$j]
3629 if $$Chk[$$state] != -$$n {
3630 $$state = $$Act[$$g]
3633 // dummy call; replaced with literal code
3635 goto $$stack /* stack new state and value */