cmd/goyacc: move go tool yacc from the go repo

This moves the 'go tool yacc' command from the main Go repo
to x/tools.

Copied from go rev 795ad07b3 + doc changes from "go tool yacc" to "goyacc".

Updates golang/go#11229

Change-Id: I6d17911a3bf64724c090c4fe4903238e3bce3b8c
Reviewed-on: https://go-review.googlesource.com/27324
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
diff --git a/cmd/goyacc/doc.go b/cmd/goyacc/doc.go
new file mode 100644
index 0000000..03ffee7
--- /dev/null
+++ b/cmd/goyacc/doc.go
@@ -0,0 +1,70 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+
+Goyacc is a version of yacc for Go.
+It is written in Go and generates parsers written in Go.
+
+Usage:
+
+	goyacc args...
+
+It is largely transliterated from the Inferno version written in Limbo
+which in turn was largely transliterated from the Plan 9 version
+written in C and documented at
+
+	https://9p.io/magic/man2html/1/yacc
+
+Adepts of the original yacc will have no trouble adapting to this
+form of the tool.
+
+The directory $GOPATH/src/golang.org/x/tools/cmd/goyacc/testdata/expr
+is a yacc program for a very simple expression parser. See expr.y and
+main.go in that directory for examples of how to write and build
+goyacc programs.
+
+The generated parser is reentrant. The parsing function yyParse expects
+to be given an argument that conforms to the following interface:
+
+	type yyLexer interface {
+		Lex(lval *yySymType) int
+		Error(e string)
+	}
+
+Lex should return the token identifier, and place other token
+information in lval (which replaces the usual yylval).
+Error is equivalent to yyerror in the original yacc.
+
+Code inside the grammar actions may refer to the variable yylex,
+which holds the yyLexer passed to yyParse.
+
+Clients that need to understand more about the parser state can
+create the parser separately from invoking it. The function yyNewParser
+returns a yyParser conforming to the following interface:
+
+	type yyParser interface {
+		Parse(yyLex) int
+		Lookahead() int
+	}
+
+Parse runs the parser; the top-level call yyParse(yylex) is equivalent
+to yyNewParser().Parse(yylex).
+
+Lookahead can be called during grammar actions to read (but not consume)
+the value of the current lookahead token, as returned by yylex.Lex.
+If there is no current lookahead token (because the parser has not called Lex
+or has consumed the token returned by the most recent call to Lex),
+Lookahead returns -1. Calling Lookahead is equivalent to reading
+yychar from within in a grammar action.
+
+Multiple grammars compiled into a single program should be placed in
+distinct packages.  If that is impossible, the "-p prefix" flag to
+goyacc sets the prefix, by default yy, that begins the names of
+symbols, including types, the parser, and the lexer, generated and
+referenced by yacc's generated code.  Setting it to distinct values
+allows multiple grammars to be placed in a single package.
+
+*/
+package main
diff --git a/cmd/goyacc/testdata/expr/README b/cmd/goyacc/testdata/expr/README
new file mode 100644
index 0000000..302ef57
--- /dev/null
+++ b/cmd/goyacc/testdata/expr/README
@@ -0,0 +1,20 @@
+This directory contains a simple program demonstrating how to use
+the Go version of yacc.
+
+To build it:
+
+	$ go generate
+	$ go build
+
+or
+
+	$ go generate
+	$ go run expr.go
+
+The file main.go contains the "go generate" command to run yacc to
+create expr.go from expr.y. It also has the package doc comment,
+as godoc will not scan the .y file.
+
+The actual implementation is in expr.y.
+
+The program is not installed in the binary distributions of Go.
diff --git a/cmd/goyacc/testdata/expr/expr.y b/cmd/goyacc/testdata/expr/expr.y
new file mode 100644
index 0000000..ba4a1b2
--- /dev/null
+++ b/cmd/goyacc/testdata/expr/expr.y
@@ -0,0 +1,202 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This is an example of a goyacc program.
+// To build it:
+// goyacc -p "expr" expr.y (produces y.go)
+// go build -o expr y.go
+// expr
+// > <type an expression>
+
+%{
+
+package main
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"io"
+	"log"
+	"math/big"
+	"os"
+	"unicode/utf8"
+)
+
+%}
+
+%union {
+	num *big.Rat
+}
+
+%type	<num>	expr expr1 expr2 expr3
+
+%token '+' '-' '*' '/' '(' ')'
+
+%token	<num>	NUM
+
+%%
+
+top:
+	expr
+	{
+		if $1.IsInt() {
+			fmt.Println($1.Num().String())
+		} else {
+			fmt.Println($1.String())
+		}
+	}
+
+expr:
+	expr1
+|	'+' expr
+	{
+		$$ = $2
+	}
+|	'-' expr
+	{
+		$$ = $2.Neg($2)
+	}
+
+expr1:
+	expr2
+|	expr1 '+' expr2
+	{
+		$$ = $1.Add($1, $3)
+	}
+|	expr1 '-' expr2
+	{
+		$$ = $1.Sub($1, $3)
+	}
+
+expr2:
+	expr3
+|	expr2 '*' expr3
+	{
+		$$ = $1.Mul($1, $3)
+	}
+|	expr2 '/' expr3
+	{
+		$$ = $1.Quo($1, $3)
+	}
+
+expr3:
+	NUM
+|	'(' expr ')'
+	{
+		$$ = $2
+	}
+
+
+%%
+
+// The parser expects the lexer to return 0 on EOF.  Give it a name
+// for clarity.
+const eof = 0
+
+// The parser uses the type <prefix>Lex as a lexer. It must provide
+// the methods Lex(*<prefix>SymType) int and Error(string).
+type exprLex struct {
+	line []byte
+	peek rune
+}
+
+// The parser calls this method to get each new token. This
+// implementation returns operators and NUM.
+func (x *exprLex) Lex(yylval *exprSymType) int {
+	for {
+		c := x.next()
+		switch c {
+		case eof:
+			return eof
+		case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+			return x.num(c, yylval)
+		case '+', '-', '*', '/', '(', ')':
+			return int(c)
+
+		// Recognize Unicode multiplication and division
+		// symbols, returning what the parser expects.
+		case '×':
+			return '*'
+		case '÷':
+			return '/'
+
+		case ' ', '\t', '\n', '\r':
+		default:
+			log.Printf("unrecognized character %q", c)
+		}
+	}
+}
+
+// Lex a number.
+func (x *exprLex) num(c rune, yylval *exprSymType) int {
+	add := func(b *bytes.Buffer, c rune) {
+		if _, err := b.WriteRune(c); err != nil {
+			log.Fatalf("WriteRune: %s", err)
+		}
+	}
+	var b bytes.Buffer
+	add(&b, c)
+	L: for {
+		c = x.next()
+		switch c {
+		case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', 'e', 'E':
+			add(&b, c)
+		default:
+			break L
+		}
+	}
+	if c != eof {
+		x.peek = c
+	}
+	yylval.num = &big.Rat{}
+	_, ok := yylval.num.SetString(b.String())
+	if !ok {
+		log.Printf("bad number %q", b.String())
+		return eof
+	}
+	return NUM
+}
+
+// Return the next rune for the lexer.
+func (x *exprLex) next() rune {
+	if x.peek != eof {
+		r := x.peek
+		x.peek = eof
+		return r
+	}
+	if len(x.line) == 0 {
+		return eof
+	}
+	c, size := utf8.DecodeRune(x.line)
+	x.line = x.line[size:]
+	if c == utf8.RuneError && size == 1 {
+		log.Print("invalid utf8")
+		return x.next()
+	}
+	return c
+}
+
+// The parser calls this method on a parse error.
+func (x *exprLex) Error(s string) {
+	log.Printf("parse error: %s", s)
+}
+
+func main() {
+	in := bufio.NewReader(os.Stdin)
+	for {
+		if _, err := os.Stdout.WriteString("> "); err != nil {
+			log.Fatalf("WriteString: %s", err)
+		}
+		line, err := in.ReadBytes('\n')
+		if err == io.EOF {
+			return
+		}
+		if err != nil {
+			log.Fatalf("ReadBytes: %s", err)
+		}
+
+		exprParse(&exprLex{line: line})
+	}
+}
diff --git a/cmd/goyacc/testdata/expr/main.go b/cmd/goyacc/testdata/expr/main.go
new file mode 100644
index 0000000..22e3543
--- /dev/null
+++ b/cmd/goyacc/testdata/expr/main.go
@@ -0,0 +1,14 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file holds the go generate command to run yacc on the grammar in expr.y.
+// To build expr:
+//	% go generate
+//	% go build
+
+//go:generate goyacc -o expr.go -p "expr" expr.y
+
+// Expr is a simple expression evaluator that serves as a working example of
+// how to use Go's yacc implementation.
+package main
diff --git a/cmd/goyacc/yacc.go b/cmd/goyacc/yacc.go
new file mode 100644
index 0000000..8a5df05
--- /dev/null
+++ b/cmd/goyacc/yacc.go
@@ -0,0 +1,3641 @@
+/*
+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  = 30000
+	NSTATES  = 2000
+	TEMPSIZE = 2000
+
+	SYMINC   = 50  // increase for non-term or term
+	RULEINC  = 50  // increase for max rule length prodptr[i]
+	PRODINC  = 100 // increase for productions     prodptr
+	WSETINC  = 50  // increase for working sets    wsets
+	STATEINC = 200 // increase for states          statemem
+
+	NAMESIZE = 50
+	NTYPES   = 63
+	ISIZE    = 400
+
+	PRIVATE = 0xE000 // unicode private use
+
+	// relationships which must hold:
+	//	TEMPSIZE >= NTERMS + NNONTERM + 1;
+	//	TEMPSIZE >= NSTATES;
+	//
+
+	NTBASE     = 010000
+	ERRCODE    = 8190
+	ACCEPTCODE = 8191
+	YYLEXUNK   = 3
+	TOKSTART   = 4 //index of first defined token
+)
+
+// no, left, right, binary assoc.
+const (
+	NOASC = iota
+	LASC
+	RASC
+	BASC
+)
+
+// flags for state generation
+const (
+	DONE = iota
+	MUSTDO
+	MUSTLOOKAHEAD
+)
+
+// flags for a rule having an action, and being reduced
+const (
+	ACTFLAG = 1 << (iota + 2)
+	REDFLAG
+)
+
+// output parser flags
+const yyFlag = -1000
+
+// parse tokens
+const (
+	IDENTIFIER = PRIVATE + iota
+	MARK
+	TERM
+	LEFT
+	RIGHT
+	BINARY
+	PREC
+	LCURLY
+	IDENTCOLON
+	NUMBER
+	START
+	TYPEDEF
+	TYPENAME
+	UNION
+	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 [NTYPES]string // pointers to type tags
+
+// token information
+
+var ntokens = 0 // number of tokens
+var tokset []Symb
+var toklev []int // vector with the precedence of the terminals
+
+// nonterminal information
+
+var nnonter = -1 // the number of nonterminals
+var nontrst []Symb
+var start int // start symbol
+
+// state information
+
+var nstate = 0                      // number of states
+var pstate = make([]int, NSTATES+2) // index into statemem to the descriptions of the states
+var statemem []Item
+var tystate = make([]int, NSTATES) // contains type information about the states
+var tstates []int                  // states generated by terminal gotos
+var ntstates []int                 // states generated by nonterminal gotos
+var mstates = make([]int, NSTATES) // chain of overflows of term/nonterm generation lists
+var lastred int                    // number of last reduction of a state
+var defact = make([]int, NSTATES)  // default actions of states
+
+// lookahead set information
+
+var 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()
+
+	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 ';':
+
+		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 ';':
+					break
+
+				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.
+	fmt.Fprintf(ftable, "var %sStatenames = [...]string{", 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 {
+	var c rune
+
+	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
+}
+
+func dumpprod(curprod []int, max int) {
+	fmt.Printf("\n")
+	for i := 0; i < max; i++ {
+		p := curprod[i]
+		if p < 0 {
+			fmt.Printf("[%v] %v\n", i, p)
+		} else {
+			fmt.Printf("[%v] %v\n", i, symnam(p))
+		}
+	}
+}
+
+//
+// copy action to the next ; or closing }
+//
+func cpyact(curprod []int, max int) {
+
+	if !lflag {
+		fmt.Fprintf(fcode, "\n\t\t//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 '{':
+			if brac == 0 {
+			}
+			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('/')
+						c = getrune(finput)
+						break swt
+					}
+					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)
+	}
+}
+
+func dumppres() {
+	for i := 0; i <= nnonter; i++ {
+		fmt.Printf("nonterm %d\n", i)
+		curres := pres[i]
+		for j := 0; j < len(curres); j++ {
+			fmt.Printf("\tproduction %d:", j)
+			prd := curres[j]
+			for k := 0; k < len(prd); k++ {
+				fmt.Printf(" %d", prd[k])
+			}
+			fmt.Print("\n")
+		}
+	}
+}
+
+//
+// mark nonterminals which derive the empty string
+// also, look for nonterminals which don't derive any token strings
+//
+func cempty() {
+	var i, p, np int
+	var prd []int
+
+	pempty = make([]int, nnonter+1)
+
+	// first, use the array pempty to detect productions that can never be reduced
+	// set pempty to WHONOWS
+	aryfil(pempty, nnonter+1, WHOKNOWS)
+
+	// now, look at productions, marking nonterminals which derive something
+more:
+	for {
+		for i = 0; i < nprod; i++ {
+			prd = prdptr[i]
+			if pempty[prd[0]-NTBASE] != 0 {
+				continue
+			}
+			np = len(prd) - 1
+			for p = 1; p < np; p++ {
+				if prd[p] >= NTBASE && pempty[prd[p]-NTBASE] == WHOKNOWS {
+					break
+				}
+			}
+			// production can be derived
+			if p == np {
+				pempty[prd[0]-NTBASE] = OK
+				continue more
+			}
+		}
+		break
+	}
+
+	// now, look at the nonterminals, to see if they are all OK
+	for i = 0; i <= nnonter; i++ {
+		// the added production rises or falls as the start symbol ...
+		if i == 0 {
+			continue
+		}
+		if pempty[i] != OK {
+			fatfl = 0
+			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
+	}
+}
+
+func dumpempty() {
+	for i := 0; i <= nnonter; i++ {
+		if pempty[i] == EMPTY {
+			fmt.Printf("non-term %d %s matches empty\n", i, symnam(i+NTBASE))
+		}
+	}
+}
+
+//
+// compute an array with the first of nonterminals
+//
+func cpfir() {
+	var s, n, p, np, ch, i int
+	var curres [][]int
+	var prd []int
+
+	wsets = make([]Wset, nnonter+WSETINC)
+	pfirst = make([]Lkset, nnonter+1)
+	for i = 0; i <= nnonter; i++ {
+		wsets[i].ws = mkset()
+		pfirst[i] = mkset()
+		curres = pres[i]
+		n = len(curres)
+
+		// initially fill the sets
+		for s = 0; s < n; s++ {
+			prd = curres[s]
+			np = len(prd) - 1
+			for p = 0; p < np; p++ {
+				ch = prd[p]
+				if ch < NTBASE {
+					setbit(pfirst[i], ch)
+					break
+				}
+				if pempty[ch-NTBASE] == 0 {
+					break
+				}
+			}
+		}
+	}
+
+	// now, reflect transitivity
+	changes := 1
+	for changes != 0 {
+		changes = 0
+		for i = 0; i <= nnonter; i++ {
+			curres = pres[i]
+			n = len(curres)
+			for s = 0; s < n; s++ {
+				prd = curres[s]
+				np = len(prd) - 1
+				for p = 0; p < np; p++ {
+					ch = prd[p] - NTBASE
+					if ch < 0 {
+						break
+					}
+					changes |= setunion(pfirst[i], pfirst[ch])
+					if pempty[ch] == 0 {
+						break
+					}
+				}
+			}
+		}
+	}
+
+	if indebug == 0 {
+		return
+	}
+	if foutput != nil {
+		for i = 0; i <= nnonter; i++ {
+			fmt.Fprintf(foutput, "\n%v: %v %v\n",
+				nontrst[i].name, pfirst[i], pempty[i])
+		}
+	}
+}
+
+//
+// generate the states
+//
+func stagen() {
+	// initialize
+	nstate = 0
+	tstates = make([]int, ntokens+1)  // states generated by terminal gotos
+	ntstates = make([]int, nnonter+1) // states generated by nonterminal gotos
+	amem = make([]int, ACTSIZE)
+	memp = 0
+
+	clset = mkset()
+	pstate[0] = 0
+	pstate[1] = 0
+	aryfil(clset, tbitset, 0)
+	putitem(Pitem{prdptr[0], 0, 0, 0}, clset)
+	tystate[0] = MUSTDO
+	nstate = 1
+	pstate[2] = pstate[1]
+
+	//
+	// now, the main state generation loop
+	// first pass generates all of the states
+	// later passes fix up lookahead
+	// could be sped up a lot by remembering
+	// results of the first pass rather than recomputing
+	//
+	first := 1
+	for more := 1; more != 0; first = 0 {
+		more = 0
+		for i := 0; i < nstate; i++ {
+			if tystate[i] != MUSTDO {
+				continue
+			}
+
+			tystate[i] = DONE
+			aryfil(temp1, nnonter+1, 0)
+
+			// take state i, close it, and do gotos
+			closure(i)
+
+			// generate goto's
+			for p := 0; p < cwp; p++ {
+				pi := wsets[p]
+				if pi.flag != 0 {
+					continue
+				}
+				wsets[p].flag = 1
+				c := pi.pitem.first
+				if c <= 1 {
+					if pstate[i+1]-pstate[i] <= p {
+						tystate[i] = MUSTLOOKAHEAD
+					}
+					continue
+				}
+
+				// do a goto on c
+				putitem(wsets[p].pitem, wsets[p].ws)
+				for q := p + 1; q < cwp; q++ {
+					// this item contributes to the goto
+					if c == wsets[q].pitem.first {
+						putitem(wsets[q].pitem, wsets[q].ws)
+						wsets[q].flag = 1
+					}
+				}
+
+				if c < NTBASE {
+					state(c) // register new state
+				} else {
+					temp1[c-NTBASE] = state(c)
+				}
+			}
+
+			if gsdebug != 0 && foutput != nil {
+				fmt.Fprintf(foutput, "%v: ", i)
+				for j := 0; j <= nnonter; j++ {
+					if temp1[j] != 0 {
+						fmt.Fprintf(foutput, "%v %v,", nontrst[j].name, temp1[j])
+					}
+				}
+				fmt.Fprintf(foutput, "\n")
+			}
+
+			if first != 0 {
+				indgo[i] = apack(temp1[1:], 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 %sNprod = %v\n", prefix, nprod)
+	fmt.Fprintf(ftable, "const %sPrivate = %v\n", prefix, PRIVATE)
+	ftable.WriteRune('\n')
+	fmt.Fprintf(ftable, "var %sTokenNames []string\n", prefix)
+	fmt.Fprintf(ftable, "var %sStates []string\n", prefix)
+}
+
+//
+// decide a shift/reduce conflict by precedence.
+// r is a rule number, t a token number
+// the conflict is in state s
+// temp1[t] is changed to reflect the action
+//
+func precftn(r, t, s int) {
+	var action int
+
+	lp := levprd[r]
+	lt := toklev[t]
+	if PLEVEL(lt) == 0 || PLEVEL(lp) == 0 {
+		// conflict
+		if foutput != nil {
+			fmt.Fprintf(foutput,
+				"\n%v: shift/reduce conflict (shift %v(%v), red'n %v(%v)) on %v",
+				s, temp1[t], PLEVEL(lt), r, PLEVEL(lp), symnam(t))
+		}
+		zzsrconf++
+		return
+	}
+	if PLEVEL(lt) == PLEVEL(lp) {
+		action = ASSOC(lt)
+	} else if PLEVEL(lt) > PLEVEL(lp) {
+		action = RASC // shift
+	} else {
+		action = LASC
+	} // reduce
+	switch action {
+	case BASC: // error action
+		temp1[t] = ERRCODE
+	case LASC: // reduce
+		temp1[t] = -r
+	}
+}
+
+//
+// output state i
+// temp1 has the actions, lastred the default
+//
+func wract(i int) {
+	var p, p1 int
+
+	// find the best choice for lastred
+	lastred = 0
+	ntimes := 0
+	for j := 0; j <= ntokens; j++ {
+		if temp1[j] >= 0 {
+			continue
+		}
+		if temp1[j]+lastred == 0 {
+			continue
+		}
+		// count the number of appearances of temp1[j]
+		count := 0
+		tred := -temp1[j]
+		levprd[tred] |= REDFLAG
+		for p = 0; p <= ntokens; p++ {
+			if temp1[p]+tred == 0 {
+				count++
+			}
+		}
+		if count > ntimes {
+			lastred = tred
+			ntimes = count
+		}
+	}
+
+	//
+	// for error recovery, arrange that, if there is a shift on the
+	// error recovery token, `error', that the default be the error action
+	//
+	if temp1[2] > 0 {
+		lastred = 0
+	}
+
+	// clear out entries in temp1 which equal lastred
+	// count entries in optst table
+	n := 0
+	for p = 0; p <= ntokens; p++ {
+		p1 = temp1[p]
+		if p1+lastred == 0 {
+			temp1[p] = 0
+			p1 = 0
+		}
+		if p1 > 0 && p1 != ACCEPTCODE && p1 != ERRCODE {
+			n++
+		}
+	}
+
+	wrstate(i)
+	defact[i] = lastred
+	flag := 0
+	os := make([]int, n*2)
+	n = 0
+	for p = 0; p <= ntokens; p++ {
+		p1 = temp1[p]
+		if p1 != 0 {
+			if p1 < 0 {
+				p1 = -p1
+			} else if p1 == ACCEPTCODE {
+				p1 = -1
+			} else if p1 == ERRCODE {
+				p1 = 0
+			} else {
+				os[n] = p
+				n++
+				os[n] = p1
+				n++
+				zzacent++
+				continue
+			}
+			if flag == 0 {
+				fmt.Fprintf(ftable, "\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\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
+	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
+	fmt.Fprintf(ftable, "var %v = [...]int{\n", 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 write(f *bufio.Writer, b []byte, n int) int {
+	panic("write")
+}
+
+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 */
+}
+`