in cmd/goyacc/yacc.go [372:742]
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)
}
}
}