github.com/vescale/zgraph@v0.0.0-20230410094002-959c02d50f95/parser/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 "io/ioutil" 136 "log" 137 "os" 138 "runtime" 139 "sort" 140 "strings" 141 142 "github.com/cznic/mathutil" 143 "github.com/cznic/sortutil" 144 "github.com/cznic/strutil" 145 "golang.org/x/exp/slices" 146 parser "modernc.org/parser/yacc" 147 "modernc.org/y" 148 ) 149 150 var ( 151 //oNoDefault = flag.Bool("nodefault", false, "disable generating $default actions") 152 oClosures = flag.Bool("c", false, "report state closures") 153 oReducible = flag.Bool("cr", false, "check all states are reducible") 154 oDlval = flag.String("dlval", "lval", "debug value (runtime yyDebug >= 3)") 155 oDlvalf = flag.String("dlvalf", "%+v", "debug format of -dlval (runtime yyDebug >= 3)") 156 oLA = flag.Bool("la", false, "report all lookahead sets") 157 oNoLines = flag.Bool("l", false, "disable line directives (for compatibility ony - ignored)") 158 oOut = flag.String("o", "y.go", "parser output") 159 oPref = flag.String("p", "yy", "name prefix to use in generated code") 160 oReport = flag.String("v", "y.output", "create grammar report") 161 oResolved = flag.Bool("ex", false, "explain how were conflicts resolved") 162 oXErrors = flag.String("xe", "", "generate eXtra errors from examples source file") 163 oXErrorsGen = flag.String("xegen", "", "generate error from examples source file automatically from the grammar") 164 oFormat = flag.Bool("fmt", false, "format the yacc file") 165 oFormatOut = flag.String("fmtout", "golden.y", "yacc formatter output") 166 oParserType = flag.String("t", "Parser", "name of the parser in the generated yyParse() function") 167 ) 168 169 func main() { 170 log.SetFlags(0) 171 172 defer func() { 173 _, file, line, ok := runtime.Caller(2) 174 if e := recover(); e != nil { 175 switch { 176 case ok: 177 log.Fatalf("%s:%d: panic: %v", file, line, e) 178 default: 179 log.Fatalf("panic: %v", e) 180 } 181 } 182 }() 183 184 flag.Parse() 185 var in string 186 switch flag.NArg() { 187 case 0: 188 in = os.Stdin.Name() 189 case 1: 190 in = flag.Arg(0) 191 default: 192 log.Fatal("expected at most one non flag argument") 193 } 194 195 if *oFormat { 196 if err := Format(in, *oFormatOut); err != nil { 197 log.Fatal(err) 198 } 199 return 200 } 201 202 if err := main1(in); err != nil { 203 switch x := err.(type) { 204 case scanner.ErrorList: 205 for _, v := range x { 206 fmt.Fprintf(os.Stderr, "%v\n", v) 207 } 208 os.Exit(1) 209 default: 210 log.Fatal(err) 211 } 212 } 213 } 214 215 type symUsed struct { 216 sym *y.Symbol 217 used int 218 } 219 220 type symsUsed []symUsed 221 222 func (s symsUsed) Len() int { return len(s) } 223 func (s symsUsed) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 224 225 func (s symsUsed) Less(i, j int) bool { 226 if s[i].used > s[j].used { 227 return true 228 } 229 230 if s[i].used < s[j].used { 231 return false 232 } 233 234 caseFoldedCompare := strings.Compare(strings.ToLower(s[i].sym.Name), strings.ToLower(s[j].sym.Name)) 235 if caseFoldedCompare < 0 { 236 return true 237 } 238 if caseFoldedCompare > 0 { 239 return false 240 } 241 242 return s[i].sym.Name < s[j].sym.Name 243 } 244 245 func main1(in string) (err error) { 246 var out io.Writer 247 if nm := *oOut; nm != "" { 248 var f *os.File 249 var e error 250 if f, err = os.Create(nm); err != nil { 251 return err 252 } 253 254 defer func() { 255 if e1 := f.Close(); e1 != nil && err == nil { 256 err = e1 257 } 258 }() 259 w := bufio.NewWriter(f) 260 defer func() { 261 if e1 := w.Flush(); e1 != nil && err == nil { 262 err = e1 263 } 264 }() 265 buf := bytes.NewBuffer(nil) 266 out = buf 267 defer func() { 268 var dest []byte 269 if dest, e = format.Source(buf.Bytes()); e != nil { 270 dest = buf.Bytes() 271 } 272 273 if _, e = w.Write(dest); e != nil && err == nil { 274 err = e 275 } 276 }() 277 } 278 279 var rep io.Writer 280 if nm := *oReport; nm != "" { 281 f, err1 := os.Create(nm) 282 if err1 != nil { 283 return err1 284 } 285 286 defer func() { 287 if e := f.Close(); e != nil && err == nil { 288 err = e 289 } 290 }() 291 w := bufio.NewWriter(f) 292 defer func() { 293 if e := w.Flush(); e != nil && err == nil { 294 err = e 295 } 296 }() 297 rep = w 298 } 299 300 var xerrors []byte 301 if nm := *oXErrors; nm != "" { 302 b, err1 := ioutil.ReadFile(nm) 303 if err1 != nil { 304 return err1 305 } 306 307 xerrors = b 308 } 309 310 p, err := y.ProcessFile(token.NewFileSet(), in, &y.Options{ 311 //NoDefault: *oNoDefault, 312 AllowConflicts: false, 313 Closures: *oClosures, 314 LA: *oLA, 315 Reducible: *oReducible, 316 Report: rep, 317 Resolved: *oResolved, 318 XErrorsName: *oXErrors, 319 XErrorsSrc: xerrors, 320 }) 321 if err != nil { 322 return err 323 } 324 325 if fn := *oXErrorsGen; fn != "" { 326 f, err := os.OpenFile(fn, os.O_RDWR|os.O_CREATE, 0600) 327 if err != nil { 328 return err 329 } 330 331 b := bufio.NewWriter(f) 332 if err := p.SkeletonXErrors(b); err != nil { 333 return err 334 } 335 336 if err := b.Flush(); err != nil { 337 return err 338 } 339 340 if err := f.Close(); err != nil { 341 return err 342 } 343 } 344 345 msu := make(map[*y.Symbol]int, len(p.Syms)) // sym -> usage 346 for nm, sym := range p.Syms { 347 if nm == "" || nm == "ε" || nm == "$accept" || nm == "#" { 348 continue 349 } 350 351 msu[sym] = 0 352 } 353 var minArg, maxArg int 354 for _, state := range p.Table { 355 for _, act := range state { 356 msu[act.Sym]++ 357 k, arg := act.Kind() 358 if k == 'a' { 359 continue 360 } 361 362 if k == 'r' { 363 arg = -arg 364 } 365 minArg, maxArg = mathutil.Min(minArg, arg), mathutil.Max(maxArg, arg) 366 } 367 } 368 su := make(symsUsed, 0, len(msu)) 369 for sym, used := range msu { 370 su = append(su, symUsed{sym, used}) 371 } 372 sort.Sort(su) 373 374 // ----------------------------------------------------------- Prologue 375 f := strutil.IndentFormatter(out, "\t") 376 mustFormat(f, "// Code generated by goyacc DO NOT EDIT.\n\n") 377 mustFormat(f, "%s", injectImport(p.Prologue)) 378 mustFormat(f, ` 379 type %[1]sSymType %i%s%u 380 381 type %[1]sXError struct { 382 state, xsym int 383 } 384 `, *oPref, p.UnionSrc) 385 386 // ---------------------------------------------------------- Constants 387 nsyms := map[string]*y.Symbol{} 388 a := make([]string, 0, len(msu)) 389 maxTokName := 0 390 for sym := range msu { 391 nm := sym.Name 392 if nm == "$default" || nm == "$end" || sym.IsTerminal && nm[0] != '\'' && sym.Value > 0 { 393 maxTokName = mathutil.Max(maxTokName, len(nm)) 394 a = append(a, nm) 395 } 396 nsyms[nm] = sym 397 } 398 slices.Sort(a) 399 mustFormat(f, "\nconst (%i\n") 400 for _, v := range a { 401 nm := v 402 switch nm { 403 case "error": 404 nm = *oPref + "ErrCode" 405 case "$default": 406 nm = *oPref + "Default" 407 case "$end": 408 nm = *oPref + "EOFCode" 409 } 410 mustFormat(f, "%s%s = %d\n", nm, strings.Repeat(" ", maxTokName-len(nm)+1), nsyms[v].Value) 411 } 412 minArg-- // eg: [-13, 42], minArg -14 maps -13 to 1 so zero cell values -> empty. 413 mustFormat(f, "\n%sMaxDepth = 200\n", *oPref) 414 mustFormat(f, "%sTabOfs = %d\n", *oPref, minArg) 415 mustFormat(f, "%u)") 416 417 // ---------------------------------------------------------- Variables 418 mustFormat(f, "\n\nvar (%i\n") 419 420 // Lex translation table 421 mustFormat(f, "%sXLAT = map[int]int{%i\n", *oPref) 422 xlat := make(map[int]int, len(su)) 423 var errSym int 424 for i, v := range su { 425 if v.sym.Name == "error" { 426 errSym = i 427 } 428 xlat[v.sym.Value] = i 429 mustFormat(f, "%6d: %3d, // %s (%dx)\n", v.sym.Value, i, v.sym.Name, msu[v.sym]) 430 } 431 mustFormat(f, "%u}\n") 432 433 // Symbol names 434 mustFormat(f, "\n%sSymNames = []string{%i\n", *oPref) 435 for _, v := range su { 436 mustFormat(f, "%q,\n", v.sym.Name) 437 } 438 mustFormat(f, "%u}\n") 439 440 // Reduction table 441 mustFormat(f, "\n%sReductions = []struct{xsym, components int}{%i\n", *oPref) 442 for _, rule := range p.Rules { 443 mustFormat(f, "{%d, %d},\n", xlat[rule.Sym.Value], len(rule.Components)) 444 } 445 mustFormat(f, "%u}\n") 446 447 // XError table 448 mustFormat(f, "\n%[1]sXErrors = map[%[1]sXError]string{%i\n", *oPref) 449 for _, xerr := range p.XErrors { 450 state := xerr.Stack[len(xerr.Stack)-1] 451 xsym := -1 452 if xerr.Lookahead != nil { 453 xsym = xlat[xerr.Lookahead.Value] 454 } 455 mustFormat(f, "%[1]sXError{%d, %d}: \"%s\",\n", *oPref, state, xsym, xerr.Msg) 456 } 457 mustFormat(f, "%u}\n\n") 458 459 // Parse table 460 tbits := 32 461 switch n := mathutil.BitLen(maxArg - minArg + 1); { 462 case n < 8: 463 tbits = 8 464 case n < 16: 465 tbits = 16 466 } 467 mustFormat(f, "%sParseTab = [%d][]uint%d{%i\n", *oPref, len(p.Table), tbits) 468 nCells := 0 469 var tabRow sortutil.Uint64Slice 470 for si, state := range p.Table { 471 tabRow = tabRow[:0] 472 max := 0 473 for _, act := range state { 474 sym := act.Sym 475 xsym, ok := xlat[sym.Value] 476 if !ok { 477 panic("internal error 001") 478 } 479 480 max = mathutil.Max(max, xsym) 481 kind, arg := act.Kind() 482 switch kind { 483 case 'a': 484 arg = 0 485 case 'r': 486 arg *= -1 487 } 488 tabRow = append(tabRow, uint64(xsym)<<32|uint64(arg-minArg)) 489 } 490 nCells += max 491 tabRow.Sort() 492 col := -1 493 if si%5 == 0 { 494 mustFormat(f, "// %d\n", si) 495 } 496 mustFormat(f, "{") 497 for i, v := range tabRow { 498 xsym := int(uint32(v >> 32)) 499 arg := int(uint32(v)) 500 if col+1 != xsym { 501 mustFormat(f, "%d: ", xsym) 502 } 503 switch { 504 case i == len(tabRow)-1: 505 mustFormat(f, "%d", arg) 506 default: 507 mustFormat(f, "%d, ", arg) 508 } 509 col = xsym 510 } 511 mustFormat(f, "},\n") 512 } 513 mustFormat(f, "%u}\n") 514 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) 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 }