github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/qiuyesuifeng/goyacc/main.go (about)

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