func setup()

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)
		}
	}
}