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 }