+++ /dev/null
-/*
-Derived from Inferno's utils/iyacc/yacc.c
-http://code.google.com/p/inferno-os/source/browse/utils/iyacc/yacc.c
-
-This copyright NOTICE applies to all files in this directory and
-subdirectories, unless another copyright notice appears in a given
-file or subdirectory. If you take substantial code from this software to use in
-other programs, you must somehow include with it an appropriate
-copyright notice that includes the copyright notice and the other
-notices below. It is fine (and often tidier) to do that in a separate
-file such as NOTICE, LICENCE or COPYING.
-
- Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
- Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
- Portions Copyright © 1997-1999 Vita Nuova Limited
- Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
- Portions Copyright © 2004,2006 Bruce Ellis
- Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
- Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
- Portions Copyright © 2009 The Go Authors. All rights reserved.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-*/
-
-package main
-
-// yacc
-// major difference is lack of stem ("y" variable)
-//
-
-import (
- "bufio"
- "bytes"
- "flag"
- "fmt"
- "go/format"
- "io/ioutil"
- "os"
- "strconv"
- "strings"
- "unicode"
-)
-
-// the following are adjustable
-// according to memory size
-const (
- ACTSIZE = 120000
- NSTATES = 8000
- TEMPSIZE = 8000
-
- SYMINC = 50 // increase for non-term or term
- RULEINC = 50 // increase for max rule length prodptr[i]
- PRODINC = 100 // increase for productions prodptr
- WSETINC = 50 // increase for working sets wsets
- STATEINC = 200 // increase for states statemem
-
- PRIVATE = 0xE000 // unicode private use
-
- // relationships which must hold:
- // TEMPSIZE >= NTERMS + NNONTERM + 1;
- // TEMPSIZE >= NSTATES;
- //
-
- NTBASE = 010000
- ERRCODE = 8190
- ACCEPTCODE = 8191
- YYLEXUNK = 3
- TOKSTART = 4 //index of first defined token
-)
-
-// no, left, right, binary assoc.
-const (
- NOASC = iota
- LASC
- RASC
- BASC
-)
-
-// flags for state generation
-const (
- DONE = iota
- MUSTDO
- MUSTLOOKAHEAD
-)
-
-// flags for a rule having an action, and being reduced
-const (
- ACTFLAG = 1 << (iota + 2)
- REDFLAG
-)
-
-// output parser flags
-const yyFlag = -1000
-
-// parse tokens
-const (
- IDENTIFIER = PRIVATE + iota
- MARK
- TERM
- LEFT
- RIGHT
- BINARY
- PREC
- LCURLY
- IDENTCOLON
- NUMBER
- START
- TYPEDEF
- TYPENAME
- UNION
- ERROR
-)
-
-const ENDFILE = 0
-const EMPTY = 1
-const WHOKNOWS = 0
-const OK = 1
-const NOMORE = -1000
-
-// macros for getting associativity and precedence levels
-func ASSOC(i int) int { return i & 3 }
-
-func PLEVEL(i int) int { return (i >> 4) & 077 }
-
-func TYPE(i int) int { return (i >> 10) & 077 }
-
-// macros for setting associativity and precedence levels
-func SETASC(i, j int) int { return i | j }
-
-func SETPLEV(i, j int) int { return i | (j << 4) }
-
-func SETTYPE(i, j int) int { return i | (j << 10) }
-
-// I/O descriptors
-var finput *bufio.Reader // input file
-var stderr *bufio.Writer
-var ftable *bufio.Writer // y.go file
-var fcode = &bytes.Buffer{} // saved code
-var foutput *bufio.Writer // y.output file
-
-var fmtImported bool // output file has recorded an import of "fmt"
-
-var oflag string // -o [y.go] - y.go file
-var vflag string // -v [y.output] - y.output file
-var lflag bool // -l - disable line directives
-var prefix string // name prefix for identifiers, default yy
-
-func init() {
- flag.StringVar(&oflag, "o", "y.go", "parser output")
- flag.StringVar(&prefix, "p", "yy", "name prefix to use in generated code")
- flag.StringVar(&vflag, "v", "y.output", "create parsing tables")
- flag.BoolVar(&lflag, "l", false, "disable line directives")
-}
-
-var initialstacksize = 16
-
-// communication variables between various I/O routines
-var infile string // input file name
-var numbval int // value of an input number
-var tokname string // input token name, slop for runes and 0
-var tokflag = false
-
-// structure declarations
-type Lkset []int
-
-type Pitem struct {
- prod []int
- off int // offset within the production
- first int // first term or non-term in item
- prodno int // production number for sorting
-}
-
-type Item struct {
- pitem Pitem
- look Lkset
-}
-
-type Symb struct {
- name string
- noconst bool
- value int
-}
-
-type Wset struct {
- pitem Pitem
- flag int
- ws Lkset
-}
-
-// storage of types
-var ntypes int // number of types defined
-var typeset = make(map[int]string) // pointers to type tags
-
-// token information
-
-var ntokens = 0 // number of tokens
-var tokset []Symb
-var toklev []int // vector with the precedence of the terminals
-
-// nonterminal information
-
-var nnonter = -1 // the number of nonterminals
-var nontrst []Symb
-var start int // start symbol
-
-// state information
-
-var nstate = 0 // number of states
-var pstate = make([]int, NSTATES+2) // index into statemem to the descriptions of the states
-var statemem []Item
-var tystate = make([]int, NSTATES) // contains type information about the states
-var tstates []int // states generated by terminal gotos
-var ntstates []int // states generated by nonterminal gotos
-var mstates = make([]int, NSTATES) // chain of overflows of term/nonterm generation lists
-var lastred int // number of last reduction of a state
-var defact = make([]int, NSTATES) // default actions of states
-
-// lookahead set information
-
-var nolook = 0 // flag to turn off lookahead computations
-var tbitset = 0 // size of lookahead sets
-var clset Lkset // temporary storage for lookahead computations
-
-// working set information
-
-var wsets []Wset
-var cwp int
-
-// storage for action table
-
-var amem []int // action table storage
-var memp int // next free action table position
-var indgo = make([]int, NSTATES) // index to the stored goto table
-
-// temporary vector, indexable by states, terms, or ntokens
-
-var temp1 = make([]int, TEMPSIZE) // temporary storage, indexed by terms + ntokens or states
-var lineno = 1 // current input line number
-var fatfl = 1 // if on, error is fatal
-var nerrors = 0 // number of errors
-
-// assigned token type values
-
-var extval = 0
-
-// grammar rule information
-
-var nprod = 1 // number of productions
-var prdptr [][]int // pointers to descriptions of productions
-var levprd []int // precedence levels for the productions
-var rlines []int // line number for this rule
-
-// statistics collection variables
-
-var zzgoent = 0
-var zzgobest = 0
-var zzacent = 0
-var zzexcp = 0
-var zzclose = 0
-var zzrrconf = 0
-var zzsrconf = 0
-var zzstate = 0
-
-// optimizer arrays
-
-var yypgo [][]int
-var optst [][]int
-var ggreed []int
-var pgo []int
-
-var maxspr int // maximum spread of any entry
-var maxoff int // maximum offset into a array
-var maxa int
-
-// storage for information about the nonterminals
-
-var pres [][][]int // vector of pointers to productions yielding each nonterminal
-var pfirst []Lkset
-var pempty []int // vector of nonterminals nontrivially deriving e
-
-// random stuff picked out from between functions
-
-var indebug = 0 // debugging flag for cpfir
-var pidebug = 0 // debugging flag for putitem
-var gsdebug = 0 // debugging flag for stagen
-var cldebug = 0 // debugging flag for closure
-var pkdebug = 0 // debugging flag for apack
-var g2debug = 0 // debugging for go2gen
-var adb = 0 // debugging for callopt
-
-type Resrv struct {
- name string
- value int
-}
-
-var resrv = []Resrv{
- {"binary", BINARY},
- {"left", LEFT},
- {"nonassoc", BINARY},
- {"prec", PREC},
- {"right", RIGHT},
- {"start", START},
- {"term", TERM},
- {"token", TERM},
- {"type", TYPEDEF},
- {"union", UNION},
- {"struct", UNION},
- {"error", ERROR},
-}
-
-type Error struct {
- lineno int
- tokens []string
- msg string
-}
-
-var errors []Error
-
-type Row struct {
- actions []int
- defaultAction int
-}
-
-var stateTable []Row
-
-var zznewstate = 0
-
-const EOF = -1
-
-func main() {
-
- setup() // initialize and read productions
-
- tbitset = (ntokens + 32) / 32
- cpres() // make table of which productions yield a given nonterminal
- cempty() // make a table of which nonterminals can match the empty string
- cpfir() // make a table of firsts of nonterminals
-
- stagen() // generate the states
-
- yypgo = make([][]int, nnonter+1)
- optst = make([][]int, nstate)
- output() // write the states and the tables
- go2out()
-
- hideprod()
- summary()
-
- callopt()
-
- others()
-
- exit(0)
-}
-
-func setup() {
- var j, ty int
-
- stderr = bufio.NewWriter(os.Stderr)
- foutput = nil
-
- flag.Parse()
- if flag.NArg() != 1 {
- usage()
- }
- if initialstacksize < 1 {
- // never set so cannot happen
- fmt.Fprintf(stderr, "yacc: stack size too small\n")
- usage()
- }
- yaccpar = strings.Replace(yaccpartext, "$$", prefix, -1)
- openup()
-
- fmt.Fprintf(ftable, "// Code generated by goyacc %s. DO NOT EDIT.\n", strings.Join(os.Args[1:], " "))
-
- defin(0, "$end")
- extval = PRIVATE // tokens start in unicode 'private use'
- defin(0, "error")
- defin(1, "$accept")
- defin(0, "$unk")
- i := 0
-
- t := gettok()
-
-outer:
- for {
- switch t {
- default:
- errorf("syntax error tok=%v", t-PRIVATE)
-
- case MARK, ENDFILE:
- break outer
-
- case ';':
- // Do nothing.
-
- case START:
- t = gettok()
- if t != IDENTIFIER {
- errorf("bad %%start construction")
- }
- start = chfind(1, tokname)
-
- case ERROR:
- lno := lineno
- var tokens []string
- for {
- t := gettok()
- if t == ':' {
- break
- }
- if t != IDENTIFIER && t != IDENTCOLON {
- errorf("bad syntax in %%error")
- }
- tokens = append(tokens, tokname)
- if t == IDENTCOLON {
- break
- }
- }
- if gettok() != IDENTIFIER {
- errorf("bad syntax in %%error")
- }
- errors = append(errors, Error{lno, tokens, tokname})
-
- case TYPEDEF:
- t = gettok()
- if t != TYPENAME {
- errorf("bad syntax in %%type")
- }
- ty = numbval
- for {
- t = gettok()
- switch t {
- case IDENTIFIER:
- t = chfind(1, tokname)
- if t < NTBASE {
- j = TYPE(toklev[t])
- if j != 0 && j != ty {
- errorf("type redeclaration of token %s",
- tokset[t].name)
- } else {
- toklev[t] = SETTYPE(toklev[t], ty)
- }
- } else {
- j = nontrst[t-NTBASE].value
- if j != 0 && j != ty {
- errorf("type redeclaration of nonterminal %v",
- nontrst[t-NTBASE].name)
- } else {
- nontrst[t-NTBASE].value = ty
- }
- }
- continue
-
- case ',':
- continue
- }
- break
- }
- continue
-
- case UNION:
- cpyunion()
-
- case LEFT, BINARY, RIGHT, TERM:
- // nonzero means new prec. and assoc.
- lev := t - TERM
- if lev != 0 {
- i++
- }
- ty = 0
-
- // get identifiers so defined
- t = gettok()
-
- // there is a type defined
- if t == TYPENAME {
- ty = numbval
- t = gettok()
- }
- for {
- switch t {
- case ',':
- t = gettok()
- continue
-
- case ';':
- // Do nothing.
-
- case IDENTIFIER:
- j = chfind(0, tokname)
- if j >= NTBASE {
- errorf("%v defined earlier as nonterminal", tokname)
- }
- if lev != 0 {
- if ASSOC(toklev[j]) != 0 {
- errorf("redeclaration of precedence of %v", tokname)
- }
- toklev[j] = SETASC(toklev[j], lev)
- toklev[j] = SETPLEV(toklev[j], i)
- }
- if ty != 0 {
- if TYPE(toklev[j]) != 0 {
- errorf("redeclaration of type of %v", tokname)
- }
- toklev[j] = SETTYPE(toklev[j], ty)
- }
- t = gettok()
- if t == NUMBER {
- tokset[j].value = numbval
- t = gettok()
- }
-
- continue
- }
- break
- }
- continue
-
- case LCURLY:
- cpycode()
- }
- t = gettok()
- }
-
- if t == ENDFILE {
- errorf("unexpected EOF before %%")
- }
-
- fmt.Fprintf(fcode, "switch %snt {\n", prefix)
-
- moreprod()
- prdptr[0] = []int{NTBASE, start, 1, 0}
-
- nprod = 1
- curprod := make([]int, RULEINC)
- t = gettok()
- if t != IDENTCOLON {
- errorf("bad syntax on first rule")
- }
-
- if start == 0 {
- prdptr[0][1] = chfind(1, tokname)
- }
-
- // read rules
- // put into prdptr array in the format
- // target
- // followed by id's of terminals and non-terminals
- // followed by -nprod
-
- for t != MARK && t != ENDFILE {
- mem := 0
-
- // process a rule
- rlines[nprod] = lineno
- ruleline := lineno
- if t == '|' {
- curprod[mem] = prdptr[nprod-1][0]
- mem++
- } else if t == IDENTCOLON {
- curprod[mem] = chfind(1, tokname)
- if curprod[mem] < NTBASE {
- lerrorf(ruleline, "token illegal on LHS of grammar rule")
- }
- mem++
- } else {
- lerrorf(ruleline, "illegal rule: missing semicolon or | ?")
- }
-
- // read rule body
- t = gettok()
- for {
- for t == IDENTIFIER {
- curprod[mem] = chfind(1, tokname)
- if curprod[mem] < NTBASE {
- levprd[nprod] = toklev[curprod[mem]]
- }
- mem++
- if mem >= len(curprod) {
- ncurprod := make([]int, mem+RULEINC)
- copy(ncurprod, curprod)
- curprod = ncurprod
- }
- t = gettok()
- }
- if t == PREC {
- if gettok() != IDENTIFIER {
- lerrorf(ruleline, "illegal %%prec syntax")
- }
- j = chfind(2, tokname)
- if j >= NTBASE {
- lerrorf(ruleline, "nonterminal "+nontrst[j-NTBASE].name+" illegal after %%prec")
- }
- levprd[nprod] = toklev[j]
- t = gettok()
- }
- if t != '=' {
- break
- }
- levprd[nprod] |= ACTFLAG
- fmt.Fprintf(fcode, "\n\tcase %v:", nprod)
- fmt.Fprintf(fcode, "\n\t\t%sDollar = %sS[%spt-%v:%spt+1]", prefix, prefix, prefix, mem-1, prefix)
- cpyact(curprod, mem)
-
- // action within rule...
- t = gettok()
- if t == IDENTIFIER {
- // make it a nonterminal
- j = chfind(1, fmt.Sprintf("$$%v", nprod))
-
- //
- // the current rule will become rule number nprod+1
- // enter null production for action
- //
- prdptr[nprod] = make([]int, 2)
- prdptr[nprod][0] = j
- prdptr[nprod][1] = -nprod
-
- // update the production information
- nprod++
- moreprod()
- levprd[nprod] = levprd[nprod-1] & ^ACTFLAG
- levprd[nprod-1] = ACTFLAG
- rlines[nprod] = lineno
-
- // make the action appear in the original rule
- curprod[mem] = j
- mem++
- if mem >= len(curprod) {
- ncurprod := make([]int, mem+RULEINC)
- copy(ncurprod, curprod)
- curprod = ncurprod
- }
- }
- }
-
- for t == ';' {
- t = gettok()
- }
- curprod[mem] = -nprod
- mem++
-
- // check that default action is reasonable
- if ntypes != 0 && (levprd[nprod]&ACTFLAG) == 0 &&
- nontrst[curprod[0]-NTBASE].value != 0 {
- // no explicit action, LHS has value
- tempty := curprod[1]
- if tempty < 0 {
- lerrorf(ruleline, "must return a value, since LHS has a type")
- }
- if tempty >= NTBASE {
- tempty = nontrst[tempty-NTBASE].value
- } else {
- tempty = TYPE(toklev[tempty])
- }
- if tempty != nontrst[curprod[0]-NTBASE].value {
- lerrorf(ruleline, "default action causes potential type clash")
- }
- }
- moreprod()
- prdptr[nprod] = make([]int, mem)
- copy(prdptr[nprod], curprod)
- nprod++
- moreprod()
- levprd[nprod] = 0
- }
-
- if TEMPSIZE < ntokens+nnonter+1 {
- errorf("too many tokens (%d) or non-terminals (%d)", ntokens, nnonter)
- }
-
- //
- // end of all rules
- // dump out the prefix code
- //
-
- fmt.Fprintf(fcode, "\n\t}")
-
- // put out non-literal terminals
- for i := TOKSTART; i <= ntokens; i++ {
- // non-literals
- if !tokset[i].noconst {
- fmt.Fprintf(ftable, "const %v = %v\n", tokset[i].name, tokset[i].value)
- }
- }
-
- // put out names of tokens
- ftable.WriteRune('\n')
- fmt.Fprintf(ftable, "var %sToknames = [...]string{\n", prefix)
- for i := 1; i <= ntokens; i++ {
- fmt.Fprintf(ftable, "\t%q,\n", tokset[i].name)
- }
- fmt.Fprintf(ftable, "}\n")
-
- // put out names of states.
- // commented out to avoid a huge table just for debugging.
- // re-enable to have the names in the binary.
- ftable.WriteRune('\n')
- fmt.Fprintf(ftable, "var %sStatenames = [...]string{\n", prefix)
- // for i:=TOKSTART; i<=ntokens; i++ {
- // fmt.Fprintf(ftable, "\t%q,\n", tokset[i].name);
- // }
- fmt.Fprintf(ftable, "}\n")
-
- ftable.WriteRune('\n')
- fmt.Fprintf(ftable, "const %sEofCode = 1\n", prefix)
- fmt.Fprintf(ftable, "const %sErrCode = 2\n", prefix)
- fmt.Fprintf(ftable, "const %sInitialStackSize = %v\n", prefix, initialstacksize)
-
- //
- // copy any postfix code
- //
- if t == MARK {
- if !lflag {
- fmt.Fprintf(ftable, "\n//line %v:%v\n", infile, lineno)
- }
- for {
- c := getrune(finput)
- if c == EOF {
- break
- }
- ftable.WriteRune(c)
- }
- }
-}
-
-//
-// allocate enough room to hold another production
-//
-func moreprod() {
- n := len(prdptr)
- if nprod >= n {
- nn := n + PRODINC
- aprod := make([][]int, nn)
- alevprd := make([]int, nn)
- arlines := make([]int, nn)
-
- copy(aprod, prdptr)
- copy(alevprd, levprd)
- copy(arlines, rlines)
-
- prdptr = aprod
- levprd = alevprd
- rlines = arlines
- }
-}
-
-//
-// define s to be a terminal if nt==0
-// or a nonterminal if nt==1
-//
-func defin(nt int, s string) int {
- val := 0
- if nt != 0 {
- nnonter++
- if nnonter >= len(nontrst) {
- anontrst := make([]Symb, nnonter+SYMINC)
- copy(anontrst, nontrst)
- nontrst = anontrst
- }
- nontrst[nnonter] = Symb{name: s}
- return NTBASE + nnonter
- }
-
- // must be a token
- ntokens++
- if ntokens >= len(tokset) {
- nn := ntokens + SYMINC
- atokset := make([]Symb, nn)
- atoklev := make([]int, nn)
-
- copy(atoklev, toklev)
- copy(atokset, tokset)
-
- tokset = atokset
- toklev = atoklev
- }
- tokset[ntokens].name = s
- toklev[ntokens] = 0
-
- // establish value for token
- // single character literal
- if s[0] == '\'' || s[0] == '"' {
- q, err := strconv.Unquote(s)
- if err != nil {
- errorf("invalid token: %s", err)
- }
- rq := []rune(q)
- if len(rq) != 1 {
- errorf("character token too long: %s", s)
- }
- val = int(rq[0])
- if val == 0 {
- errorf("token value 0 is illegal")
- }
- tokset[ntokens].noconst = true
- } else {
- val = extval
- extval++
- if s[0] == '$' {
- tokset[ntokens].noconst = true
- }
- }
-
- tokset[ntokens].value = val
- return ntokens
-}
-
-var peekline = 0
-
-func gettok() int {
- var i int
- var match, c rune
-
- tokname = ""
- for {
- lineno += peekline
- peekline = 0
- c = getrune(finput)
- for c == ' ' || c == '\n' || c == '\t' || c == '\v' || c == '\r' {
- if c == '\n' {
- lineno++
- }
- c = getrune(finput)
- }
-
- // skip comment -- fix
- if c != '/' {
- break
- }
- lineno += skipcom()
- }
-
- switch c {
- case EOF:
- if tokflag {
- fmt.Printf(">>> ENDFILE %v\n", lineno)
- }
- return ENDFILE
-
- case '{':
- ungetrune(finput, c)
- if tokflag {
- fmt.Printf(">>> ={ %v\n", lineno)
- }
- return '='
-
- case '<':
- // get, and look up, a type name (union member name)
- c = getrune(finput)
- for c != '>' && c != EOF && c != '\n' {
- tokname += string(c)
- c = getrune(finput)
- }
-
- if c != '>' {
- errorf("unterminated < ... > clause")
- }
-
- for i = 1; i <= ntypes; i++ {
- if typeset[i] == tokname {
- numbval = i
- if tokflag {
- fmt.Printf(">>> TYPENAME old <%v> %v\n", tokname, lineno)
- }
- return TYPENAME
- }
- }
- ntypes++
- numbval = ntypes
- typeset[numbval] = tokname
- if tokflag {
- fmt.Printf(">>> TYPENAME new <%v> %v\n", tokname, lineno)
- }
- return TYPENAME
-
- case '"', '\'':
- match = c
- tokname = string(c)
- for {
- c = getrune(finput)
- if c == '\n' || c == EOF {
- errorf("illegal or missing ' or \"")
- }
- if c == '\\' {
- tokname += string('\\')
- c = getrune(finput)
- } else if c == match {
- if tokflag {
- fmt.Printf(">>> IDENTIFIER \"%v\" %v\n", tokname, lineno)
- }
- tokname += string(c)
- return IDENTIFIER
- }
- tokname += string(c)
- }
-
- case '%':
- c = getrune(finput)
- switch c {
- case '%':
- if tokflag {
- fmt.Printf(">>> MARK %%%% %v\n", lineno)
- }
- return MARK
- case '=':
- if tokflag {
- fmt.Printf(">>> PREC %%= %v\n", lineno)
- }
- return PREC
- case '{':
- if tokflag {
- fmt.Printf(">>> LCURLY %%{ %v\n", lineno)
- }
- return LCURLY
- }
-
- getword(c)
- // find a reserved word
- for i := range resrv {
- if tokname == resrv[i].name {
- if tokflag {
- fmt.Printf(">>> %%%v %v %v\n", tokname,
- resrv[i].value-PRIVATE, lineno)
- }
- return resrv[i].value
- }
- }
- errorf("invalid escape, or illegal reserved word: %v", tokname)
-
- case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
- numbval = int(c - '0')
- for {
- c = getrune(finput)
- if !isdigit(c) {
- break
- }
- numbval = numbval*10 + int(c-'0')
- }
- ungetrune(finput, c)
- if tokflag {
- fmt.Printf(">>> NUMBER %v %v\n", numbval, lineno)
- }
- return NUMBER
-
- default:
- if isword(c) || c == '.' || c == '$' {
- getword(c)
- break
- }
- if tokflag {
- fmt.Printf(">>> OPERATOR %v %v\n", string(c), lineno)
- }
- return int(c)
- }
-
- // look ahead to distinguish IDENTIFIER from IDENTCOLON
- c = getrune(finput)
- for c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\r' || c == '/' {
- if c == '\n' {
- peekline++
- }
- // look for comments
- if c == '/' {
- peekline += skipcom()
- }
- c = getrune(finput)
- }
- if c == ':' {
- if tokflag {
- fmt.Printf(">>> IDENTCOLON %v: %v\n", tokname, lineno)
- }
- return IDENTCOLON
- }
-
- ungetrune(finput, c)
- if tokflag {
- fmt.Printf(">>> IDENTIFIER %v %v\n", tokname, lineno)
- }
- return IDENTIFIER
-}
-
-func getword(c rune) {
- tokname = ""
- for isword(c) || isdigit(c) || c == '.' || c == '$' {
- tokname += string(c)
- c = getrune(finput)
- }
- ungetrune(finput, c)
-}
-
-//
-// determine the type of a symbol
-//
-func fdtype(t int) int {
- var v int
- var s string
-
- if t >= NTBASE {
- v = nontrst[t-NTBASE].value
- s = nontrst[t-NTBASE].name
- } else {
- v = TYPE(toklev[t])
- s = tokset[t].name
- }
- if v <= 0 {
- errorf("must specify type for %v", s)
- }
- return v
-}
-
-func chfind(t int, s string) int {
- if s[0] == '"' || s[0] == '\'' {
- t = 0
- }
- for i := 0; i <= ntokens; i++ {
- if s == tokset[i].name {
- return i
- }
- }
- for i := 0; i <= nnonter; i++ {
- if s == nontrst[i].name {
- return NTBASE + i
- }
- }
-
- // cannot find name
- if t > 1 {
- errorf("%v should have been defined earlier", s)
- }
- return defin(t, s)
-}
-
-//
-// copy the union declaration to the output, and the define file if present
-//
-func cpyunion() {
-
- if !lflag {
- fmt.Fprintf(ftable, "\n//line %v:%v\n", infile, lineno)
- }
- fmt.Fprintf(ftable, "type %sSymType struct", prefix)
-
- level := 0
-
-out:
- for {
- c := getrune(finput)
- if c == EOF {
- errorf("EOF encountered while processing %%union")
- }
- ftable.WriteRune(c)
- switch c {
- case '\n':
- lineno++
- case '{':
- if level == 0 {
- fmt.Fprintf(ftable, "\n\tyys int")
- }
- level++
- case '}':
- level--
- if level == 0 {
- break out
- }
- }
- }
- fmt.Fprintf(ftable, "\n\n")
-}
-
-//
-// saves code between %{ and %}
-// adds an import for __fmt__ the first time
-//
-func cpycode() {
- lno := lineno
-
- c := getrune(finput)
- if c == '\n' {
- c = getrune(finput)
- lineno++
- }
- if !lflag {
- fmt.Fprintf(ftable, "\n//line %v:%v\n", infile, lineno)
- }
- // accumulate until %}
- code := make([]rune, 0, 1024)
- for c != EOF {
- if c == '%' {
- c = getrune(finput)
- if c == '}' {
- emitcode(code, lno+1)
- return
- }
- code = append(code, '%')
- }
- code = append(code, c)
- if c == '\n' {
- lineno++
- }
- c = getrune(finput)
- }
- lineno = lno
- errorf("eof before %%}")
-}
-
-//
-// emits code saved up from between %{ and %}
-// called by cpycode
-// adds an import for __yyfmt__ after the package clause
-//
-func emitcode(code []rune, lineno int) {
- for i, line := range lines(code) {
- writecode(line)
- if !fmtImported && isPackageClause(line) {
- fmt.Fprintln(ftable, `import __yyfmt__ "fmt"`)
- if !lflag {
- fmt.Fprintf(ftable, "//line %v:%v\n\t\t", infile, lineno+i)
- }
- fmtImported = true
- }
- }
-}
-
-//
-// does this line look like a package clause? not perfect: might be confused by early comments.
-//
-func isPackageClause(line []rune) bool {
- line = skipspace(line)
-
- // must be big enough.
- if len(line) < len("package X\n") {
- return false
- }
-
- // must start with "package"
- for i, r := range []rune("package") {
- if line[i] != r {
- return false
- }
- }
- line = skipspace(line[len("package"):])
-
- // must have another identifier.
- if len(line) == 0 || (!unicode.IsLetter(line[0]) && line[0] != '_') {
- return false
- }
- for len(line) > 0 {
- if !unicode.IsLetter(line[0]) && !unicode.IsDigit(line[0]) && line[0] != '_' {
- break
- }
- line = line[1:]
- }
- line = skipspace(line)
-
- // eol, newline, or comment must follow
- if len(line) == 0 {
- return true
- }
- if line[0] == '\r' || line[0] == '\n' {
- return true
- }
- if len(line) >= 2 {
- return line[0] == '/' && (line[1] == '/' || line[1] == '*')
- }
- return false
-}
-
-//
-// skip initial spaces
-//
-func skipspace(line []rune) []rune {
- for len(line) > 0 {
- if line[0] != ' ' && line[0] != '\t' {
- break
- }
- line = line[1:]
- }
- return line
-}
-
-//
-// break code into lines
-//
-func lines(code []rune) [][]rune {
- l := make([][]rune, 0, 100)
- for len(code) > 0 {
- // one line per loop
- var i int
- for i = range code {
- if code[i] == '\n' {
- break
- }
- }
- l = append(l, code[:i+1])
- code = code[i+1:]
- }
- return l
-}
-
-//
-// writes code to ftable
-//
-func writecode(code []rune) {
- for _, r := range code {
- ftable.WriteRune(r)
- }
-}
-
-//
-// skip over comments
-// skipcom is called after reading a '/'
-//
-func skipcom() int {
- c := getrune(finput)
- if c == '/' {
- for c != EOF {
- if c == '\n' {
- return 1
- }
- c = getrune(finput)
- }
- errorf("EOF inside comment")
- return 0
- }
- if c != '*' {
- errorf("illegal comment")
- }
-
- nl := 0 // lines skipped
- c = getrune(finput)
-
-l1:
- switch c {
- case '*':
- c = getrune(finput)
- if c == '/' {
- break
- }
- goto l1
-
- case '\n':
- nl++
- fallthrough
-
- default:
- c = getrune(finput)
- goto l1
- }
- return nl
-}
-
-//
-// copy action to the next ; or closing }
-//
-func cpyact(curprod []int, max int) {
-
- if !lflag {
- fmt.Fprintf(fcode, "\n//line %v:%v", infile, lineno)
- }
- fmt.Fprint(fcode, "\n\t\t")
-
- lno := lineno
- brac := 0
-
-loop:
- for {
- c := getrune(finput)
-
- swt:
- switch c {
- case ';':
- if brac == 0 {
- fcode.WriteRune(c)
- return
- }
-
- case '{':
- brac++
-
- case '$':
- s := 1
- tok := -1
- c = getrune(finput)
-
- // type description
- if c == '<' {
- ungetrune(finput, c)
- if gettok() != TYPENAME {
- errorf("bad syntax on $<ident> clause")
- }
- tok = numbval
- c = getrune(finput)
- }
- if c == '$' {
- fmt.Fprintf(fcode, "%sVAL", prefix)
-
- // put out the proper tag...
- if ntypes != 0 {
- if tok < 0 {
- tok = fdtype(curprod[0])
- }
- fmt.Fprintf(fcode, ".%v", typeset[tok])
- }
- continue loop
- }
- if c == '-' {
- s = -s
- c = getrune(finput)
- }
- j := 0
- if isdigit(c) {
- for isdigit(c) {
- j = j*10 + int(c-'0')
- c = getrune(finput)
- }
- ungetrune(finput, c)
- j = j * s
- if j >= max {
- errorf("Illegal use of $%v", j)
- }
- } else if isword(c) || c == '.' {
- // look for $name
- ungetrune(finput, c)
- if gettok() != IDENTIFIER {
- errorf("$ must be followed by an identifier")
- }
- tokn := chfind(2, tokname)
- fnd := -1
- c = getrune(finput)
- if c != '@' {
- ungetrune(finput, c)
- } else if gettok() != NUMBER {
- errorf("@ must be followed by number")
- } else {
- fnd = numbval
- }
- for j = 1; j < max; j++ {
- if tokn == curprod[j] {
- fnd--
- if fnd <= 0 {
- break
- }
- }
- }
- if j >= max {
- errorf("$name or $name@number not found")
- }
- } else {
- fcode.WriteRune('$')
- if s < 0 {
- fcode.WriteRune('-')
- }
- ungetrune(finput, c)
- continue loop
- }
- fmt.Fprintf(fcode, "%sDollar[%v]", prefix, j)
-
- // put out the proper tag
- if ntypes != 0 {
- if j <= 0 && tok < 0 {
- errorf("must specify type of $%v", j)
- }
- if tok < 0 {
- tok = fdtype(curprod[j])
- }
- fmt.Fprintf(fcode, ".%v", typeset[tok])
- }
- continue loop
-
- case '}':
- brac--
- if brac != 0 {
- break
- }
- fcode.WriteRune(c)
- return
-
- case '/':
- nc := getrune(finput)
- if nc != '/' && nc != '*' {
- ungetrune(finput, nc)
- break
- }
- // a comment
- fcode.WriteRune(c)
- fcode.WriteRune(nc)
- c = getrune(finput)
- for c != EOF {
- switch {
- case c == '\n':
- lineno++
- if nc == '/' { // end of // comment
- break swt
- }
- case c == '*' && nc == '*': // end of /* comment?
- nnc := getrune(finput)
- if nnc == '/' {
- fcode.WriteRune('*')
- fcode.WriteRune('/')
- continue loop
- }
- ungetrune(finput, nnc)
- }
- fcode.WriteRune(c)
- c = getrune(finput)
- }
- errorf("EOF inside comment")
-
- case '\'', '"':
- // character string or constant
- match := c
- fcode.WriteRune(c)
- c = getrune(finput)
- for c != EOF {
- if c == '\\' {
- fcode.WriteRune(c)
- c = getrune(finput)
- if c == '\n' {
- lineno++
- }
- } else if c == match {
- break swt
- }
- if c == '\n' {
- errorf("newline in string or char const")
- }
- fcode.WriteRune(c)
- c = getrune(finput)
- }
- errorf("EOF in string or character constant")
-
- case EOF:
- lineno = lno
- errorf("action does not terminate")
-
- case '\n':
- fmt.Fprint(fcode, "\n\t")
- lineno++
- continue loop
- }
-
- fcode.WriteRune(c)
- }
-}
-
-func openup() {
- infile = flag.Arg(0)
- finput = open(infile)
- if finput == nil {
- errorf("cannot open %v", infile)
- }
-
- foutput = nil
- if vflag != "" {
- foutput = create(vflag)
- if foutput == nil {
- errorf("can't create file %v", vflag)
- }
- }
-
- ftable = nil
- if oflag == "" {
- oflag = "y.go"
- }
- ftable = create(oflag)
- if ftable == nil {
- errorf("can't create file %v", oflag)
- }
-
-}
-
-//
-// return a pointer to the name of symbol i
-//
-func symnam(i int) string {
- var s string
-
- if i >= NTBASE {
- s = nontrst[i-NTBASE].name
- } else {
- s = tokset[i].name
- }
- return s
-}
-
-//
-// set elements 0 through n-1 to c
-//
-func aryfil(v []int, n, c int) {
- for i := 0; i < n; i++ {
- v[i] = c
- }
-}
-
-//
-// compute an array with the beginnings of productions yielding given nonterminals
-// The array pres points to these lists
-// the array pyield has the lists: the total size is only NPROD+1
-//
-func cpres() {
- pres = make([][][]int, nnonter+1)
- curres := make([][]int, nprod)
-
- if false {
- for j := 0; j <= nnonter; j++ {
- fmt.Printf("nnonter[%v] = %v\n", j, nontrst[j].name)
- }
- for j := 0; j < nprod; j++ {
- fmt.Printf("prdptr[%v][0] = %v+NTBASE\n", j, prdptr[j][0]-NTBASE)
- }
- }
-
- fatfl = 0 // make undefined symbols nonfatal
- for i := 0; i <= nnonter; i++ {
- n := 0
- c := i + NTBASE
- for j := 0; j < nprod; j++ {
- if prdptr[j][0] == c {
- curres[n] = prdptr[j][1:]
- n++
- }
- }
- if n == 0 {
- errorf("nonterminal %v not defined", nontrst[i].name)
- continue
- }
- pres[i] = make([][]int, n)
- copy(pres[i], curres)
- }
- fatfl = 1
- if nerrors != 0 {
- summary()
- exit(1)
- }
-}
-
-//
-// mark nonterminals which derive the empty string
-// also, look for nonterminals which don't derive any token strings
-//
-func cempty() {
- var i, p, np int
- var prd []int
-
- pempty = make([]int, nnonter+1)
-
- // first, use the array pempty to detect productions that can never be reduced
- // set pempty to WHONOWS
- aryfil(pempty, nnonter+1, WHOKNOWS)
-
- // now, look at productions, marking nonterminals which derive something
-more:
- for {
- for i = 0; i < nprod; i++ {
- prd = prdptr[i]
- if pempty[prd[0]-NTBASE] != 0 {
- continue
- }
- np = len(prd) - 1
- for p = 1; p < np; p++ {
- if prd[p] >= NTBASE && pempty[prd[p]-NTBASE] == WHOKNOWS {
- break
- }
- }
- // production can be derived
- if p == np {
- pempty[prd[0]-NTBASE] = OK
- continue more
- }
- }
- break
- }
-
- // now, look at the nonterminals, to see if they are all OK
- for i = 0; i <= nnonter; i++ {
- // the added production rises or falls as the start symbol ...
- if i == 0 {
- continue
- }
- if pempty[i] != OK {
- fatfl = 0
- errorf("nonterminal " + nontrst[i].name + " never derives any token string")
- }
- }
-
- if nerrors != 0 {
- summary()
- exit(1)
- }
-
- // now, compute the pempty array, to see which nonterminals derive the empty string
- // set pempty to WHOKNOWS
- aryfil(pempty, nnonter+1, WHOKNOWS)
-
- // loop as long as we keep finding empty nonterminals
-
-again:
- for {
- next:
- for i = 1; i < nprod; i++ {
- // not known to be empty
- prd = prdptr[i]
- if pempty[prd[0]-NTBASE] != WHOKNOWS {
- continue
- }
- np = len(prd) - 1
- for p = 1; p < np; p++ {
- if prd[p] < NTBASE || pempty[prd[p]-NTBASE] != EMPTY {
- continue next
- }
- }
-
- // we have a nontrivially empty nonterminal
- pempty[prd[0]-NTBASE] = EMPTY
-
- // got one ... try for another
- continue again
- }
- return
- }
-}
-
-//
-// compute an array with the first of nonterminals
-//
-func cpfir() {
- var s, n, p, np, ch, i int
- var curres [][]int
- var prd []int
-
- wsets = make([]Wset, nnonter+WSETINC)
- pfirst = make([]Lkset, nnonter+1)
- for i = 0; i <= nnonter; i++ {
- wsets[i].ws = mkset()
- pfirst[i] = mkset()
- curres = pres[i]
- n = len(curres)
-
- // initially fill the sets
- for s = 0; s < n; s++ {
- prd = curres[s]
- np = len(prd) - 1
- for p = 0; p < np; p++ {
- ch = prd[p]
- if ch < NTBASE {
- setbit(pfirst[i], ch)
- break
- }
- if pempty[ch-NTBASE] == 0 {
- break
- }
- }
- }
- }
-
- // now, reflect transitivity
- changes := 1
- for changes != 0 {
- changes = 0
- for i = 0; i <= nnonter; i++ {
- curres = pres[i]
- n = len(curres)
- for s = 0; s < n; s++ {
- prd = curres[s]
- np = len(prd) - 1
- for p = 0; p < np; p++ {
- ch = prd[p] - NTBASE
- if ch < 0 {
- break
- }
- changes |= setunion(pfirst[i], pfirst[ch])
- if pempty[ch] == 0 {
- break
- }
- }
- }
- }
- }
-
- if indebug == 0 {
- return
- }
- if foutput != nil {
- for i = 0; i <= nnonter; i++ {
- fmt.Fprintf(foutput, "\n%v: %v %v\n",
- nontrst[i].name, pfirst[i], pempty[i])
- }
- }
-}
-
-//
-// generate the states
-//
-func stagen() {
- // initialize
- nstate = 0
- tstates = make([]int, ntokens+1) // states generated by terminal gotos
- ntstates = make([]int, nnonter+1) // states generated by nonterminal gotos
- amem = make([]int, ACTSIZE)
- memp = 0
-
- clset = mkset()
- pstate[0] = 0
- pstate[1] = 0
- aryfil(clset, tbitset, 0)
- putitem(Pitem{prdptr[0], 0, 0, 0}, clset)
- tystate[0] = MUSTDO
- nstate = 1
- pstate[2] = pstate[1]
-
- //
- // now, the main state generation loop
- // first pass generates all of the states
- // later passes fix up lookahead
- // could be sped up a lot by remembering
- // results of the first pass rather than recomputing
- //
- first := 1
- for more := 1; more != 0; first = 0 {
- more = 0
- for i := 0; i < nstate; i++ {
- if tystate[i] != MUSTDO {
- continue
- }
-
- tystate[i] = DONE
- aryfil(temp1, nnonter+1, 0)
-
- // take state i, close it, and do gotos
- closure(i)
-
- // generate goto's
- for p := 0; p < cwp; p++ {
- pi := wsets[p]
- if pi.flag != 0 {
- continue
- }
- wsets[p].flag = 1
- c := pi.pitem.first
- if c <= 1 {
- if pstate[i+1]-pstate[i] <= p {
- tystate[i] = MUSTLOOKAHEAD
- }
- continue
- }
-
- // do a goto on c
- putitem(wsets[p].pitem, wsets[p].ws)
- for q := p + 1; q < cwp; q++ {
- // this item contributes to the goto
- if c == wsets[q].pitem.first {
- putitem(wsets[q].pitem, wsets[q].ws)
- wsets[q].flag = 1
- }
- }
-
- if c < NTBASE {
- state(c) // register new state
- } else {
- temp1[c-NTBASE] = state(c)
- }
- }
-
- if gsdebug != 0 && foutput != nil {
- fmt.Fprintf(foutput, "%v: ", i)
- for j := 0; j <= nnonter; j++ {
- if temp1[j] != 0 {
- fmt.Fprintf(foutput, "%v %v,", nontrst[j].name, temp1[j])
- }
- }
- fmt.Fprintf(foutput, "\n")
- }
-
- if first != 0 {
- indgo[i] = apack(temp1[1:], nnonter-1) - 1
- }
-
- more++
- }
- }
-}
-
-//
-// generate the closure of state i
-//
-func closure(i int) {
- zzclose++
-
- // first, copy kernel of state i to wsets
- cwp = 0
- q := pstate[i+1]
- for p := pstate[i]; p < q; p++ {
- wsets[cwp].pitem = statemem[p].pitem
- wsets[cwp].flag = 1 // this item must get closed
- copy(wsets[cwp].ws, statemem[p].look)
- cwp++
- }
-
- // now, go through the loop, closing each item
- work := 1
- for work != 0 {
- work = 0
- for u := 0; u < cwp; u++ {
- if wsets[u].flag == 0 {
- continue
- }
-
- // dot is before c
- c := wsets[u].pitem.first
- if c < NTBASE {
- wsets[u].flag = 0
- // only interesting case is where . is before nonterminal
- continue
- }
-
- // compute the lookahead
- aryfil(clset, tbitset, 0)
-
- // find items involving c
- for v := u; v < cwp; v++ {
- if wsets[v].flag != 1 || wsets[v].pitem.first != c {
- continue
- }
- pi := wsets[v].pitem.prod
- ipi := wsets[v].pitem.off + 1
-
- wsets[v].flag = 0
- if nolook != 0 {
- continue
- }
-
- ch := pi[ipi]
- ipi++
- for ch > 0 {
- // terminal symbol
- if ch < NTBASE {
- setbit(clset, ch)
- break
- }
-
- // nonterminal symbol
- setunion(clset, pfirst[ch-NTBASE])
- if pempty[ch-NTBASE] == 0 {
- break
- }
- ch = pi[ipi]
- ipi++
- }
- if ch <= 0 {
- setunion(clset, wsets[v].ws)
- }
- }
-
- //
- // now loop over productions derived from c
- //
- curres := pres[c-NTBASE]
- n := len(curres)
-
- nexts:
- // initially fill the sets
- for s := 0; s < n; s++ {
- prd := curres[s]
-
- //
- // put these items into the closure
- // is the item there
- //
- for v := 0; v < cwp; v++ {
- // yes, it is there
- if wsets[v].pitem.off == 0 &&
- aryeq(wsets[v].pitem.prod, prd) != 0 {
- if nolook == 0 &&
- setunion(wsets[v].ws, clset) != 0 {
- wsets[v].flag = 1
- work = 1
- }
- continue nexts
- }
- }
-
- // not there; make a new entry
- if cwp >= len(wsets) {
- awsets := make([]Wset, cwp+WSETINC)
- copy(awsets, wsets)
- wsets = awsets
- }
- wsets[cwp].pitem = Pitem{prd, 0, prd[0], -prd[len(prd)-1]}
- wsets[cwp].flag = 1
- wsets[cwp].ws = mkset()
- if nolook == 0 {
- work = 1
- copy(wsets[cwp].ws, clset)
- }
- cwp++
- }
- }
- }
-
- // have computed closure; flags are reset; return
- if cldebug != 0 && foutput != nil {
- fmt.Fprintf(foutput, "\nState %v, nolook = %v\n", i, nolook)
- for u := 0; u < cwp; u++ {
- if wsets[u].flag != 0 {
- fmt.Fprintf(foutput, "flag set\n")
- }
- wsets[u].flag = 0
- fmt.Fprintf(foutput, "\t%v", writem(wsets[u].pitem))
- prlook(wsets[u].ws)
- fmt.Fprintf(foutput, "\n")
- }
- }
-}
-
-//
-// sorts last state,and sees if it equals earlier ones. returns state number
-//
-func state(c int) int {
- zzstate++
- p1 := pstate[nstate]
- p2 := pstate[nstate+1]
- if p1 == p2 {
- return 0 // null state
- }
-
- // sort the items
- var k, l int
- for k = p1 + 1; k < p2; k++ { // make k the biggest
- for l = k; l > p1; l-- {
- if statemem[l].pitem.prodno < statemem[l-1].pitem.prodno ||
- statemem[l].pitem.prodno == statemem[l-1].pitem.prodno &&
- statemem[l].pitem.off < statemem[l-1].pitem.off {
- s := statemem[l]
- statemem[l] = statemem[l-1]
- statemem[l-1] = s
- } else {
- break
- }
- }
- }
-
- size1 := p2 - p1 // size of state
-
- var i int
- if c >= NTBASE {
- i = ntstates[c-NTBASE]
- } else {
- i = tstates[c]
- }
-
-look:
- for ; i != 0; i = mstates[i] {
- // get ith state
- q1 := pstate[i]
- q2 := pstate[i+1]
- size2 := q2 - q1
- if size1 != size2 {
- continue
- }
- k = p1
- for l = q1; l < q2; l++ {
- if aryeq(statemem[l].pitem.prod, statemem[k].pitem.prod) == 0 ||
- statemem[l].pitem.off != statemem[k].pitem.off {
- continue look
- }
- k++
- }
-
- // found it
- pstate[nstate+1] = pstate[nstate] // delete last state
-
- // fix up lookaheads
- if nolook != 0 {
- return i
- }
- k = p1
- for l = q1; l < q2; l++ {
- if setunion(statemem[l].look, statemem[k].look) != 0 {
- tystate[i] = MUSTDO
- }
- k++
- }
- return i
- }
-
- // state is new
- zznewstate++
- if nolook != 0 {
- errorf("yacc state/nolook error")
- }
- pstate[nstate+2] = p2
- if nstate+1 >= NSTATES {
- errorf("too many states")
- }
- if c >= NTBASE {
- mstates[nstate] = ntstates[c-NTBASE]
- ntstates[c-NTBASE] = nstate
- } else {
- mstates[nstate] = tstates[c]
- tstates[c] = nstate
- }
- tystate[nstate] = MUSTDO
- nstate++
- return nstate - 1
-}
-
-func putitem(p Pitem, set Lkset) {
- p.off++
- p.first = p.prod[p.off]
-
- if pidebug != 0 && foutput != nil {
- fmt.Fprintf(foutput, "putitem(%v), state %v\n", writem(p), nstate)
- }
- j := pstate[nstate+1]
- if j >= len(statemem) {
- asm := make([]Item, j+STATEINC)
- copy(asm, statemem)
- statemem = asm
- }
- statemem[j].pitem = p
- if nolook == 0 {
- s := mkset()
- copy(s, set)
- statemem[j].look = s
- }
- j++
- pstate[nstate+1] = j
-}
-
-//
-// creates output string for item pointed to by pp
-//
-func writem(pp Pitem) string {
- var i int
-
- p := pp.prod
- q := chcopy(nontrst[prdptr[pp.prodno][0]-NTBASE].name) + ": "
- npi := pp.off
-
- pi := aryeq(p, prdptr[pp.prodno])
-
- for {
- c := ' '
- if pi == npi {
- c = '.'
- }
- q += string(c)
-
- i = p[pi]
- pi++
- if i <= 0 {
- break
- }
- q += chcopy(symnam(i))
- }
-
- // an item calling for a reduction
- i = p[npi]
- if i < 0 {
- q += fmt.Sprintf(" (%v)", -i)
- }
-
- return q
-}
-
-//
-// pack state i from temp1 into amem
-//
-func apack(p []int, n int) int {
- //
- // we don't need to worry about checking because
- // we will only look at entries known to be there...
- // eliminate leading and trailing 0's
- //
- off := 0
- pp := 0
- for ; pp <= n && p[pp] == 0; pp++ {
- off--
- }
-
- // no actions
- if pp > n {
- return 0
- }
- for ; n > pp && p[n] == 0; n-- {
- }
- p = p[pp : n+1]
-
- // now, find a place for the elements from p to q, inclusive
- r := len(amem) - len(p)
-
-nextk:
- for rr := 0; rr <= r; rr++ {
- qq := rr
- for pp = 0; pp < len(p); pp++ {
- if p[pp] != 0 {
- if p[pp] != amem[qq] && amem[qq] != 0 {
- continue nextk
- }
- }
- qq++
- }
-
- // we have found an acceptable k
- if pkdebug != 0 && foutput != nil {
- fmt.Fprintf(foutput, "off = %v, k = %v\n", off+rr, rr)
- }
- qq = rr
- for pp = 0; pp < len(p); pp++ {
- if p[pp] != 0 {
- if qq > memp {
- memp = qq
- }
- amem[qq] = p[pp]
- }
- qq++
- }
- if pkdebug != 0 && foutput != nil {
- for pp = 0; pp <= memp; pp += 10 {
- fmt.Fprintf(foutput, "\n")
- for qq = pp; qq <= pp+9; qq++ {
- fmt.Fprintf(foutput, "%v ", amem[qq])
- }
- fmt.Fprintf(foutput, "\n")
- }
- }
- return off + rr
- }
- errorf("no space in action table")
- return 0
-}
-
-//
-// print the output for the states
-//
-func output() {
- var c, u, v int
-
- if !lflag {
- fmt.Fprintf(ftable, "\n//line yacctab:1")
- }
- fmt.Fprintf(ftable, "\nvar %sExca = [...]int{\n", prefix)
-
- if len(errors) > 0 {
- stateTable = make([]Row, nstate)
- }
-
- noset := mkset()
-
- // output the stuff for state i
- for i := 0; i < nstate; i++ {
- nolook = 0
- if tystate[i] != MUSTLOOKAHEAD {
- nolook = 1
- }
- closure(i)
-
- // output actions
- nolook = 1
- aryfil(temp1, ntokens+nnonter+1, 0)
- for u = 0; u < cwp; u++ {
- c = wsets[u].pitem.first
- if c > 1 && c < NTBASE && temp1[c] == 0 {
- for v = u; v < cwp; v++ {
- if c == wsets[v].pitem.first {
- putitem(wsets[v].pitem, noset)
- }
- }
- temp1[c] = state(c)
- } else if c > NTBASE {
- c -= NTBASE
- if temp1[c+ntokens] == 0 {
- temp1[c+ntokens] = amem[indgo[i]+c]
- }
- }
- }
- if i == 1 {
- temp1[1] = ACCEPTCODE
- }
-
- // now, we have the shifts; look at the reductions
- lastred = 0
- for u = 0; u < cwp; u++ {
- c = wsets[u].pitem.first
-
- // reduction
- if c > 0 {
- continue
- }
- lastred = -c
- us := wsets[u].ws
- for k := 0; k <= ntokens; k++ {
- if bitset(us, k) == 0 {
- continue
- }
- if temp1[k] == 0 {
- temp1[k] = c
- } else if temp1[k] < 0 { // reduce/reduce conflict
- if foutput != nil {
- fmt.Fprintf(foutput,
- "\n %v: reduce/reduce conflict (red'ns "+
- "%v and %v) on %v",
- i, -temp1[k], lastred, symnam(k))
- }
- if -temp1[k] > lastred {
- temp1[k] = -lastred
- }
- zzrrconf++
- } else {
- // potential shift/reduce conflict
- precftn(lastred, k, i)
- }
- }
- }
- wract(i)
- }
-
- fmt.Fprintf(ftable, "}\n")
- ftable.WriteRune('\n')
- fmt.Fprintf(ftable, "const %sPrivate = %v\n", prefix, PRIVATE)
-}
-
-//
-// decide a shift/reduce conflict by precedence.
-// r is a rule number, t a token number
-// the conflict is in state s
-// temp1[t] is changed to reflect the action
-//
-func precftn(r, t, s int) {
- action := NOASC
-
- lp := levprd[r]
- lt := toklev[t]
- if PLEVEL(lt) == 0 || PLEVEL(lp) == 0 {
- // conflict
- if foutput != nil {
- fmt.Fprintf(foutput,
- "\n%v: shift/reduce conflict (shift %v(%v), red'n %v(%v)) on %v",
- s, temp1[t], PLEVEL(lt), r, PLEVEL(lp), symnam(t))
- }
- zzsrconf++
- return
- }
- if PLEVEL(lt) == PLEVEL(lp) {
- action = ASSOC(lt)
- } else if PLEVEL(lt) > PLEVEL(lp) {
- action = RASC // shift
- } else {
- action = LASC
- } // reduce
- switch action {
- case BASC: // error action
- temp1[t] = ERRCODE
- case LASC: // reduce
- temp1[t] = -r
- }
-}
-
-//
-// output state i
-// temp1 has the actions, lastred the default
-//
-func wract(i int) {
- var p, p1 int
-
- // find the best choice for lastred
- lastred = 0
- ntimes := 0
- for j := 0; j <= ntokens; j++ {
- if temp1[j] >= 0 {
- continue
- }
- if temp1[j]+lastred == 0 {
- continue
- }
- // count the number of appearances of temp1[j]
- count := 0
- tred := -temp1[j]
- levprd[tred] |= REDFLAG
- for p = 0; p <= ntokens; p++ {
- if temp1[p]+tred == 0 {
- count++
- }
- }
- if count > ntimes {
- lastred = tred
- ntimes = count
- }
- }
-
- //
- // for error recovery, arrange that, if there is a shift on the
- // error recovery token, `error', that the default be the error action
- //
- if temp1[2] > 0 {
- lastred = 0
- }
-
- // clear out entries in temp1 which equal lastred
- // count entries in optst table
- n := 0
- for p = 0; p <= ntokens; p++ {
- p1 = temp1[p]
- if p1+lastred == 0 {
- temp1[p] = 0
- p1 = 0
- }
- if p1 > 0 && p1 != ACCEPTCODE && p1 != ERRCODE {
- n++
- }
- }
-
- wrstate(i)
- defact[i] = lastred
- flag := 0
- os := make([]int, n*2)
- n = 0
- for p = 0; p <= ntokens; p++ {
- p1 = temp1[p]
- if p1 != 0 {
- if p1 < 0 {
- p1 = -p1
- } else if p1 == ACCEPTCODE {
- p1 = -1
- } else if p1 == ERRCODE {
- p1 = 0
- } else {
- os[n] = p
- n++
- os[n] = p1
- n++
- zzacent++
- continue
- }
- if flag == 0 {
- fmt.Fprintf(ftable, "\t-1, %v,\n", i)
- }
- flag++
- fmt.Fprintf(ftable, "\t%v, %v,\n", p, p1)
- zzexcp++
- }
- }
- if flag != 0 {
- defact[i] = -2
- fmt.Fprintf(ftable, "\t-2, %v,\n", lastred)
- }
- optst[i] = os
-}
-
-//
-// writes state i
-//
-func wrstate(i int) {
- var j0, j1, u int
- var pp, qq int
-
- if len(errors) > 0 {
- actions := append([]int(nil), temp1...)
- defaultAction := ERRCODE
- if lastred != 0 {
- defaultAction = -lastred
- }
- stateTable[i] = Row{actions, defaultAction}
- }
-
- if foutput == nil {
- return
- }
- fmt.Fprintf(foutput, "\nstate %v\n", i)
- qq = pstate[i+1]
- for pp = pstate[i]; pp < qq; pp++ {
- fmt.Fprintf(foutput, "\t%v\n", writem(statemem[pp].pitem))
- }
- if tystate[i] == MUSTLOOKAHEAD {
- // print out empty productions in closure
- for u = pstate[i+1] - pstate[i]; u < cwp; u++ {
- if wsets[u].pitem.first < 0 {
- fmt.Fprintf(foutput, "\t%v\n", writem(wsets[u].pitem))
- }
- }
- }
-
- // check for state equal to another
- for j0 = 0; j0 <= ntokens; j0++ {
- j1 = temp1[j0]
- if j1 != 0 {
- fmt.Fprintf(foutput, "\n\t%v ", symnam(j0))
-
- // shift, error, or accept
- if j1 > 0 {
- if j1 == ACCEPTCODE {
- fmt.Fprintf(foutput, "accept")
- } else if j1 == ERRCODE {
- fmt.Fprintf(foutput, "error")
- } else {
- fmt.Fprintf(foutput, "shift %v", j1)
- }
- } else {
- fmt.Fprintf(foutput, "reduce %v (src line %v)", -j1, rlines[-j1])
- }
- }
- }
-
- // output the final production
- if lastred != 0 {
- fmt.Fprintf(foutput, "\n\t. reduce %v (src line %v)\n\n",
- lastred, rlines[lastred])
- } else {
- fmt.Fprintf(foutput, "\n\t. error\n\n")
- }
-
- // now, output nonterminal actions
- j1 = ntokens
- for j0 = 1; j0 <= nnonter; j0++ {
- j1++
- if temp1[j1] != 0 {
- fmt.Fprintf(foutput, "\t%v goto %v\n", symnam(j0+NTBASE), temp1[j1])
- }
- }
-}
-
-//
-// output the gotos for the nontermninals
-//
-func go2out() {
- for i := 1; i <= nnonter; i++ {
- go2gen(i)
-
- // find the best one to make default
- best := -1
- times := 0
-
- // is j the most frequent
- for j := 0; j < nstate; j++ {
- if tystate[j] == 0 {
- continue
- }
- if tystate[j] == best {
- continue
- }
-
- // is tystate[j] the most frequent
- count := 0
- cbest := tystate[j]
- for k := j; k < nstate; k++ {
- if tystate[k] == cbest {
- count++
- }
- }
- if count > times {
- best = cbest
- times = count
- }
- }
-
- // best is now the default entry
- zzgobest += times - 1
- n := 0
- for j := 0; j < nstate; j++ {
- if tystate[j] != 0 && tystate[j] != best {
- n++
- }
- }
- goent := make([]int, 2*n+1)
- n = 0
- for j := 0; j < nstate; j++ {
- if tystate[j] != 0 && tystate[j] != best {
- goent[n] = j
- n++
- goent[n] = tystate[j]
- n++
- zzgoent++
- }
- }
-
- // now, the default
- if best == -1 {
- best = 0
- }
-
- zzgoent++
- goent[n] = best
- yypgo[i] = goent
- }
-}
-
-//
-// output the gotos for nonterminal c
-//
-func go2gen(c int) {
- var i, cc, p, q int
-
- // first, find nonterminals with gotos on c
- aryfil(temp1, nnonter+1, 0)
- temp1[c] = 1
- work := 1
- for work != 0 {
- work = 0
- for i = 0; i < nprod; i++ {
- // cc is a nonterminal with a goto on c
- cc = prdptr[i][1] - NTBASE
- if cc >= 0 && temp1[cc] != 0 {
- // thus, the left side of production i does too
- cc = prdptr[i][0] - NTBASE
- if temp1[cc] == 0 {
- work = 1
- temp1[cc] = 1
- }
- }
- }
- }
-
- // now, we have temp1[c] = 1 if a goto on c in closure of cc
- if g2debug != 0 && foutput != nil {
- fmt.Fprintf(foutput, "%v: gotos on ", nontrst[c].name)
- for i = 0; i <= nnonter; i++ {
- if temp1[i] != 0 {
- fmt.Fprintf(foutput, "%v ", nontrst[i].name)
- }
- }
- fmt.Fprintf(foutput, "\n")
- }
-
- // now, go through and put gotos into tystate
- aryfil(tystate, nstate, 0)
- for i = 0; i < nstate; i++ {
- q = pstate[i+1]
- for p = pstate[i]; p < q; p++ {
- cc = statemem[p].pitem.first
- if cc >= NTBASE {
- // goto on c is possible
- if temp1[cc-NTBASE] != 0 {
- tystate[i] = amem[indgo[i]+c]
- break
- }
- }
- }
- }
-}
-
-//
-// in order to free up the mem and amem arrays for the optimizer,
-// and still be able to output yyr1, etc., after the sizes of
-// the action array is known, we hide the nonterminals
-// derived by productions in levprd.
-//
-func hideprod() {
- nred := 0
- levprd[0] = 0
- for i := 1; i < nprod; i++ {
- if (levprd[i] & REDFLAG) == 0 {
- if foutput != nil {
- fmt.Fprintf(foutput, "Rule not reduced: %v\n",
- writem(Pitem{prdptr[i], 0, 0, i}))
- }
- fmt.Printf("rule %v never reduced\n", writem(Pitem{prdptr[i], 0, 0, i}))
- nred++
- }
- levprd[i] = prdptr[i][0] - NTBASE
- }
- if nred != 0 {
- fmt.Printf("%v rules never reduced\n", nred)
- }
-}
-
-func callopt() {
- var j, k, p, q, i int
- var v []int
-
- pgo = make([]int, nnonter+1)
- pgo[0] = 0
- maxoff = 0
- maxspr = 0
- for i = 0; i < nstate; i++ {
- k = 32000
- j = 0
- v = optst[i]
- q = len(v)
- for p = 0; p < q; p += 2 {
- if v[p] > j {
- j = v[p]
- }
- if v[p] < k {
- k = v[p]
- }
- }
-
- // nontrivial situation
- if k <= j {
- // j is now the range
- // j -= k; // call scj
- if k > maxoff {
- maxoff = k
- }
- }
- tystate[i] = q + 2*j
- if j > maxspr {
- maxspr = j
- }
- }
-
- // initialize ggreed table
- ggreed = make([]int, nnonter+1)
- for i = 1; i <= nnonter; i++ {
- ggreed[i] = 1
- j = 0
-
- // minimum entry index is always 0
- v = yypgo[i]
- q = len(v) - 1
- for p = 0; p < q; p += 2 {
- ggreed[i] += 2
- if v[p] > j {
- j = v[p]
- }
- }
- ggreed[i] = ggreed[i] + 2*j
- if j > maxoff {
- maxoff = j
- }
- }
-
- // now, prepare to put the shift actions into the amem array
- for i = 0; i < ACTSIZE; i++ {
- amem[i] = 0
- }
- maxa = 0
- for i = 0; i < nstate; i++ {
- if tystate[i] == 0 && adb > 1 {
- fmt.Fprintf(ftable, "State %v: null\n", i)
- }
- indgo[i] = yyFlag
- }
-
- i = nxti()
- for i != NOMORE {
- if i >= 0 {
- stin(i)
- } else {
- gin(-i)
- }
- i = nxti()
- }
-
- // print amem array
- if adb > 2 {
- for p = 0; p <= maxa; p += 10 {
- fmt.Fprintf(ftable, "%v ", p)
- for i = 0; i < 10; i++ {
- fmt.Fprintf(ftable, "%v ", amem[p+i])
- }
- ftable.WriteRune('\n')
- }
- }
-
- aoutput()
- osummary()
-}
-
-//
-// finds the next i
-//
-func nxti() int {
- max := 0
- maxi := 0
- for i := 1; i <= nnonter; i++ {
- if ggreed[i] >= max {
- max = ggreed[i]
- maxi = -i
- }
- }
- for i := 0; i < nstate; i++ {
- if tystate[i] >= max {
- max = tystate[i]
- maxi = i
- }
- }
- if max == 0 {
- return NOMORE
- }
- return maxi
-}
-
-func gin(i int) {
- var s int
-
- // enter gotos on nonterminal i into array amem
- ggreed[i] = 0
-
- q := yypgo[i]
- nq := len(q) - 1
-
- // now, find amem place for it
-nextgp:
- for p := 0; p < ACTSIZE; p++ {
- if amem[p] != 0 {
- continue
- }
- for r := 0; r < nq; r += 2 {
- s = p + q[r] + 1
- if s > maxa {
- maxa = s
- if maxa >= ACTSIZE {
- errorf("a array overflow")
- }
- }
- if amem[s] != 0 {
- continue nextgp
- }
- }
-
- // we have found amem spot
- amem[p] = q[nq]
- if p > maxa {
- maxa = p
- }
- for r := 0; r < nq; r += 2 {
- s = p + q[r] + 1
- amem[s] = q[r+1]
- }
- pgo[i] = p
- if adb > 1 {
- fmt.Fprintf(ftable, "Nonterminal %v, entry at %v\n", i, pgo[i])
- }
- return
- }
- errorf("cannot place goto %v\n", i)
-}
-
-func stin(i int) {
- var s int
-
- tystate[i] = 0
-
- // enter state i into the amem array
- q := optst[i]
- nq := len(q)
-
-nextn:
- // find an acceptable place
- for n := -maxoff; n < ACTSIZE; n++ {
- flag := 0
- for r := 0; r < nq; r += 2 {
- s = q[r] + n
- if s < 0 || s > ACTSIZE {
- continue nextn
- }
- if amem[s] == 0 {
- flag++
- } else if amem[s] != q[r+1] {
- continue nextn
- }
- }
-
- // check the position equals another only if the states are identical
- for j := 0; j < nstate; j++ {
- if indgo[j] == n {
-
- // we have some disagreement
- if flag != 0 {
- continue nextn
- }
- if nq == len(optst[j]) {
-
- // states are equal
- indgo[i] = n
- if adb > 1 {
- fmt.Fprintf(ftable, "State %v: entry at"+
- "%v equals state %v\n",
- i, n, j)
- }
- return
- }
-
- // we have some disagreement
- continue nextn
- }
- }
-
- for r := 0; r < nq; r += 2 {
- s = q[r] + n
- if s > maxa {
- maxa = s
- }
- if amem[s] != 0 && amem[s] != q[r+1] {
- errorf("clobber of a array, pos'n %v, by %v", s, q[r+1])
- }
- amem[s] = q[r+1]
- }
- indgo[i] = n
- if adb > 1 {
- fmt.Fprintf(ftable, "State %v: entry at %v\n", i, indgo[i])
- }
- return
- }
- errorf("Error; failure to place state %v", i)
-}
-
-//
-// this version is for limbo
-// write out the optimized parser
-//
-func aoutput() {
- ftable.WriteRune('\n')
- fmt.Fprintf(ftable, "const %sLast = %v\n", prefix, maxa+1)
- arout("Act", amem, maxa+1)
- arout("Pact", indgo, nstate)
- arout("Pgo", pgo, nnonter+1)
-}
-
-//
-// put out other arrays, copy the parsers
-//
-func others() {
- var i, j int
-
- arout("R1", levprd, nprod)
- aryfil(temp1, nprod, 0)
-
- //
- //yyr2 is the number of rules for each production
- //
- for i = 1; i < nprod; i++ {
- temp1[i] = len(prdptr[i]) - 2
- }
- arout("R2", temp1, nprod)
-
- aryfil(temp1, nstate, -1000)
- for i = 0; i <= ntokens; i++ {
- for j := tstates[i]; j != 0; j = mstates[j] {
- temp1[j] = i
- }
- }
- for i = 0; i <= nnonter; i++ {
- for j = ntstates[i]; j != 0; j = mstates[j] {
- temp1[j] = -i
- }
- }
- arout("Chk", temp1, nstate)
- arout("Def", defact, nstate)
-
- // put out token translation tables
- // table 1 has 0-256
- aryfil(temp1, 256, 0)
- c := 0
- for i = 1; i <= ntokens; i++ {
- j = tokset[i].value
- if j >= 0 && j < 256 {
- if temp1[j] != 0 {
- fmt.Print("yacc bug -- cannot have 2 different Ts with same value\n")
- fmt.Printf(" %s and %s\n", tokset[i].name, tokset[temp1[j]].name)
- nerrors++
- }
- temp1[j] = i
- if j > c {
- c = j
- }
- }
- }
- for i = 0; i <= c; i++ {
- if temp1[i] == 0 {
- temp1[i] = YYLEXUNK
- }
- }
- arout("Tok1", temp1, c+1)
-
- // table 2 has PRIVATE-PRIVATE+256
- aryfil(temp1, 256, 0)
- c = 0
- for i = 1; i <= ntokens; i++ {
- j = tokset[i].value - PRIVATE
- if j >= 0 && j < 256 {
- if temp1[j] != 0 {
- fmt.Print("yacc bug -- cannot have 2 different Ts with same value\n")
- fmt.Printf(" %s and %s\n", tokset[i].name, tokset[temp1[j]].name)
- nerrors++
- }
- temp1[j] = i
- if j > c {
- c = j
- }
- }
- }
- arout("Tok2", temp1, c+1)
-
- // table 3 has everything else
- ftable.WriteRune('\n')
- fmt.Fprintf(ftable, "var %sTok3 = [...]int{\n\t", prefix)
- c = 0
- for i = 1; i <= ntokens; i++ {
- j = tokset[i].value
- if j >= 0 && j < 256 {
- continue
- }
- if j >= PRIVATE && j < 256+PRIVATE {
- continue
- }
-
- if c%5 != 0 {
- ftable.WriteRune(' ')
- }
- fmt.Fprintf(ftable, "%d, %d,", j, i)
- c++
- if c%5 == 0 {
- fmt.Fprint(ftable, "\n\t")
- }
- }
- if c%5 != 0 {
- ftable.WriteRune(' ')
- }
- fmt.Fprintf(ftable, "%d,\n}\n", 0)
-
- // Custom error messages.
- fmt.Fprintf(ftable, "\n")
- fmt.Fprintf(ftable, "var %sErrorMessages = [...]struct {\n", prefix)
- fmt.Fprintf(ftable, "\tstate int\n")
- fmt.Fprintf(ftable, "\ttoken int\n")
- fmt.Fprintf(ftable, "\tmsg string\n")
- fmt.Fprintf(ftable, "}{\n")
- for _, error := range errors {
- lineno = error.lineno
- state, token := runMachine(error.tokens)
- fmt.Fprintf(ftable, "\t{%v, %v, %s},\n", state, token, error.msg)
- }
- fmt.Fprintf(ftable, "}\n")
-
- // copy parser text
- ch := getrune(finput)
- for ch != EOF {
- ftable.WriteRune(ch)
- ch = getrune(finput)
- }
-
- // copy yaccpar
- if !lflag {
- fmt.Fprintf(ftable, "\n//line yaccpar:1\n")
- }
-
- parts := strings.SplitN(yaccpar, prefix+"run()", 2)
- fmt.Fprintf(ftable, "%v", parts[0])
- ftable.Write(fcode.Bytes())
- fmt.Fprintf(ftable, "%v", parts[1])
-}
-
-func runMachine(tokens []string) (state, token int) {
- var stack []int
- i := 0
- token = -1
-
-Loop:
- if token < 0 {
- token = chfind(2, tokens[i])
- i++
- }
-
- row := stateTable[state]
-
- c := token
- if token >= NTBASE {
- c = token - NTBASE + ntokens
- }
- action := row.actions[c]
- if action == 0 {
- action = row.defaultAction
- }
-
- switch {
- case action == ACCEPTCODE:
- errorf("tokens are accepted")
- return
- case action == ERRCODE:
- if token >= NTBASE {
- errorf("error at non-terminal token %s", symnam(token))
- }
- return
- case action > 0:
- // Shift to state action.
- stack = append(stack, state)
- state = action
- token = -1
- goto Loop
- default:
- // Reduce by production -action.
- prod := prdptr[-action]
- if rhsLen := len(prod) - 2; rhsLen > 0 {
- n := len(stack) - rhsLen
- state = stack[n]
- stack = stack[:n]
- }
- if token >= 0 {
- i--
- }
- token = prod[0]
- goto Loop
- }
-}
-
-func arout(s string, v []int, n int) {
- s = prefix + s
- ftable.WriteRune('\n')
- fmt.Fprintf(ftable, "var %v = [...]int{", s)
- for i := 0; i < n; i++ {
- if i%10 == 0 {
- fmt.Fprintf(ftable, "\n\t")
- } else {
- ftable.WriteRune(' ')
- }
- fmt.Fprintf(ftable, "%d,", v[i])
- }
- fmt.Fprintf(ftable, "\n}\n")
-}
-
-//
-// output the summary on y.output
-//
-func summary() {
- if foutput != nil {
- fmt.Fprintf(foutput, "\n%v terminals, %v nonterminals\n", ntokens, nnonter+1)
- fmt.Fprintf(foutput, "%v grammar rules, %v/%v states\n", nprod, nstate, NSTATES)
- fmt.Fprintf(foutput, "%v shift/reduce, %v reduce/reduce conflicts reported\n", zzsrconf, zzrrconf)
- fmt.Fprintf(foutput, "%v working sets used\n", len(wsets))
- fmt.Fprintf(foutput, "memory: parser %v/%v\n", memp, ACTSIZE)
- fmt.Fprintf(foutput, "%v extra closures\n", zzclose-2*nstate)
- fmt.Fprintf(foutput, "%v shift entries, %v exceptions\n", zzacent, zzexcp)
- fmt.Fprintf(foutput, "%v goto entries\n", zzgoent)
- fmt.Fprintf(foutput, "%v entries saved by goto default\n", zzgobest)
- }
- if zzsrconf != 0 || zzrrconf != 0 {
- fmt.Printf("\nconflicts: ")
- if zzsrconf != 0 {
- fmt.Printf("%v shift/reduce", zzsrconf)
- }
- if zzsrconf != 0 && zzrrconf != 0 {
- fmt.Printf(", ")
- }
- if zzrrconf != 0 {
- fmt.Printf("%v reduce/reduce", zzrrconf)
- }
- fmt.Printf("\n")
- }
-}
-
-//
-// write optimizer summary
-//
-func osummary() {
- if foutput == nil {
- return
- }
- i := 0
- for p := maxa; p >= 0; p-- {
- if amem[p] == 0 {
- i++
- }
- }
-
- fmt.Fprintf(foutput, "Optimizer space used: output %v/%v\n", maxa+1, ACTSIZE)
- fmt.Fprintf(foutput, "%v table entries, %v zero\n", maxa+1, i)
- fmt.Fprintf(foutput, "maximum spread: %v, maximum offset: %v\n", maxspr, maxoff)
-}
-
-//
-// copies and protects "'s in q
-//
-func chcopy(q string) string {
- s := ""
- i := 0
- j := 0
- for i = 0; i < len(q); i++ {
- if q[i] == '"' {
- s += q[j:i] + "\\"
- j = i
- }
- }
- return s + q[j:i]
-}
-
-func usage() {
- fmt.Fprintf(stderr, "usage: yacc [-o output] [-v parsetable] input\n")
- exit(1)
-}
-
-func bitset(set Lkset, bit int) int { return set[bit>>5] & (1 << uint(bit&31)) }
-
-func setbit(set Lkset, bit int) { set[bit>>5] |= (1 << uint(bit&31)) }
-
-func mkset() Lkset { return make([]int, tbitset) }
-
-//
-// set a to the union of a and b
-// return 1 if b is not a subset of a, 0 otherwise
-//
-func setunion(a, b []int) int {
- sub := 0
- for i := 0; i < tbitset; i++ {
- x := a[i]
- y := x | b[i]
- a[i] = y
- if y != x {
- sub = 1
- }
- }
- return sub
-}
-
-func prlook(p Lkset) {
- if p == nil {
- fmt.Fprintf(foutput, "\tNULL")
- return
- }
- fmt.Fprintf(foutput, " { ")
- for j := 0; j <= ntokens; j++ {
- if bitset(p, j) != 0 {
- fmt.Fprintf(foutput, "%v ", symnam(j))
- }
- }
- fmt.Fprintf(foutput, "}")
-}
-
-//
-// utility routines
-//
-var peekrune rune
-
-func isdigit(c rune) bool { return c >= '0' && c <= '9' }
-
-func isword(c rune) bool {
- return c >= 0xa0 || c == '_' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
-}
-
-//
-// return 1 if 2 arrays are equal
-// return 0 if not equal
-//
-func aryeq(a []int, b []int) int {
- n := len(a)
- if len(b) != n {
- return 0
- }
- for ll := 0; ll < n; ll++ {
- if a[ll] != b[ll] {
- return 0
- }
- }
- return 1
-}
-
-func getrune(f *bufio.Reader) rune {
- var r rune
-
- if peekrune != 0 {
- if peekrune == EOF {
- return EOF
- }
- r = peekrune
- peekrune = 0
- return r
- }
-
- c, n, err := f.ReadRune()
- if n == 0 {
- return EOF
- }
- if err != nil {
- errorf("read error: %v", err)
- }
- //fmt.Printf("rune = %v n=%v\n", string(c), n);
- return c
-}
-
-func ungetrune(f *bufio.Reader, c rune) {
- if f != finput {
- panic("ungetc - not finput")
- }
- if peekrune != 0 {
- panic("ungetc - 2nd unget")
- }
- peekrune = c
-}
-
-func open(s string) *bufio.Reader {
- fi, err := os.Open(s)
- if err != nil {
- errorf("error opening %v: %v", s, err)
- }
- //fmt.Printf("open %v\n", s);
- return bufio.NewReader(fi)
-}
-
-func create(s string) *bufio.Writer {
- fo, err := os.Create(s)
- if err != nil {
- errorf("error creating %v: %v", s, err)
- }
- //fmt.Printf("create %v mode %v\n", s);
- return bufio.NewWriter(fo)
-}
-
-//
-// write out error comment
-//
-func lerrorf(lineno int, s string, v ...interface{}) {
- nerrors++
- fmt.Fprintf(stderr, s, v...)
- fmt.Fprintf(stderr, ": %v:%v\n", infile, lineno)
- if fatfl != 0 {
- summary()
- exit(1)
- }
-}
-
-func errorf(s string, v ...interface{}) {
- lerrorf(lineno, s, v...)
-}
-
-func exit(status int) {
- if ftable != nil {
- ftable.Flush()
- ftable = nil
- gofmt()
- }
- if foutput != nil {
- foutput.Flush()
- foutput = nil
- }
- if stderr != nil {
- stderr.Flush()
- stderr = nil
- }
- os.Exit(status)
-}
-
-func gofmt() {
- src, err := ioutil.ReadFile(oflag)
- if err != nil {
- return
- }
- src, err = format.Source(src)
- if err != nil {
- return
- }
- ioutil.WriteFile(oflag, src, 0666)
-}
-
-var yaccpar string // will be processed version of yaccpartext: s/$$/prefix/g
-var yaccpartext = `
-/* parser for yacc output */
-
-var (
- $$Debug = 0
- $$ErrorVerbose = false
-)
-
-type $$Lexer interface {
- Lex(lval *$$SymType) int
- Error(s string)
-}
-
-type $$Parser interface {
- Parse($$Lexer) int
- Lookahead() int
-}
-
-type $$ParserImpl struct {
- lval $$SymType
- stack [$$InitialStackSize]$$SymType
- char int
-}
-
-func (p *$$ParserImpl) Lookahead() int {
- return p.char
-}
-
-func $$NewParser() $$Parser {
- return &$$ParserImpl{}
-}
-
-const $$Flag = -1000
-
-func $$Tokname(c int) string {
- if c >= 1 && c-1 < len($$Toknames) {
- if $$Toknames[c-1] != "" {
- return $$Toknames[c-1]
- }
- }
- return __yyfmt__.Sprintf("tok-%v", c)
-}
-
-func $$Statname(s int) string {
- if s >= 0 && s < len($$Statenames) {
- if $$Statenames[s] != "" {
- return $$Statenames[s]
- }
- }
- return __yyfmt__.Sprintf("state-%v", s)
-}
-
-func $$ErrorMessage(state, lookAhead int) string {
- const TOKSTART = 4
-
- if !$$ErrorVerbose {
- return "syntax error"
- }
-
- for _, e := range $$ErrorMessages {
- if e.state == state && e.token == lookAhead {
- return "syntax error: " + e.msg
- }
- }
-
- res := "syntax error: unexpected " + $$Tokname(lookAhead)
-
- // To match Bison, suggest at most four expected tokens.
- expected := make([]int, 0, 4)
-
- // Look for shiftable tokens.
- base := $$Pact[state]
- for tok := TOKSTART; tok-1 < len($$Toknames); tok++ {
- if n := base + tok; n >= 0 && n < $$Last && $$Chk[$$Act[n]] == tok {
- if len(expected) == cap(expected) {
- return res
- }
- expected = append(expected, tok)
- }
- }
-
- if $$Def[state] == -2 {
- i := 0
- for $$Exca[i] != -1 || $$Exca[i+1] != state {
- i += 2
- }
-
- // Look for tokens that we accept or reduce.
- for i += 2; $$Exca[i] >= 0; i += 2 {
- tok := $$Exca[i]
- if tok < TOKSTART || $$Exca[i+1] == 0 {
- continue
- }
- if len(expected) == cap(expected) {
- return res
- }
- expected = append(expected, tok)
- }
-
- // If the default action is to accept or reduce, give up.
- if $$Exca[i+1] != 0 {
- return res
- }
- }
-
- for i, tok := range expected {
- if i == 0 {
- res += ", expecting "
- } else {
- res += " or "
- }
- res += $$Tokname(tok)
- }
- return res
-}
-
-func $$lex1(lex $$Lexer, lval *$$SymType) (char, token int) {
- token = 0
- char = lex.Lex(lval)
- if char <= 0 {
- token = $$Tok1[0]
- goto out
- }
- if char < len($$Tok1) {
- token = $$Tok1[char]
- goto out
- }
- if char >= $$Private {
- if char < $$Private+len($$Tok2) {
- token = $$Tok2[char-$$Private]
- goto out
- }
- }
- for i := 0; i < len($$Tok3); i += 2 {
- token = $$Tok3[i+0]
- if token == char {
- token = $$Tok3[i+1]
- goto out
- }
- }
-
-out:
- if token == 0 {
- token = $$Tok2[1] /* unknown char */
- }
- if $$Debug >= 3 {
- __yyfmt__.Printf("lex %s(%d)\n", $$Tokname(token), uint(char))
- }
- return char, token
-}
-
-func $$Parse($$lex $$Lexer) int {
- return $$NewParser().Parse($$lex)
-}
-
-func ($$rcvr *$$ParserImpl) Parse($$lex $$Lexer) int {
- var $$n int
- var $$VAL $$SymType
- var $$Dollar []$$SymType
- _ = $$Dollar // silence set and not used
- $$S := $$rcvr.stack[:]
-
- Nerrs := 0 /* number of errors */
- Errflag := 0 /* error recovery flag */
- $$state := 0
- $$rcvr.char = -1
- $$token := -1 // $$rcvr.char translated into internal numbering
- defer func() {
- // Make sure we report no lookahead when not parsing.
- $$state = -1
- $$rcvr.char = -1
- $$token = -1
- }()
- $$p := -1
- goto $$stack
-
-ret0:
- return 0
-
-ret1:
- return 1
-
-$$stack:
- /* put a state and value onto the stack */
- if $$Debug >= 4 {
- __yyfmt__.Printf("char %v in %v\n", $$Tokname($$token), $$Statname($$state))
- }
-
- $$p++
- if $$p >= len($$S) {
- nyys := make([]$$SymType, len($$S)*2)
- copy(nyys, $$S)
- $$S = nyys
- }
- $$S[$$p] = $$VAL
- $$S[$$p].yys = $$state
-
-$$newstate:
- $$n = $$Pact[$$state]
- if $$n <= $$Flag {
- goto $$default /* simple state */
- }
- if $$rcvr.char < 0 {
- $$rcvr.char, $$token = $$lex1($$lex, &$$rcvr.lval)
- }
- $$n += $$token
- if $$n < 0 || $$n >= $$Last {
- goto $$default
- }
- $$n = $$Act[$$n]
- if $$Chk[$$n] == $$token { /* valid shift */
- $$rcvr.char = -1
- $$token = -1
- $$VAL = $$rcvr.lval
- $$state = $$n
- if Errflag > 0 {
- Errflag--
- }
- goto $$stack
- }
-
-$$default:
- /* default state action */
- $$n = $$Def[$$state]
- if $$n == -2 {
- if $$rcvr.char < 0 {
- $$rcvr.char, $$token = $$lex1($$lex, &$$rcvr.lval)
- }
-
- /* look through exception table */
- xi := 0
- for {
- if $$Exca[xi+0] == -1 && $$Exca[xi+1] == $$state {
- break
- }
- xi += 2
- }
- for xi += 2; ; xi += 2 {
- $$n = $$Exca[xi+0]
- if $$n < 0 || $$n == $$token {
- break
- }
- }
- $$n = $$Exca[xi+1]
- if $$n < 0 {
- goto ret0
- }
- }
- if $$n == 0 {
- /* error ... attempt to resume parsing */
- switch Errflag {
- case 0: /* brand new error */
- $$lex.Error($$ErrorMessage($$state, $$token))
- Nerrs++
- if $$Debug >= 1 {
- __yyfmt__.Printf("%s", $$Statname($$state))
- __yyfmt__.Printf(" saw %s\n", $$Tokname($$token))
- }
- fallthrough
-
- case 1, 2: /* incompletely recovered error ... try again */
- Errflag = 3
-
- /* find a state where "error" is a legal shift action */
- for $$p >= 0 {
- $$n = $$Pact[$$S[$$p].yys] + $$ErrCode
- if $$n >= 0 && $$n < $$Last {
- $$state = $$Act[$$n] /* simulate a shift of "error" */
- if $$Chk[$$state] == $$ErrCode {
- goto $$stack
- }
- }
-
- /* the current p has no shift on "error", pop stack */
- if $$Debug >= 2 {
- __yyfmt__.Printf("error recovery pops state %d\n", $$S[$$p].yys)
- }
- $$p--
- }
- /* there is no state on the stack with an error shift ... abort */
- goto ret1
-
- case 3: /* no shift yet; clobber input char */
- if $$Debug >= 2 {
- __yyfmt__.Printf("error recovery discards %s\n", $$Tokname($$token))
- }
- if $$token == $$EofCode {
- goto ret1
- }
- $$rcvr.char = -1
- $$token = -1
- goto $$newstate /* try again in the same state */
- }
- }
-
- /* reduction by production $$n */
- if $$Debug >= 2 {
- __yyfmt__.Printf("reduce %v in:\n\t%v\n", $$n, $$Statname($$state))
- }
-
- $$nt := $$n
- $$pt := $$p
- _ = $$pt // guard against "declared and not used"
-
- $$p -= $$R2[$$n]
- // $$p is now the index of $0. Perform the default action. Iff the
- // reduced production is ε, $1 is possibly out of range.
- if $$p+1 >= len($$S) {
- nyys := make([]$$SymType, len($$S)*2)
- copy(nyys, $$S)
- $$S = nyys
- }
- $$VAL = $$S[$$p+1]
-
- /* consult goto table to find next state */
- $$n = $$R1[$$n]
- $$g := $$Pgo[$$n]
- $$j := $$g + $$S[$$p].yys + 1
-
- if $$j >= $$Last {
- $$state = $$Act[$$g]
- } else {
- $$state = $$Act[$$j]
- if $$Chk[$$state] != -$$n {
- $$state = $$Act[$$g]
- }
- }
- // dummy call; replaced with literal code
- $$run()
- goto $$stack /* stack new state and value */
-}
-`