github.com/pingcap/tidb/parser@v0.0.0-20231013125129-93a834a6bf8d/goyacc/main.go (about)

     1  // Copyright 2016 PingCAP, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  // Copyright 2014 The goyacc Authors. All rights reserved.
    15  // Use of this source code is governed by a BSD-style
    16  // license that can be found in the LICENSE file.
    17  
    18  // This source code uses portions of code previously published in the Go tool
    19  // yacc[0] program, the respective license can be found in the LICENSE-GO-YACC
    20  // file.
    21  
    22  // Goyacc is a version of yacc generating Go parsers.
    23  //
    24  // # Usage
    25  //
    26  // Note: If no non flag arguments are given, goyacc reads standard input.
    27  //
    28  //	goyacc [options] [input]
    29  //
    30  //	options and (defaults)
    31  //		-c                  Report state closures. (false)
    32  //		-cr                 Check all states are reducible. (false)
    33  //		-dlval              Debug value when runtime yyDebug >= 3. ("lval")
    34  //		-dlvalf             Debug format of -dlval. ("%+v")
    35  //		-ex                 Explain how were conflicts resolved. (false)
    36  //		-l                  Disable line directives, for compatibility only - ignored. (false)
    37  //		-la                 Report all lookahead sets. (false)
    38  //		-o outputFile       Parser output. ("y.go")
    39  //		-p prefix           Name prefix to use in generated code. ("yy")
    40  //		-v reportFile       Create grammar report. ("y.output")
    41  //		-xe examplesFile    Generate error messages by examples. ("")
    42  //		-xegen examplesFile Generate a file suitable for -xe automatically from the grammar.
    43  //		                    The file must not exist. ("")
    44  //
    45  // # Changelog
    46  //
    47  // 2015-03-24: The search for a custom error message is now extended to include
    48  // also the last state that was shifted into, if any. This change resolves a
    49  // problem in which a lookahead symbol is valid for a reduce action in state A,
    50  // but the same symbol is later never accepted by any shift action in some
    51  // state B which is popped from the state stack after the reduction is
    52  // performed. The computed from example state is A but when the error is
    53  // actually detected, the state is now B and the custom error was thus not
    54  // used.
    55  //
    56  // 2015-02-23: Added -xegen flag. It can be used to automagically generate a
    57  // skeleton errors by example file which can be, for example, edited and/or
    58  // submited later as an argument of the -xe option.
    59  //
    60  // 2014-12-18: Support %precedence for better bison compatibility[3]. The
    61  // actual changes are in packages goyacc is dependent on. Goyacc users should
    62  // rebuild the binary:
    63  //
    64  //	$ go get -u github.com/cznic/goyacc
    65  //
    66  // 2014-12-02: Added support for the optional yyLexerEx interface. The Reduced
    67  // method can be useful for debugging and/or automatically producing examples
    68  // by parsing code fragments. If it returns true the parser exits immediately
    69  // with return value -1.
    70  //
    71  // # Overview
    72  //
    73  // The generated parser is reentrant and mostly backwards compatible with
    74  // parsers generated by go tool yacc[0]. yyParse expects to be given an
    75  // argument that conforms to the following interface:
    76  //
    77  //	type yyLexer interface {
    78  //		Lex(lval *yySymType) int
    79  //		Errorf(format string,  a ...interface{})
    80  //		Errors() (warns []error, errs []error)
    81  //	}
    82  //
    83  // Optionally the argument to yyParse may implement the following interface:
    84  //
    85  //	type yyLexerEx interface {
    86  //		yyLexer
    87  //		// Hook for recording a reduction.
    88  //		Reduced(rule, state int, lval *yySymType) (stop bool) // Client should copy *lval.
    89  //	}
    90  //
    91  // Lex should return the token identifier, and place other token information in
    92  // lval (which replaces the usual yylval). Error is equivalent to yyerror in
    93  // the original yacc.
    94  //
    95  // Code inside the parser may refer to the variable yylex, which holds the
    96  // yyLexer passed to Parse.
    97  //
    98  // Multiple grammars compiled into a single program should be placed in
    99  // distinct packages. If that is impossible, the "-p prefix" flag to yacc sets
   100  // the prefix, by default yy, that begins the names of symbols, including
   101  // types, the parser, and the lexer, generated and referenced by yacc's
   102  // generated code. Setting it to distinct values allows multiple grammars to be
   103  // placed in a single package.
   104  //
   105  // # Differences wrt go tool yacc
   106  //
   107  // - goyacc implements ideas from "Generating LR Syntax Error Messages from
   108  // Examples"[1]. Use the -xe flag to pass a name of the example file. For more
   109  // details about the example format please see [2].
   110  //
   111  // - The grammar report includes example token sequences leading to the
   112  // particular state. Can help understanding conflicts.
   113  //
   114  // - Minor changes in parser debug output.
   115  //
   116  // # Links
   117  //
   118  // Referenced from elsewhere:
   119  //
   120  //	[0]: http://golang.org/cmd/yacc/
   121  //	[1]: http://people.via.ecp.fr/~stilgar/doc/compilo/parser/Generating%20LR%20Syntax%20Error%20Messages.pdf
   122  //	[2]: http://godoc.org/github.com/cznic/y#hdr-Error_Examples
   123  //	[3]: http://www.gnu.org/software/bison/manual/html_node/Precedence-Only.html#Precedence-Only
   124  package main
   125  
   126  import (
   127  	"bufio"
   128  	"bytes"
   129  	"flag"
   130  	"fmt"
   131  	"go/format"
   132  	"go/scanner"
   133  	"go/token"
   134  	"io"
   135  	"log"
   136  	"os"
   137  	"runtime"
   138  	"slices"
   139  	"sort"
   140  	"strings"
   141  
   142  	"github.com/cznic/mathutil"
   143  	"github.com/cznic/sortutil"
   144  	"github.com/cznic/strutil"
   145  	parser "modernc.org/parser/yacc"
   146  	"modernc.org/y"
   147  )
   148  
   149  var (
   150  	//oNoDefault = flag.Bool("nodefault", false, "disable generating $default actions")
   151  	oClosures   = flag.Bool("c", false, "report state closures")
   152  	oReducible  = flag.Bool("cr", false, "check all states are reducible")
   153  	oDlval      = flag.String("dlval", "lval", "debug value (runtime yyDebug >= 3)")
   154  	oDlvalf     = flag.String("dlvalf", "%+v", "debug format of -dlval (runtime yyDebug >= 3)")
   155  	oLA         = flag.Bool("la", false, "report all lookahead sets")
   156  	oNoLines    = flag.Bool("l", false, "disable line directives (for compatibility ony - ignored)")
   157  	oOut        = flag.String("o", "y.go", "parser output")
   158  	oPref       = flag.String("p", "yy", "name prefix to use in generated code")
   159  	oReport     = flag.String("v", "y.output", "create grammar report")
   160  	oResolved   = flag.Bool("ex", false, "explain how were conflicts resolved")
   161  	oXErrors    = flag.String("xe", "", "generate eXtra errors from examples source file")
   162  	oXErrorsGen = flag.String("xegen", "", "generate error from examples source file automatically from the grammar")
   163  	oFormat     = flag.Bool("fmt", false, "format the yacc file")
   164  	oFormatOut  = flag.String("fmtout", "golden.y", "yacc formatter output")
   165  	oParserType = flag.String("t", "Parser", "name of the parser in the generated yyParse() function")
   166  )
   167  
   168  func main() {
   169  	log.SetFlags(0)
   170  
   171  	defer func() {
   172  		_, file, line, ok := runtime.Caller(2)
   173  		if e := recover(); e != nil {
   174  			switch {
   175  			case ok:
   176  				log.Fatalf("%s:%d: panic: %v", file, line, e)
   177  			default:
   178  				log.Fatalf("panic: %v", e)
   179  			}
   180  		}
   181  	}()
   182  
   183  	flag.Parse()
   184  	var in string
   185  	switch flag.NArg() {
   186  	case 0:
   187  		in = os.Stdin.Name()
   188  	case 1:
   189  		in = flag.Arg(0)
   190  	default:
   191  		log.Fatal("expected at most one non flag argument")
   192  	}
   193  
   194  	if *oFormat {
   195  		if err := Format(in, *oFormatOut); err != nil {
   196  			log.Fatal(err)
   197  		}
   198  		return
   199  	}
   200  
   201  	if err := main1(in); err != nil {
   202  		switch x := err.(type) {
   203  		case scanner.ErrorList:
   204  			for _, v := range x {
   205  				fmt.Fprintf(os.Stderr, "%v\n", v)
   206  			}
   207  			os.Exit(1)
   208  		default:
   209  			log.Fatal(err)
   210  		}
   211  	}
   212  }
   213  
   214  type symUsed struct {
   215  	sym  *y.Symbol
   216  	used int
   217  }
   218  
   219  type symsUsed []symUsed
   220  
   221  func (s symsUsed) Len() int      { return len(s) }
   222  func (s symsUsed) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
   223  
   224  func (s symsUsed) Less(i, j int) bool {
   225  	if s[i].used > s[j].used {
   226  		return true
   227  	}
   228  
   229  	if s[i].used < s[j].used {
   230  		return false
   231  	}
   232  
   233  	caseFoldedCompare := strings.Compare(strings.ToLower(s[i].sym.Name), strings.ToLower(s[j].sym.Name))
   234  	if caseFoldedCompare < 0 {
   235  		return true
   236  	}
   237  	if caseFoldedCompare > 0 {
   238  		return false
   239  	}
   240  
   241  	return s[i].sym.Name < s[j].sym.Name
   242  }
   243  
   244  func main1(in string) (err error) {
   245  	var out io.Writer
   246  	if nm := *oOut; nm != "" {
   247  		var f *os.File
   248  		var e error
   249  		if f, err = os.Create(nm); err != nil {
   250  			return err
   251  		}
   252  
   253  		defer func() {
   254  			if e1 := f.Close(); e1 != nil && err == nil {
   255  				err = e1
   256  			}
   257  		}()
   258  		w := bufio.NewWriter(f)
   259  		defer func() {
   260  			if e1 := w.Flush(); e1 != nil && err == nil {
   261  				err = e1
   262  			}
   263  		}()
   264  		buf := bytes.NewBuffer(nil)
   265  		out = buf
   266  		defer func() {
   267  			var dest []byte
   268  			if dest, e = format.Source(buf.Bytes()); e != nil {
   269  				dest = buf.Bytes()
   270  			}
   271  
   272  			if _, e = w.Write(dest); e != nil && err == nil {
   273  				err = e
   274  			}
   275  		}()
   276  	}
   277  
   278  	var rep io.Writer
   279  	if nm := *oReport; nm != "" {
   280  		f, err1 := os.Create(nm)
   281  		if err1 != nil {
   282  			return err1
   283  		}
   284  
   285  		defer func() {
   286  			if e := f.Close(); e != nil && err == nil {
   287  				err = e
   288  			}
   289  		}()
   290  		w := bufio.NewWriter(f)
   291  		defer func() {
   292  			if e := w.Flush(); e != nil && err == nil {
   293  				err = e
   294  			}
   295  		}()
   296  		rep = w
   297  	}
   298  
   299  	var xerrors []byte
   300  	if nm := *oXErrors; nm != "" {
   301  		b, err1 := os.ReadFile(nm)
   302  		if err1 != nil {
   303  			return err1
   304  		}
   305  
   306  		xerrors = b
   307  	}
   308  
   309  	p, err := y.ProcessFile(token.NewFileSet(), in, &y.Options{
   310  		//NoDefault:   *oNoDefault,
   311  		AllowConflicts: false,
   312  		Closures:       *oClosures,
   313  		LA:             *oLA,
   314  		Reducible:      *oReducible,
   315  		Report:         rep,
   316  		Resolved:       *oResolved,
   317  		XErrorsName:    *oXErrors,
   318  		XErrorsSrc:     xerrors,
   319  	})
   320  	if err != nil {
   321  		return err
   322  	}
   323  
   324  	if fn := *oXErrorsGen; fn != "" {
   325  		f, err := os.OpenFile(fn, os.O_RDWR|os.O_CREATE, 0600)
   326  		if err != nil {
   327  			return err
   328  		}
   329  
   330  		b := bufio.NewWriter(f)
   331  		if err := p.SkeletonXErrors(b); err != nil {
   332  			return err
   333  		}
   334  
   335  		if err := b.Flush(); err != nil {
   336  			return err
   337  		}
   338  
   339  		if err := f.Close(); err != nil {
   340  			return err
   341  		}
   342  	}
   343  
   344  	msu := make(map[*y.Symbol]int, len(p.Syms)) // sym -> usage
   345  	for nm, sym := range p.Syms {
   346  		if nm == "" || nm == "ε" || nm == "$accept" || nm == "#" {
   347  			continue
   348  		}
   349  
   350  		msu[sym] = 0
   351  	}
   352  	var minArg, maxArg int
   353  	for _, state := range p.Table {
   354  		for _, act := range state {
   355  			msu[act.Sym]++
   356  			k, arg := act.Kind()
   357  			if k == 'a' {
   358  				continue
   359  			}
   360  
   361  			if k == 'r' {
   362  				arg = -arg
   363  			}
   364  			minArg, maxArg = mathutil.Min(minArg, arg), mathutil.Max(maxArg, arg)
   365  		}
   366  	}
   367  	su := make(symsUsed, 0, len(msu))
   368  	for sym, used := range msu {
   369  		su = append(su, symUsed{sym, used})
   370  	}
   371  	sort.Sort(su)
   372  
   373  	// ----------------------------------------------------------- Prologue
   374  	f := strutil.IndentFormatter(out, "\t")
   375  	mustFormat(f, "// Code generated by goyacc DO NOT EDIT.\n\n")
   376  	mustFormat(f, "%s", injectImport(p.Prologue))
   377  	mustFormat(f, `
   378  type %[1]sSymType %i%s%u
   379  
   380  type %[1]sXError struct {
   381  	state, xsym int
   382  }
   383  `, *oPref, p.UnionSrc)
   384  
   385  	// ---------------------------------------------------------- Constants
   386  	nsyms := map[string]*y.Symbol{}
   387  	a := make([]string, 0, len(msu))
   388  	maxTokName := 0
   389  	for sym := range msu {
   390  		nm := sym.Name
   391  		if nm == "$default" || nm == "$end" || sym.IsTerminal && nm[0] != '\'' && sym.Value > 0 {
   392  			maxTokName = mathutil.Max(maxTokName, len(nm))
   393  			a = append(a, nm)
   394  		}
   395  		nsyms[nm] = sym
   396  	}
   397  	slices.Sort(a)
   398  	mustFormat(f, "\nconst (%i\n")
   399  	for _, v := range a {
   400  		nm := v
   401  		switch nm {
   402  		case "error":
   403  			nm = *oPref + "ErrCode"
   404  		case "$default":
   405  			nm = *oPref + "Default"
   406  		case "$end":
   407  			nm = *oPref + "EOFCode"
   408  		}
   409  		mustFormat(f, "%s%s = %d\n", nm, strings.Repeat(" ", maxTokName-len(nm)+1), nsyms[v].Value)
   410  	}
   411  	minArg-- // eg: [-13, 42], minArg -14 maps -13 to 1 so zero cell values -> empty.
   412  	mustFormat(f, "\n%sMaxDepth = 200\n", *oPref)
   413  	mustFormat(f, "%sTabOfs   = %d\n", *oPref, minArg)
   414  	mustFormat(f, "%u)")
   415  
   416  	// ---------------------------------------------------------- Variables
   417  	mustFormat(f, "\n\nvar (%i\n")
   418  
   419  	// Lex translation table
   420  	mustFormat(f, "%sXLAT = map[int]int{%i\n", *oPref)
   421  	xlat := make(map[int]int, len(su))
   422  	var errSym int
   423  	for i, v := range su {
   424  		if v.sym.Name == "error" {
   425  			errSym = i
   426  		}
   427  		xlat[v.sym.Value] = i
   428  		mustFormat(f, "%6d: %3d, // %s (%dx)\n", v.sym.Value, i, v.sym.Name, msu[v.sym])
   429  	}
   430  	mustFormat(f, "%u}\n")
   431  
   432  	// Symbol names
   433  	mustFormat(f, "\n%sSymNames = []string{%i\n", *oPref)
   434  	for _, v := range su {
   435  		mustFormat(f, "%q,\n", v.sym.Name)
   436  	}
   437  	mustFormat(f, "%u}\n")
   438  
   439  	// Reduction table
   440  	mustFormat(f, "\n%sReductions = []struct{xsym, components int}{%i\n", *oPref)
   441  	for _, rule := range p.Rules {
   442  		mustFormat(f, "{%d, %d},\n", xlat[rule.Sym.Value], len(rule.Components))
   443  	}
   444  	mustFormat(f, "%u}\n")
   445  
   446  	// XError table
   447  	mustFormat(f, "\n%[1]sXErrors = map[%[1]sXError]string{%i\n", *oPref)
   448  	for _, xerr := range p.XErrors {
   449  		state := xerr.Stack[len(xerr.Stack)-1]
   450  		xsym := -1
   451  		if xerr.Lookahead != nil {
   452  			xsym = xlat[xerr.Lookahead.Value]
   453  		}
   454  		mustFormat(f, "%[1]sXError{%d, %d}: \"%s\",\n", *oPref, state, xsym, xerr.Msg)
   455  	}
   456  	mustFormat(f, "%u}\n\n")
   457  
   458  	// Parse table
   459  	tbits := 32
   460  	switch n := mathutil.BitLen(maxArg - minArg + 1); {
   461  	case n < 8:
   462  		tbits = 8
   463  	case n < 16:
   464  		tbits = 16
   465  	}
   466  	mustFormat(f, "%sParseTab = [%d][]uint%d{%i\n", *oPref, len(p.Table), tbits)
   467  	nCells := 0
   468  	var tabRow sortutil.Uint64Slice
   469  	for si, state := range p.Table {
   470  		tabRow = tabRow[:0]
   471  		max := 0
   472  		for _, act := range state {
   473  			sym := act.Sym
   474  			xsym, ok := xlat[sym.Value]
   475  			if !ok {
   476  				panic("internal error 001")
   477  			}
   478  
   479  			max = mathutil.Max(max, xsym)
   480  			kind, arg := act.Kind()
   481  			switch kind {
   482  			case 'a':
   483  				arg = 0
   484  			case 'r':
   485  				arg *= -1
   486  			}
   487  			tabRow = append(tabRow, uint64(xsym)<<32|uint64(arg-minArg))
   488  		}
   489  		nCells += max
   490  		tabRow.Sort()
   491  		col := -1
   492  		if si%5 == 0 {
   493  			mustFormat(f, "// %d\n", si)
   494  		}
   495  		mustFormat(f, "{")
   496  		for i, v := range tabRow {
   497  			xsym := int(uint32(v >> 32))
   498  			arg := int(uint32(v))
   499  			if col+1 != xsym {
   500  				mustFormat(f, "%d: ", xsym)
   501  			}
   502  			switch {
   503  			case i == len(tabRow)-1:
   504  				mustFormat(f, "%d", arg)
   505  			default:
   506  				mustFormat(f, "%d, ", arg)
   507  			}
   508  			col = xsym
   509  		}
   510  		mustFormat(f, "},\n")
   511  	}
   512  	mustFormat(f, "%u}\n")
   513  	fmt.Fprintf(os.Stderr, "Parse table entries: %d of %d, x %d bits == %d bytes\n",
   514  		nCells, len(p.Table)*len(msu), tbits, nCells*tbits/8)
   515  	if n := p.ConflictsSR; n != 0 {
   516  		fmt.Fprintf(os.Stderr, "conflicts: %d shift/reduce\n", n)
   517  	}
   518  	if n := p.ConflictsRR; n != 0 {
   519  		fmt.Fprintf(os.Stderr, "conflicts: %d reduce/reduce\n", n)
   520  	}
   521  
   522  	mustFormat(f, `%u)
   523  
   524  var %[1]sDebug = 0
   525  
   526  type %[1]sLexer interface {
   527  	Lex(lval *%[1]sSymType) int
   528  	Errorf(format string, a ...interface{}) error
   529  	AppendError(err error)
   530  	AppendWarn(err error)
   531  	Errors() (warns []error, errs []error)
   532  }
   533  
   534  type %[1]sLexerEx interface {
   535  	%[1]sLexer
   536  	Reduced(rule, state int, lval *%[1]sSymType) bool
   537  }
   538  
   539  func %[1]sSymName(c int) (s string) {
   540  	x, ok := %[1]sXLAT[c]
   541  	if ok {
   542  		return %[1]sSymNames[x]
   543  	}
   544  
   545  	return __yyfmt__.Sprintf("%%d", c)
   546  }
   547  
   548  func %[1]slex1(yylex %[1]sLexer, lval *%[1]sSymType) (n int) {
   549  	n = yylex.Lex(lval)
   550  	if n <= 0 {
   551  		n = %[1]sEOFCode
   552  	}
   553  	if %[1]sDebug >= 3 {
   554  		__yyfmt__.Printf("\nlex %%s(%%#x %%d), %[4]s: %[3]s\n", %[1]sSymName(n), n, n, %[4]s)
   555  	}
   556  	return n
   557  }
   558  
   559  func %[1]sParse(yylex %[1]sLexer, parser *%[5]s) int {
   560  	const yyError = %[2]d
   561  
   562  	yyEx, _ := yylex.(%[1]sLexerEx)
   563  	var yyn int
   564  	parser.yylval = %[1]sSymType{}
   565  	yyS := parser.cache
   566  
   567  	Nerrs := 0   /* number of errors */
   568  	Errflag := 0 /* error recovery flag */
   569  	yyerrok := func() {
   570  		if %[1]sDebug >= 2 {
   571  			__yyfmt__.Printf("yyerrok()\n")
   572  		}
   573  		Errflag = 0
   574  	}
   575  	_ = yyerrok
   576  	yystate := 0
   577  	yychar := -1
   578  	var yyxchar int
   579  	var yyshift int
   580  	yyp := -1
   581  	goto yystack
   582  
   583  ret0:
   584  	return 0
   585  
   586  ret1:
   587  	return 1
   588  
   589  yystack:
   590  	/* put a state and value onto the stack */
   591  	yyp++
   592  	if yyp+1 >= len(yyS) {
   593  		nyys := make([]%[1]sSymType, len(yyS)*2)
   594  		copy(nyys, yyS)
   595  		yyS = nyys
   596  		parser.cache = yyS
   597  	}
   598  	parser.yyVAL = &yyS[yyp+1]
   599  	yyS[yyp].yys = yystate
   600  
   601  yynewstate:
   602  	if yychar < 0 {
   603  		yychar = %[1]slex1(yylex, &parser.yylval)
   604  		var ok bool
   605  		if yyxchar, ok = %[1]sXLAT[yychar]; !ok {
   606  			yyxchar = len(%[1]sSymNames) // > tab width
   607  		}
   608  	}
   609  	if %[1]sDebug >= 4 {
   610  		var a []int
   611  		for _, v := range yyS[:yyp+1] {
   612  			a = append(a, v.yys)
   613  		}
   614  		__yyfmt__.Printf("state stack %%v\n", a)
   615  	}
   616  	row := %[1]sParseTab[yystate]
   617  	yyn = 0
   618  	if yyxchar < len(row) {
   619  		if yyn = int(row[yyxchar]); yyn != 0 {
   620  			yyn += %[1]sTabOfs
   621  		}
   622  	}
   623  	switch {
   624  	case yyn > 0: // shift
   625  		yychar = -1
   626  		*parser.yyVAL = parser.yylval
   627  		yystate = yyn
   628  		yyshift = yyn
   629  		if %[1]sDebug >= 2 {
   630  			__yyfmt__.Printf("shift, and goto state %%d\n", yystate)
   631  		}
   632  		if Errflag > 0 {
   633  			Errflag--
   634  		}
   635  		goto yystack
   636  	case yyn < 0: // reduce
   637  	case yystate == 1: // accept
   638  		if %[1]sDebug >= 2 {
   639  			__yyfmt__.Println("accept")
   640  		}
   641  		goto ret0
   642  	}
   643  
   644  	if yyn == 0 {
   645  		/* error ... attempt to resume parsing */
   646  		switch Errflag {
   647  		case 0: /* brand new error */
   648  			if %[1]sDebug >= 1 {
   649  				__yyfmt__.Printf("no action for %%s in state %%d\n", %[1]sSymName(yychar), yystate)
   650  			}
   651  			msg, ok := %[1]sXErrors[%[1]sXError{yystate, yyxchar}]
   652  			if !ok {
   653  				msg, ok = %[1]sXErrors[%[1]sXError{yystate, -1}]
   654  			}
   655  			if !ok && yyshift != 0 {
   656  				msg, ok = %[1]sXErrors[%[1]sXError{yyshift, yyxchar}]
   657  			}
   658  			if !ok {
   659  				msg, ok = %[1]sXErrors[%[1]sXError{yyshift, -1}]
   660  			}
   661  			if !ok || msg == "" {
   662  				msg = "syntax error"
   663  			}
   664  			// ignore goyacc error message
   665  			yylex.AppendError(yylex.Errorf(""))
   666  			Nerrs++
   667  			fallthrough
   668  
   669  		case 1, 2: /* incompletely recovered error ... try again */
   670  			Errflag = 3
   671  
   672  			/* find a state where "error" is a legal shift action */
   673  			for yyp >= 0 {
   674  				row := %[1]sParseTab[yyS[yyp].yys]
   675  				if yyError < len(row) {
   676  					yyn = int(row[yyError])+%[1]sTabOfs
   677  					if yyn > 0 { // hit
   678  						if %[1]sDebug >= 2 {
   679  							__yyfmt__.Printf("error recovery found error shift in state %%d\n", yyS[yyp].yys)
   680  						}
   681  						yystate = yyn /* simulate a shift of "error" */
   682  						goto yystack
   683  					}
   684  				}
   685  
   686  				/* the current p has no shift on "error", pop stack */
   687  				if %[1]sDebug >= 2 {
   688  					__yyfmt__.Printf("error recovery pops state %%d\n", yyS[yyp].yys)
   689  				}
   690  				yyp--
   691  			}
   692  			/* there is no state on the stack with an error shift ... abort */
   693  			if %[1]sDebug >= 2 {
   694  				__yyfmt__.Printf("error recovery failed\n")
   695  			}
   696  			goto ret1
   697  
   698  		case 3: /* no shift yet; clobber input char */
   699  			if %[1]sDebug >= 2 {
   700  				__yyfmt__.Printf("error recovery discards %%s\n", %[1]sSymName(yychar))
   701  			}
   702  			if yychar == %[1]sEOFCode {
   703  				goto ret1
   704  			}
   705  
   706  			yychar = -1
   707  			goto yynewstate /* try again in the same state */
   708  		}
   709  	}
   710  
   711  	r := -yyn
   712  	x0 := %[1]sReductions[r]
   713  	x, n := x0.xsym, x0.components
   714  	yypt := yyp
   715  	_ = yypt // guard against "declared and not used"
   716  
   717  	yyp -= n
   718  	if yyp+1 >= len(yyS) {
   719  		nyys := make([]%[1]sSymType, len(yyS)*2)
   720  		copy(nyys, yyS)
   721  		yyS = nyys
   722  		parser.cache = yyS
   723  	}
   724  	parser.yyVAL = &yyS[yyp+1]
   725  
   726  	/* consult goto table to find next state */
   727  	exState := yystate
   728  	yystate = int(%[1]sParseTab[yyS[yyp].yys][x])+%[1]sTabOfs
   729  	/* reduction by production r */
   730  	if %[1]sDebug >= 2 {
   731  		__yyfmt__.Printf("reduce using rule %%v (%%s), and goto state %%d\n", r, %[1]sSymNames[x], yystate)
   732  	}
   733  
   734  	switch r {%i
   735  `,
   736  		*oPref, errSym, *oDlvalf, *oDlval, *oParserType)
   737  	for r, rule := range p.Rules {
   738  		if rule.Action == nil {
   739  			continue
   740  		}
   741  
   742  		action := rule.Action.Values
   743  		if len(action) == 0 {
   744  			continue
   745  		}
   746  
   747  		if len(action) == 1 {
   748  			part := action[0]
   749  			if part.Type == parser.ActionValueGo {
   750  				src := part.Src
   751  				src = src[1 : len(src)-1] // Remove lead '{' and trail '}'
   752  				if strings.TrimSpace(src) == "" {
   753  					continue
   754  				}
   755  			}
   756  		}
   757  
   758  		components := rule.Components
   759  		typ := rule.Sym.Type
   760  		max := len(components)
   761  		if p1 := rule.Parent; p1 != nil {
   762  			max = rule.MaxParentDlr
   763  			components = p1.Components
   764  		}
   765  		mustFormat(f, "case %d: ", r)
   766  		for _, part := range action {
   767  			num := part.Num
   768  			switch part.Type {
   769  			case parser.ActionValueGo:
   770  				mustFormat(f, "%s", part.Src)
   771  			case parser.ActionValueDlrDlr:
   772  				mustFormat(f, "parser.yyVAL.%s", typ)
   773  				if typ == "" {
   774  					panic("internal error 002")
   775  				}
   776  			case parser.ActionValueDlrNum:
   777  				typ := p.Syms[components[num-1]].Type
   778  				if typ == "" {
   779  					panic("internal error 003")
   780  				}
   781  				mustFormat(f, "yyS[yypt-%d].%s", max-num, typ)
   782  			case parser.ActionValueDlrTagDlr:
   783  				mustFormat(f, "parser.yyVAL.%s", part.Tag)
   784  			case parser.ActionValueDlrTagNum:
   785  				mustFormat(f, "yyS[yypt-%d].%s", max-num, part.Tag)
   786  			}
   787  		}
   788  		mustFormat(f, "\n")
   789  	}
   790  	mustFormat(f, `%u
   791  	}
   792  
   793  	if !parser.lexer.skipPositionRecording {
   794  		%[1]sSetOffset(parser.yyVAL, parser.yyVAL.offset)
   795  	}
   796  
   797  	if yyEx != nil && yyEx.Reduced(r, exState, parser.yyVAL) {
   798  		return -1
   799  	}
   800  	goto yystack /* stack new state and value */
   801  }
   802  
   803  %[2]s
   804  `, *oPref, p.Tail)
   805  	_ = oNoLines //TODO Ignored for now
   806  	return nil
   807  }
   808  
   809  func injectImport(src string) string {
   810  	const inj = `
   811  
   812  import __yyfmt__ "fmt"
   813  `
   814  	fset := token.NewFileSet()
   815  	file := fset.AddFile("", -1, len(src))
   816  	var s scanner.Scanner
   817  	s.Init(
   818  		file,
   819  		[]byte(src),
   820  		nil,
   821  		scanner.ScanComments,
   822  	)
   823  	for {
   824  		switch _, tok, _ := s.Scan(); tok {
   825  		case token.EOF:
   826  			return inj + src
   827  		case token.PACKAGE:
   828  			s.Scan() // ident
   829  			pos, _, _ := s.Scan()
   830  			ofs := file.Offset(pos)
   831  			return src[:ofs] + inj + src[ofs:]
   832  		}
   833  	}
   834  }
   835  
   836  func mustFormat(f strutil.Formatter, format string, args ...interface{}) {
   837  	_, err := f.Format(format, args...)
   838  	if err != nil {
   839  		log.Fatalf("format error %v", err)
   840  	}
   841  }