├── README.md ├── LICENSE ├── doc.go └── yacc.go /README.md: -------------------------------------------------------------------------------- 1 | # Yacc 2 | 3 | This is a fork of the go yacc tool with minor tweaks to allow larger 4 | grammar sizes. 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 The Go 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 | /* 6 | 7 | Yacc is a version of yacc for Go. 8 | It is written in Go and generates parsers written in Go. 9 | 10 | Usage: 11 | 12 | go tool yacc args... 13 | 14 | It is largely transliterated from the Inferno version written in Limbo 15 | which in turn was largely transliterated from the Plan 9 version 16 | written in C and documented at 17 | 18 | https://9p.io/magic/man2html/1/yacc 19 | 20 | Adepts of the original yacc will have no trouble adapting to this 21 | form of the tool. 22 | 23 | The directory $GOROOT/src/cmd/yacc/testdata/expr is a yacc program 24 | for a very simple expression parser. See expr.y and main.go in that 25 | directory for examples of how to write and build yacc programs. 26 | 27 | The generated parser is reentrant. The parsing function yyParse expects 28 | to be given an argument that conforms to the following interface: 29 | 30 | type yyLexer interface { 31 | Lex(lval *yySymType) int 32 | Error(e string) 33 | } 34 | 35 | Lex should return the token identifier, and place other token 36 | information in lval (which replaces the usual yylval). 37 | Error is equivalent to yyerror in the original yacc. 38 | 39 | Code inside the grammar actions may refer to the variable yylex, 40 | which holds the yyLexer passed to yyParse. 41 | 42 | Clients that need to understand more about the parser state can 43 | create the parser separately from invoking it. The function yyNewParser 44 | returns a yyParser conforming to the following interface: 45 | 46 | type yyParser interface { 47 | Parse(yyLex) int 48 | Lookahead() int 49 | } 50 | 51 | Parse runs the parser; the top-level call yyParse(yylex) is equivalent 52 | to yyNewParser().Parse(yylex). 53 | 54 | Lookahead can be called during grammar actions to read (but not consume) 55 | the value of the current lookahead token, as returned by yylex.Lex. 56 | If there is no current lookahead token (because the parser has not called Lex 57 | or has consumed the token returned by the most recent call to Lex), 58 | Lookahead returns -1. Calling Lookahead is equivalent to reading 59 | yychar from within in a grammar action. 60 | 61 | Multiple grammars compiled into a single program should be placed in 62 | distinct packages. If that is impossible, the "-p prefix" flag to 63 | yacc sets the prefix, by default yy, that begins the names of 64 | symbols, including types, the parser, and the lexer, generated and 65 | referenced by yacc's generated code. Setting it to distinct values 66 | allows multiple grammars to be placed in a single package. 67 | 68 | */ 69 | package main 70 | -------------------------------------------------------------------------------- /yacc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Derived from Inferno's utils/iyacc/yacc.c 3 | http://code.google.com/p/inferno-os/source/browse/utils/iyacc/yacc.c 4 | 5 | This copyright NOTICE applies to all files in this directory and 6 | subdirectories, unless another copyright notice appears in a given 7 | file or subdirectory. If you take substantial code from this software to use in 8 | other programs, you must somehow include with it an appropriate 9 | copyright notice that includes the copyright notice and the other 10 | notices below. It is fine (and often tidier) to do that in a separate 11 | file such as NOTICE, LICENCE or COPYING. 12 | 13 | Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. 14 | Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) 15 | Portions Copyright © 1997-1999 Vita Nuova Limited 16 | Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) 17 | Portions Copyright © 2004,2006 Bruce Ellis 18 | Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) 19 | Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others 20 | Portions Copyright © 2009 The Go Authors. All rights reserved. 21 | 22 | Permission is hereby granted, free of charge, to any person obtaining a copy 23 | of this software and associated documentation files (the "Software"), to deal 24 | in the Software without restriction, including without limitation the rights 25 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 26 | copies of the Software, and to permit persons to whom the Software is 27 | furnished to do so, subject to the following conditions: 28 | 29 | The above copyright notice and this permission notice shall be included in 30 | all copies or substantial portions of the Software. 31 | 32 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 33 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 34 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 35 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 36 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 37 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 38 | THE SOFTWARE. 39 | */ 40 | 41 | package main 42 | 43 | // yacc 44 | // major difference is lack of stem ("y" variable) 45 | // 46 | 47 | import ( 48 | "bufio" 49 | "bytes" 50 | "flag" 51 | "fmt" 52 | "go/format" 53 | "io/ioutil" 54 | "os" 55 | "strconv" 56 | "strings" 57 | "unicode" 58 | ) 59 | 60 | // the following are adjustable 61 | // according to memory size 62 | const ( 63 | ACTSIZE = 30000 64 | NSTATES = 2000 65 | TEMPSIZE = 2000 66 | 67 | SYMINC = 50 // increase for non-term or term 68 | RULEINC = 50 // increase for max rule length prodptr[i] 69 | PRODINC = 100 // increase for productions prodptr 70 | WSETINC = 50 // increase for working sets wsets 71 | STATEINC = 200 // increase for states statemem 72 | 73 | NAMESIZE = 50 74 | ISIZE = 400 75 | 76 | PRIVATE = 0xE000 // unicode private use 77 | 78 | // relationships which must hold: 79 | // TEMPSIZE >= NTERMS + NNONTERM + 1; 80 | // TEMPSIZE >= NSTATES; 81 | // 82 | 83 | NTBASE = 010000 84 | ERRCODE = 8190 85 | ACCEPTCODE = 8191 86 | YYLEXUNK = 3 87 | TOKSTART = 4 //index of first defined token 88 | ) 89 | 90 | // no, left, right, binary assoc. 91 | const ( 92 | NOASC = iota 93 | LASC 94 | RASC 95 | BASC 96 | ) 97 | 98 | // flags for state generation 99 | const ( 100 | DONE = iota 101 | MUSTDO 102 | MUSTLOOKAHEAD 103 | ) 104 | 105 | // flags for a rule having an action, and being reduced 106 | const ( 107 | ACTFLAG = 1 << (iota + 2) 108 | REDFLAG 109 | ) 110 | 111 | // output parser flags 112 | const yyFlag = -1000 113 | 114 | // parse tokens 115 | const ( 116 | IDENTIFIER = PRIVATE + iota 117 | MARK 118 | TERM 119 | LEFT 120 | RIGHT 121 | BINARY 122 | PREC 123 | LCURLY 124 | IDENTCOLON 125 | NUMBER 126 | START 127 | TYPEDEF 128 | TYPENAME 129 | UNION 130 | ERROR 131 | ) 132 | 133 | const ENDFILE = 0 134 | const EMPTY = 1 135 | const WHOKNOWS = 0 136 | const OK = 1 137 | const NOMORE = -1000 138 | 139 | // macros for getting associativity and precedence levels 140 | func ASSOC(i int) int { return i & 3 } 141 | 142 | func PLEVEL(i int) int { return (i >> 4) & 077 } 143 | 144 | func TYPE(i int) int { return (i >> 10) & 077 } 145 | 146 | // macros for setting associativity and precedence levels 147 | func SETASC(i, j int) int { return i | j } 148 | 149 | func SETPLEV(i, j int) int { return i | (j << 4) } 150 | 151 | func SETTYPE(i, j int) int { return i | (j << 10) } 152 | 153 | // I/O descriptors 154 | var finput *bufio.Reader // input file 155 | var stderr *bufio.Writer 156 | var ftable *bufio.Writer // y.go file 157 | var fcode = &bytes.Buffer{} // saved code 158 | var foutput *bufio.Writer // y.output file 159 | 160 | var fmtImported bool // output file has recorded an import of "fmt" 161 | 162 | var oflag string // -o [y.go] - y.go file 163 | var vflag string // -v [y.output] - y.output file 164 | var lflag bool // -l - disable line directives 165 | var prefix string // name prefix for identifiers, default yy 166 | 167 | func init() { 168 | flag.StringVar(&oflag, "o", "y.go", "parser output") 169 | flag.StringVar(&prefix, "p", "yy", "name prefix to use in generated code") 170 | flag.StringVar(&vflag, "v", "y.output", "create parsing tables") 171 | flag.BoolVar(&lflag, "l", false, "disable line directives") 172 | } 173 | 174 | var initialstacksize = 16 175 | 176 | // communication variables between various I/O routines 177 | var infile string // input file name 178 | var numbval int // value of an input number 179 | var tokname string // input token name, slop for runes and 0 180 | var tokflag = false 181 | 182 | // structure declarations 183 | type Lkset []int 184 | 185 | type Pitem struct { 186 | prod []int 187 | off int // offset within the production 188 | first int // first term or non-term in item 189 | prodno int // production number for sorting 190 | } 191 | 192 | type Item struct { 193 | pitem Pitem 194 | look Lkset 195 | } 196 | 197 | type Symb struct { 198 | name string 199 | noconst bool 200 | value int 201 | } 202 | 203 | type Wset struct { 204 | pitem Pitem 205 | flag int 206 | ws Lkset 207 | } 208 | 209 | // storage of types 210 | var ntypes int // number of types defined 211 | var typeset = map[int]string{} // pointers to type tags 212 | 213 | // token information 214 | 215 | var ntokens = 0 // number of tokens 216 | var tokset []Symb 217 | var toklev []int // vector with the precedence of the terminals 218 | 219 | // nonterminal information 220 | 221 | var nnonter = -1 // the number of nonterminals 222 | var nontrst []Symb 223 | var start int // start symbol 224 | 225 | // state information 226 | 227 | var nstate = 0 // number of states 228 | var pstate = make([]int, NSTATES+2) // index into statemem to the descriptions of the states 229 | var statemem []Item 230 | var tystate = make([]int, NSTATES) // contains type information about the states 231 | var tstates []int // states generated by terminal gotos 232 | var ntstates []int // states generated by nonterminal gotos 233 | var mstates = make([]int, NSTATES) // chain of overflows of term/nonterm generation lists 234 | var lastred int // number of last reduction of a state 235 | var defact = make([]int, NSTATES) // default actions of states 236 | 237 | // lookahead set information 238 | 239 | var nolook = 0 // flag to turn off lookahead computations 240 | var tbitset = 0 // size of lookahead sets 241 | var clset Lkset // temporary storage for lookahead computations 242 | 243 | // working set information 244 | 245 | var wsets []Wset 246 | var cwp int 247 | 248 | // storage for action table 249 | 250 | var amem []int // action table storage 251 | var memp int // next free action table position 252 | var indgo = make([]int, NSTATES) // index to the stored goto table 253 | 254 | // temporary vector, indexable by states, terms, or ntokens 255 | 256 | var temp1 = make([]int, TEMPSIZE) // temporary storage, indexed by terms + ntokens or states 257 | var lineno = 1 // current input line number 258 | var fatfl = 1 // if on, error is fatal 259 | var nerrors = 0 // number of errors 260 | 261 | // assigned token type values 262 | 263 | var extval = 0 264 | 265 | // grammar rule information 266 | 267 | var nprod = 1 // number of productions 268 | var prdptr [][]int // pointers to descriptions of productions 269 | var levprd []int // precedence levels for the productions 270 | var rlines []int // line number for this rule 271 | 272 | // statistics collection variables 273 | 274 | var zzgoent = 0 275 | var zzgobest = 0 276 | var zzacent = 0 277 | var zzexcp = 0 278 | var zzclose = 0 279 | var zzrrconf = 0 280 | var zzsrconf = 0 281 | var zzstate = 0 282 | 283 | // optimizer arrays 284 | 285 | var yypgo [][]int 286 | var optst [][]int 287 | var ggreed []int 288 | var pgo []int 289 | 290 | var maxspr int // maximum spread of any entry 291 | var maxoff int // maximum offset into a array 292 | var maxa int 293 | 294 | // storage for information about the nonterminals 295 | 296 | var pres [][][]int // vector of pointers to productions yielding each nonterminal 297 | var pfirst []Lkset 298 | var pempty []int // vector of nonterminals nontrivially deriving e 299 | 300 | // random stuff picked out from between functions 301 | 302 | var indebug = 0 // debugging flag for cpfir 303 | var pidebug = 0 // debugging flag for putitem 304 | var gsdebug = 0 // debugging flag for stagen 305 | var cldebug = 0 // debugging flag for closure 306 | var pkdebug = 0 // debugging flag for apack 307 | var g2debug = 0 // debugging for go2gen 308 | var adb = 0 // debugging for callopt 309 | 310 | type Resrv struct { 311 | name string 312 | value int 313 | } 314 | 315 | var resrv = []Resrv{ 316 | {"binary", BINARY}, 317 | {"left", LEFT}, 318 | {"nonassoc", BINARY}, 319 | {"prec", PREC}, 320 | {"right", RIGHT}, 321 | {"start", START}, 322 | {"term", TERM}, 323 | {"token", TERM}, 324 | {"type", TYPEDEF}, 325 | {"union", UNION}, 326 | {"struct", UNION}, 327 | {"error", ERROR}, 328 | } 329 | 330 | type Error struct { 331 | lineno int 332 | tokens []string 333 | msg string 334 | } 335 | 336 | var errors []Error 337 | 338 | type Row struct { 339 | actions []int 340 | defaultAction int 341 | } 342 | 343 | var stateTable []Row 344 | 345 | var zznewstate = 0 346 | 347 | const EOF = -1 348 | 349 | func main() { 350 | 351 | setup() // initialize and read productions 352 | 353 | tbitset = (ntokens + 32) / 32 354 | cpres() // make table of which productions yield a given nonterminal 355 | cempty() // make a table of which nonterminals can match the empty string 356 | cpfir() // make a table of firsts of nonterminals 357 | 358 | stagen() // generate the states 359 | 360 | yypgo = make([][]int, nnonter+1) 361 | optst = make([][]int, nstate) 362 | output() // write the states and the tables 363 | go2out() 364 | 365 | hideprod() 366 | summary() 367 | 368 | callopt() 369 | 370 | others() 371 | 372 | exit(0) 373 | } 374 | 375 | func setup() { 376 | var j, ty int 377 | 378 | stderr = bufio.NewWriter(os.Stderr) 379 | foutput = nil 380 | 381 | flag.Parse() 382 | if flag.NArg() != 1 { 383 | usage() 384 | } 385 | if initialstacksize < 1 { 386 | // never set so cannot happen 387 | fmt.Fprintf(stderr, "yacc: stack size too small\n") 388 | usage() 389 | } 390 | yaccpar = strings.Replace(yaccpartext, "$$", prefix, -1) 391 | openup() 392 | 393 | defin(0, "$end") 394 | extval = PRIVATE // tokens start in unicode 'private use' 395 | defin(0, "error") 396 | defin(1, "$accept") 397 | defin(0, "$unk") 398 | i := 0 399 | 400 | t := gettok() 401 | 402 | outer: 403 | for { 404 | switch t { 405 | default: 406 | errorf("syntax error tok=%v", t-PRIVATE) 407 | 408 | case MARK, ENDFILE: 409 | break outer 410 | 411 | case ';': 412 | 413 | case START: 414 | t = gettok() 415 | if t != IDENTIFIER { 416 | errorf("bad %%start construction") 417 | } 418 | start = chfind(1, tokname) 419 | 420 | case ERROR: 421 | lno := lineno 422 | var tokens []string 423 | for { 424 | t := gettok() 425 | if t == ':' { 426 | break 427 | } 428 | if t != IDENTIFIER && t != IDENTCOLON { 429 | errorf("bad syntax in %%error") 430 | } 431 | tokens = append(tokens, tokname) 432 | if t == IDENTCOLON { 433 | break 434 | } 435 | } 436 | if gettok() != IDENTIFIER { 437 | errorf("bad syntax in %%error") 438 | } 439 | errors = append(errors, Error{lno, tokens, tokname}) 440 | 441 | case TYPEDEF: 442 | t = gettok() 443 | if t != TYPENAME { 444 | errorf("bad syntax in %%type") 445 | } 446 | ty = numbval 447 | for { 448 | t = gettok() 449 | switch t { 450 | case IDENTIFIER: 451 | t = chfind(1, tokname) 452 | if t < NTBASE { 453 | j = TYPE(toklev[t]) 454 | if j != 0 && j != ty { 455 | errorf("type redeclaration of token %s", 456 | tokset[t].name) 457 | } else { 458 | toklev[t] = SETTYPE(toklev[t], ty) 459 | } 460 | } else { 461 | j = nontrst[t-NTBASE].value 462 | if j != 0 && j != ty { 463 | errorf("type redeclaration of nonterminal %v", 464 | nontrst[t-NTBASE].name) 465 | } else { 466 | nontrst[t-NTBASE].value = ty 467 | } 468 | } 469 | continue 470 | 471 | case ',': 472 | continue 473 | } 474 | break 475 | } 476 | continue 477 | 478 | case UNION: 479 | cpyunion() 480 | 481 | case LEFT, BINARY, RIGHT, TERM: 482 | // nonzero means new prec. and assoc. 483 | lev := t - TERM 484 | if lev != 0 { 485 | i++ 486 | } 487 | ty = 0 488 | 489 | // get identifiers so defined 490 | t = gettok() 491 | 492 | // there is a type defined 493 | if t == TYPENAME { 494 | ty = numbval 495 | t = gettok() 496 | } 497 | for { 498 | switch t { 499 | case ',': 500 | t = gettok() 501 | continue 502 | 503 | case ';': 504 | break 505 | 506 | case IDENTIFIER: 507 | j = chfind(0, tokname) 508 | if j >= NTBASE { 509 | errorf("%v defined earlier as nonterminal", tokname) 510 | } 511 | if lev != 0 { 512 | if ASSOC(toklev[j]) != 0 { 513 | errorf("redeclaration of precedence of %v", tokname) 514 | } 515 | toklev[j] = SETASC(toklev[j], lev) 516 | toklev[j] = SETPLEV(toklev[j], i) 517 | } 518 | if ty != 0 { 519 | if TYPE(toklev[j]) != 0 { 520 | errorf("redeclaration of type of %v", tokname) 521 | } 522 | toklev[j] = SETTYPE(toklev[j], ty) 523 | } 524 | t = gettok() 525 | if t == NUMBER { 526 | tokset[j].value = numbval 527 | t = gettok() 528 | } 529 | 530 | continue 531 | } 532 | break 533 | } 534 | continue 535 | 536 | case LCURLY: 537 | cpycode() 538 | } 539 | t = gettok() 540 | } 541 | 542 | if t == ENDFILE { 543 | errorf("unexpected EOF before %%") 544 | } 545 | 546 | fmt.Fprintf(fcode, "switch %snt {\n", prefix) 547 | 548 | moreprod() 549 | prdptr[0] = []int{NTBASE, start, 1, 0} 550 | 551 | nprod = 1 552 | curprod := make([]int, RULEINC) 553 | t = gettok() 554 | if t != IDENTCOLON { 555 | errorf("bad syntax on first rule") 556 | } 557 | 558 | if start == 0 { 559 | prdptr[0][1] = chfind(1, tokname) 560 | } 561 | 562 | // read rules 563 | // put into prdptr array in the format 564 | // target 565 | // followed by id's of terminals and non-terminals 566 | // followed by -nprod 567 | 568 | for t != MARK && t != ENDFILE { 569 | mem := 0 570 | 571 | // process a rule 572 | rlines[nprod] = lineno 573 | ruleline := lineno 574 | if t == '|' { 575 | curprod[mem] = prdptr[nprod-1][0] 576 | mem++ 577 | } else if t == IDENTCOLON { 578 | curprod[mem] = chfind(1, tokname) 579 | if curprod[mem] < NTBASE { 580 | lerrorf(ruleline, "token illegal on LHS of grammar rule") 581 | } 582 | mem++ 583 | } else { 584 | lerrorf(ruleline, "illegal rule: missing semicolon or | ?") 585 | } 586 | 587 | // read rule body 588 | t = gettok() 589 | for { 590 | for t == IDENTIFIER { 591 | curprod[mem] = chfind(1, tokname) 592 | if curprod[mem] < NTBASE { 593 | levprd[nprod] = toklev[curprod[mem]] 594 | } 595 | mem++ 596 | if mem >= len(curprod) { 597 | ncurprod := make([]int, mem+RULEINC) 598 | copy(ncurprod, curprod) 599 | curprod = ncurprod 600 | } 601 | t = gettok() 602 | } 603 | if t == PREC { 604 | if gettok() != IDENTIFIER { 605 | lerrorf(ruleline, "illegal %%prec syntax") 606 | } 607 | j = chfind(2, tokname) 608 | if j >= NTBASE { 609 | lerrorf(ruleline, "nonterminal "+nontrst[j-NTBASE].name+" illegal after %%prec") 610 | } 611 | levprd[nprod] = toklev[j] 612 | t = gettok() 613 | } 614 | if t != '=' { 615 | break 616 | } 617 | levprd[nprod] |= ACTFLAG 618 | fmt.Fprintf(fcode, "\n\tcase %v:", nprod) 619 | fmt.Fprintf(fcode, "\n\t\t%sDollar = %sS[%spt-%v:%spt+1]", prefix, prefix, prefix, mem-1, prefix) 620 | cpyact(curprod, mem) 621 | 622 | // action within rule... 623 | t = gettok() 624 | if t == IDENTIFIER { 625 | // make it a nonterminal 626 | j = chfind(1, fmt.Sprintf("$$%v", nprod)) 627 | 628 | // 629 | // the current rule will become rule number nprod+1 630 | // enter null production for action 631 | // 632 | prdptr[nprod] = make([]int, 2) 633 | prdptr[nprod][0] = j 634 | prdptr[nprod][1] = -nprod 635 | 636 | // update the production information 637 | nprod++ 638 | moreprod() 639 | levprd[nprod] = levprd[nprod-1] & ^ACTFLAG 640 | levprd[nprod-1] = ACTFLAG 641 | rlines[nprod] = lineno 642 | 643 | // make the action appear in the original rule 644 | curprod[mem] = j 645 | mem++ 646 | if mem >= len(curprod) { 647 | ncurprod := make([]int, mem+RULEINC) 648 | copy(ncurprod, curprod) 649 | curprod = ncurprod 650 | } 651 | } 652 | } 653 | 654 | for t == ';' { 655 | t = gettok() 656 | } 657 | curprod[mem] = -nprod 658 | mem++ 659 | 660 | // check that default action is reasonable 661 | if ntypes != 0 && (levprd[nprod]&ACTFLAG) == 0 && 662 | nontrst[curprod[0]-NTBASE].value != 0 { 663 | // no explicit action, LHS has value 664 | tempty := curprod[1] 665 | if tempty < 0 { 666 | lerrorf(ruleline, "must return a value, since LHS has a type") 667 | } 668 | if tempty >= NTBASE { 669 | tempty = nontrst[tempty-NTBASE].value 670 | } else { 671 | tempty = TYPE(toklev[tempty]) 672 | } 673 | if tempty != nontrst[curprod[0]-NTBASE].value { 674 | lerrorf(ruleline, "default action causes potential type clash") 675 | } 676 | } 677 | moreprod() 678 | prdptr[nprod] = make([]int, mem) 679 | copy(prdptr[nprod], curprod) 680 | nprod++ 681 | moreprod() 682 | levprd[nprod] = 0 683 | } 684 | 685 | if TEMPSIZE < ntokens+nnonter+1 { 686 | errorf("too many tokens (%d) or non-terminals (%d)", ntokens, nnonter) 687 | } 688 | 689 | // 690 | // end of all rules 691 | // dump out the prefix code 692 | // 693 | 694 | fmt.Fprintf(fcode, "\n\t}") 695 | 696 | // put out non-literal terminals 697 | for i := TOKSTART; i <= ntokens; i++ { 698 | // non-literals 699 | if !tokset[i].noconst { 700 | fmt.Fprintf(ftable, "const %v = %v\n", tokset[i].name, tokset[i].value) 701 | } 702 | } 703 | 704 | // put out names of tokens 705 | ftable.WriteRune('\n') 706 | fmt.Fprintf(ftable, "var %sToknames = [...]string{\n", prefix) 707 | for i := 1; i <= ntokens; i++ { 708 | fmt.Fprintf(ftable, "\t%q,\n", tokset[i].name) 709 | } 710 | fmt.Fprintf(ftable, "}\n") 711 | 712 | // put out names of states. 713 | // commented out to avoid a huge table just for debugging. 714 | // re-enable to have the names in the binary. 715 | fmt.Fprintf(ftable, "var %sStatenames = [...]string{", prefix) 716 | // for i:=TOKSTART; i<=ntokens; i++ { 717 | // fmt.Fprintf(ftable, "\t%q,\n", tokset[i].name); 718 | // } 719 | fmt.Fprintf(ftable, "}\n") 720 | 721 | ftable.WriteRune('\n') 722 | fmt.Fprintf(ftable, "const %sEofCode = 1\n", prefix) 723 | fmt.Fprintf(ftable, "const %sErrCode = 2\n", prefix) 724 | fmt.Fprintf(ftable, "const %sInitialStackSize = %v\n", prefix, initialstacksize) 725 | 726 | // 727 | // copy any postfix code 728 | // 729 | if t == MARK { 730 | if !lflag { 731 | fmt.Fprintf(ftable, "\n//line %v:%v\n", infile, lineno) 732 | } 733 | for { 734 | c := getrune(finput) 735 | if c == EOF { 736 | break 737 | } 738 | ftable.WriteRune(c) 739 | } 740 | } 741 | } 742 | 743 | // 744 | // allocate enough room to hold another production 745 | // 746 | func moreprod() { 747 | n := len(prdptr) 748 | if nprod >= n { 749 | nn := n + PRODINC 750 | aprod := make([][]int, nn) 751 | alevprd := make([]int, nn) 752 | arlines := make([]int, nn) 753 | 754 | copy(aprod, prdptr) 755 | copy(alevprd, levprd) 756 | copy(arlines, rlines) 757 | 758 | prdptr = aprod 759 | levprd = alevprd 760 | rlines = arlines 761 | } 762 | } 763 | 764 | // 765 | // define s to be a terminal if nt==0 766 | // or a nonterminal if nt==1 767 | // 768 | func defin(nt int, s string) int { 769 | val := 0 770 | if nt != 0 { 771 | nnonter++ 772 | if nnonter >= len(nontrst) { 773 | anontrst := make([]Symb, nnonter+SYMINC) 774 | copy(anontrst, nontrst) 775 | nontrst = anontrst 776 | } 777 | nontrst[nnonter] = Symb{name: s} 778 | return NTBASE + nnonter 779 | } 780 | 781 | // must be a token 782 | ntokens++ 783 | if ntokens >= len(tokset) { 784 | nn := ntokens + SYMINC 785 | atokset := make([]Symb, nn) 786 | atoklev := make([]int, nn) 787 | 788 | copy(atoklev, toklev) 789 | copy(atokset, tokset) 790 | 791 | tokset = atokset 792 | toklev = atoklev 793 | } 794 | tokset[ntokens].name = s 795 | toklev[ntokens] = 0 796 | 797 | // establish value for token 798 | // single character literal 799 | if s[0] == '\'' || s[0] == '"' { 800 | q, err := strconv.Unquote(s) 801 | if err != nil { 802 | errorf("invalid token: %s", err) 803 | } 804 | rq := []rune(q) 805 | if len(rq) != 1 { 806 | errorf("character token too long: %s", s) 807 | } 808 | val = int(rq[0]) 809 | if val == 0 { 810 | errorf("token value 0 is illegal") 811 | } 812 | tokset[ntokens].noconst = true 813 | } else { 814 | val = extval 815 | extval++ 816 | if s[0] == '$' { 817 | tokset[ntokens].noconst = true 818 | } 819 | } 820 | 821 | tokset[ntokens].value = val 822 | return ntokens 823 | } 824 | 825 | var peekline = 0 826 | 827 | func gettok() int { 828 | var i int 829 | var match, c rune 830 | 831 | tokname = "" 832 | for { 833 | lineno += peekline 834 | peekline = 0 835 | c = getrune(finput) 836 | for c == ' ' || c == '\n' || c == '\t' || c == '\v' || c == '\r' { 837 | if c == '\n' { 838 | lineno++ 839 | } 840 | c = getrune(finput) 841 | } 842 | 843 | // skip comment -- fix 844 | if c != '/' { 845 | break 846 | } 847 | lineno += skipcom() 848 | } 849 | 850 | switch c { 851 | case EOF: 852 | if tokflag { 853 | fmt.Printf(">>> ENDFILE %v\n", lineno) 854 | } 855 | return ENDFILE 856 | 857 | case '{': 858 | ungetrune(finput, c) 859 | if tokflag { 860 | fmt.Printf(">>> ={ %v\n", lineno) 861 | } 862 | return '=' 863 | 864 | case '<': 865 | // get, and look up, a type name (union member name) 866 | c = getrune(finput) 867 | for c != '>' && c != EOF && c != '\n' { 868 | tokname += string(c) 869 | c = getrune(finput) 870 | } 871 | 872 | if c != '>' { 873 | errorf("unterminated < ... > clause") 874 | } 875 | 876 | for i = 1; i <= ntypes; i++ { 877 | if typeset[i] == tokname { 878 | numbval = i 879 | if tokflag { 880 | fmt.Printf(">>> TYPENAME old <%v> %v\n", tokname, lineno) 881 | } 882 | return TYPENAME 883 | } 884 | } 885 | ntypes++ 886 | numbval = ntypes 887 | typeset[numbval] = tokname 888 | if tokflag { 889 | fmt.Printf(">>> TYPENAME new <%v> %v\n", tokname, lineno) 890 | } 891 | return TYPENAME 892 | 893 | case '"', '\'': 894 | match = c 895 | tokname = string(c) 896 | for { 897 | c = getrune(finput) 898 | if c == '\n' || c == EOF { 899 | errorf("illegal or missing ' or \"") 900 | } 901 | if c == '\\' { 902 | tokname += string('\\') 903 | c = getrune(finput) 904 | } else if c == match { 905 | if tokflag { 906 | fmt.Printf(">>> IDENTIFIER \"%v\" %v\n", tokname, lineno) 907 | } 908 | tokname += string(c) 909 | return IDENTIFIER 910 | } 911 | tokname += string(c) 912 | } 913 | 914 | case '%': 915 | c = getrune(finput) 916 | switch c { 917 | case '%': 918 | if tokflag { 919 | fmt.Printf(">>> MARK %%%% %v\n", lineno) 920 | } 921 | return MARK 922 | case '=': 923 | if tokflag { 924 | fmt.Printf(">>> PREC %%= %v\n", lineno) 925 | } 926 | return PREC 927 | case '{': 928 | if tokflag { 929 | fmt.Printf(">>> LCURLY %%{ %v\n", lineno) 930 | } 931 | return LCURLY 932 | } 933 | 934 | getword(c) 935 | // find a reserved word 936 | for i := range resrv { 937 | if tokname == resrv[i].name { 938 | if tokflag { 939 | fmt.Printf(">>> %%%v %v %v\n", tokname, 940 | resrv[i].value-PRIVATE, lineno) 941 | } 942 | return resrv[i].value 943 | } 944 | } 945 | errorf("invalid escape, or illegal reserved word: %v", tokname) 946 | 947 | case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': 948 | numbval = int(c - '0') 949 | for { 950 | c = getrune(finput) 951 | if !isdigit(c) { 952 | break 953 | } 954 | numbval = numbval*10 + int(c-'0') 955 | } 956 | ungetrune(finput, c) 957 | if tokflag { 958 | fmt.Printf(">>> NUMBER %v %v\n", numbval, lineno) 959 | } 960 | return NUMBER 961 | 962 | default: 963 | if isword(c) || c == '.' || c == '$' { 964 | getword(c) 965 | break 966 | } 967 | if tokflag { 968 | fmt.Printf(">>> OPERATOR %v %v\n", string(c), lineno) 969 | } 970 | return int(c) 971 | } 972 | 973 | // look ahead to distinguish IDENTIFIER from IDENTCOLON 974 | c = getrune(finput) 975 | for c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\r' || c == '/' { 976 | if c == '\n' { 977 | peekline++ 978 | } 979 | // look for comments 980 | if c == '/' { 981 | peekline += skipcom() 982 | } 983 | c = getrune(finput) 984 | } 985 | if c == ':' { 986 | if tokflag { 987 | fmt.Printf(">>> IDENTCOLON %v: %v\n", tokname, lineno) 988 | } 989 | return IDENTCOLON 990 | } 991 | 992 | ungetrune(finput, c) 993 | if tokflag { 994 | fmt.Printf(">>> IDENTIFIER %v %v\n", tokname, lineno) 995 | } 996 | return IDENTIFIER 997 | } 998 | 999 | func getword(c rune) { 1000 | tokname = "" 1001 | for isword(c) || isdigit(c) || c == '.' || c == '$' { 1002 | tokname += string(c) 1003 | c = getrune(finput) 1004 | } 1005 | ungetrune(finput, c) 1006 | } 1007 | 1008 | // 1009 | // determine the type of a symbol 1010 | // 1011 | func fdtype(t int) int { 1012 | var v int 1013 | var s string 1014 | 1015 | if t >= NTBASE { 1016 | v = nontrst[t-NTBASE].value 1017 | s = nontrst[t-NTBASE].name 1018 | } else { 1019 | v = TYPE(toklev[t]) 1020 | s = tokset[t].name 1021 | } 1022 | if v <= 0 { 1023 | errorf("must specify type for %v", s) 1024 | } 1025 | return v 1026 | } 1027 | 1028 | func chfind(t int, s string) int { 1029 | if s[0] == '"' || s[0] == '\'' { 1030 | t = 0 1031 | } 1032 | for i := 0; i <= ntokens; i++ { 1033 | if s == tokset[i].name { 1034 | return i 1035 | } 1036 | } 1037 | for i := 0; i <= nnonter; i++ { 1038 | if s == nontrst[i].name { 1039 | return NTBASE + i 1040 | } 1041 | } 1042 | 1043 | // cannot find name 1044 | if t > 1 { 1045 | errorf("%v should have been defined earlier", s) 1046 | } 1047 | return defin(t, s) 1048 | } 1049 | 1050 | // 1051 | // copy the union declaration to the output, and the define file if present 1052 | // 1053 | func cpyunion() { 1054 | 1055 | if !lflag { 1056 | fmt.Fprintf(ftable, "\n//line %v:%v\n", infile, lineno) 1057 | } 1058 | fmt.Fprintf(ftable, "type %sSymType struct", prefix) 1059 | 1060 | level := 0 1061 | 1062 | out: 1063 | for { 1064 | c := getrune(finput) 1065 | if c == EOF { 1066 | errorf("EOF encountered while processing %%union") 1067 | } 1068 | ftable.WriteRune(c) 1069 | switch c { 1070 | case '\n': 1071 | lineno++ 1072 | case '{': 1073 | if level == 0 { 1074 | fmt.Fprintf(ftable, "\n\tyys int") 1075 | } 1076 | level++ 1077 | case '}': 1078 | level-- 1079 | if level == 0 { 1080 | break out 1081 | } 1082 | } 1083 | } 1084 | fmt.Fprintf(ftable, "\n\n") 1085 | } 1086 | 1087 | // 1088 | // saves code between %{ and %} 1089 | // adds an import for __fmt__ the first time 1090 | // 1091 | func cpycode() { 1092 | lno := lineno 1093 | 1094 | c := getrune(finput) 1095 | if c == '\n' { 1096 | c = getrune(finput) 1097 | lineno++ 1098 | } 1099 | if !lflag { 1100 | fmt.Fprintf(ftable, "\n//line %v:%v\n", infile, lineno) 1101 | } 1102 | // accumulate until %} 1103 | code := make([]rune, 0, 1024) 1104 | for c != EOF { 1105 | if c == '%' { 1106 | c = getrune(finput) 1107 | if c == '}' { 1108 | emitcode(code, lno+1) 1109 | return 1110 | } 1111 | code = append(code, '%') 1112 | } 1113 | code = append(code, c) 1114 | if c == '\n' { 1115 | lineno++ 1116 | } 1117 | c = getrune(finput) 1118 | } 1119 | lineno = lno 1120 | errorf("eof before %%}") 1121 | } 1122 | 1123 | // 1124 | // emits code saved up from between %{ and %} 1125 | // called by cpycode 1126 | // adds an import for __yyfmt__ after the package clause 1127 | // 1128 | func emitcode(code []rune, lineno int) { 1129 | for i, line := range lines(code) { 1130 | writecode(line) 1131 | if !fmtImported && isPackageClause(line) { 1132 | fmt.Fprintln(ftable, `import __yyfmt__ "fmt"`) 1133 | if !lflag { 1134 | fmt.Fprintf(ftable, "//line %v:%v\n\t\t", infile, lineno+i) 1135 | } 1136 | fmtImported = true 1137 | } 1138 | } 1139 | } 1140 | 1141 | // 1142 | // does this line look like a package clause? not perfect: might be confused by early comments. 1143 | // 1144 | func isPackageClause(line []rune) bool { 1145 | line = skipspace(line) 1146 | 1147 | // must be big enough. 1148 | if len(line) < len("package X\n") { 1149 | return false 1150 | } 1151 | 1152 | // must start with "package" 1153 | for i, r := range []rune("package") { 1154 | if line[i] != r { 1155 | return false 1156 | } 1157 | } 1158 | line = skipspace(line[len("package"):]) 1159 | 1160 | // must have another identifier. 1161 | if len(line) == 0 || (!unicode.IsLetter(line[0]) && line[0] != '_') { 1162 | return false 1163 | } 1164 | for len(line) > 0 { 1165 | if !unicode.IsLetter(line[0]) && !unicode.IsDigit(line[0]) && line[0] != '_' { 1166 | break 1167 | } 1168 | line = line[1:] 1169 | } 1170 | line = skipspace(line) 1171 | 1172 | // eol, newline, or comment must follow 1173 | if len(line) == 0 { 1174 | return true 1175 | } 1176 | if line[0] == '\r' || line[0] == '\n' { 1177 | return true 1178 | } 1179 | if len(line) >= 2 { 1180 | return line[0] == '/' && (line[1] == '/' || line[1] == '*') 1181 | } 1182 | return false 1183 | } 1184 | 1185 | // 1186 | // skip initial spaces 1187 | // 1188 | func skipspace(line []rune) []rune { 1189 | for len(line) > 0 { 1190 | if line[0] != ' ' && line[0] != '\t' { 1191 | break 1192 | } 1193 | line = line[1:] 1194 | } 1195 | return line 1196 | } 1197 | 1198 | // 1199 | // break code into lines 1200 | // 1201 | func lines(code []rune) [][]rune { 1202 | l := make([][]rune, 0, 100) 1203 | for len(code) > 0 { 1204 | // one line per loop 1205 | var i int 1206 | for i = range code { 1207 | if code[i] == '\n' { 1208 | break 1209 | } 1210 | } 1211 | l = append(l, code[:i+1]) 1212 | code = code[i+1:] 1213 | } 1214 | return l 1215 | } 1216 | 1217 | // 1218 | // writes code to ftable 1219 | // 1220 | func writecode(code []rune) { 1221 | for _, r := range code { 1222 | ftable.WriteRune(r) 1223 | } 1224 | } 1225 | 1226 | // 1227 | // skip over comments 1228 | // skipcom is called after reading a '/' 1229 | // 1230 | func skipcom() int { 1231 | var c rune 1232 | 1233 | c = getrune(finput) 1234 | if c == '/' { 1235 | for c != EOF { 1236 | if c == '\n' { 1237 | return 1 1238 | } 1239 | c = getrune(finput) 1240 | } 1241 | errorf("EOF inside comment") 1242 | return 0 1243 | } 1244 | if c != '*' { 1245 | errorf("illegal comment") 1246 | } 1247 | 1248 | nl := 0 // lines skipped 1249 | c = getrune(finput) 1250 | 1251 | l1: 1252 | switch c { 1253 | case '*': 1254 | c = getrune(finput) 1255 | if c == '/' { 1256 | break 1257 | } 1258 | goto l1 1259 | 1260 | case '\n': 1261 | nl++ 1262 | fallthrough 1263 | 1264 | default: 1265 | c = getrune(finput) 1266 | goto l1 1267 | } 1268 | return nl 1269 | } 1270 | 1271 | func dumpprod(curprod []int, max int) { 1272 | fmt.Printf("\n") 1273 | for i := 0; i < max; i++ { 1274 | p := curprod[i] 1275 | if p < 0 { 1276 | fmt.Printf("[%v] %v\n", i, p) 1277 | } else { 1278 | fmt.Printf("[%v] %v\n", i, symnam(p)) 1279 | } 1280 | } 1281 | } 1282 | 1283 | // 1284 | // copy action to the next ; or closing } 1285 | // 1286 | func cpyact(curprod []int, max int) { 1287 | 1288 | if !lflag { 1289 | fmt.Fprintf(fcode, "\n\t\t//line %v:%v", infile, lineno) 1290 | } 1291 | fmt.Fprint(fcode, "\n\t\t") 1292 | 1293 | lno := lineno 1294 | brac := 0 1295 | 1296 | loop: 1297 | for { 1298 | c := getrune(finput) 1299 | 1300 | swt: 1301 | switch c { 1302 | case ';': 1303 | if brac == 0 { 1304 | fcode.WriteRune(c) 1305 | return 1306 | } 1307 | 1308 | case '{': 1309 | if brac == 0 { 1310 | } 1311 | brac++ 1312 | 1313 | case '$': 1314 | s := 1 1315 | tok := -1 1316 | c = getrune(finput) 1317 | 1318 | // type description 1319 | if c == '<' { 1320 | ungetrune(finput, c) 1321 | if gettok() != TYPENAME { 1322 | errorf("bad syntax on $ clause") 1323 | } 1324 | tok = numbval 1325 | c = getrune(finput) 1326 | } 1327 | if c == '$' { 1328 | fmt.Fprintf(fcode, "%sVAL", prefix) 1329 | 1330 | // put out the proper tag... 1331 | if ntypes != 0 { 1332 | if tok < 0 { 1333 | tok = fdtype(curprod[0]) 1334 | } 1335 | fmt.Fprintf(fcode, ".%v", typeset[tok]) 1336 | } 1337 | continue loop 1338 | } 1339 | if c == '-' { 1340 | s = -s 1341 | c = getrune(finput) 1342 | } 1343 | j := 0 1344 | if isdigit(c) { 1345 | for isdigit(c) { 1346 | j = j*10 + int(c-'0') 1347 | c = getrune(finput) 1348 | } 1349 | ungetrune(finput, c) 1350 | j = j * s 1351 | if j >= max { 1352 | errorf("Illegal use of $%v", j) 1353 | } 1354 | } else if isword(c) || c == '.' { 1355 | // look for $name 1356 | ungetrune(finput, c) 1357 | if gettok() != IDENTIFIER { 1358 | errorf("$ must be followed by an identifier") 1359 | } 1360 | tokn := chfind(2, tokname) 1361 | fnd := -1 1362 | c = getrune(finput) 1363 | if c != '@' { 1364 | ungetrune(finput, c) 1365 | } else if gettok() != NUMBER { 1366 | errorf("@ must be followed by number") 1367 | } else { 1368 | fnd = numbval 1369 | } 1370 | for j = 1; j < max; j++ { 1371 | if tokn == curprod[j] { 1372 | fnd-- 1373 | if fnd <= 0 { 1374 | break 1375 | } 1376 | } 1377 | } 1378 | if j >= max { 1379 | errorf("$name or $name@number not found") 1380 | } 1381 | } else { 1382 | fcode.WriteRune('$') 1383 | if s < 0 { 1384 | fcode.WriteRune('-') 1385 | } 1386 | ungetrune(finput, c) 1387 | continue loop 1388 | } 1389 | fmt.Fprintf(fcode, "%sDollar[%v]", prefix, j) 1390 | 1391 | // put out the proper tag 1392 | if ntypes != 0 { 1393 | if j <= 0 && tok < 0 { 1394 | errorf("must specify type of $%v", j) 1395 | } 1396 | if tok < 0 { 1397 | tok = fdtype(curprod[j]) 1398 | } 1399 | fmt.Fprintf(fcode, ".%v", typeset[tok]) 1400 | } 1401 | continue loop 1402 | 1403 | case '}': 1404 | brac-- 1405 | if brac != 0 { 1406 | break 1407 | } 1408 | fcode.WriteRune(c) 1409 | return 1410 | 1411 | case '/': 1412 | nc := getrune(finput) 1413 | if nc != '/' && nc != '*' { 1414 | ungetrune(finput, nc) 1415 | break 1416 | } 1417 | // a comment 1418 | fcode.WriteRune(c) 1419 | fcode.WriteRune(nc) 1420 | c = getrune(finput) 1421 | for c != EOF { 1422 | switch { 1423 | case c == '\n': 1424 | lineno++ 1425 | if nc == '/' { // end of // comment 1426 | break swt 1427 | } 1428 | case c == '*' && nc == '*': // end of /* comment? 1429 | nnc := getrune(finput) 1430 | if nnc == '/' { 1431 | fcode.WriteRune('*') 1432 | fcode.WriteRune('/') 1433 | c = getrune(finput) 1434 | break swt 1435 | } 1436 | ungetrune(finput, nnc) 1437 | } 1438 | fcode.WriteRune(c) 1439 | c = getrune(finput) 1440 | } 1441 | errorf("EOF inside comment") 1442 | 1443 | case '\'', '"': 1444 | // character string or constant 1445 | match := c 1446 | fcode.WriteRune(c) 1447 | c = getrune(finput) 1448 | for c != EOF { 1449 | if c == '\\' { 1450 | fcode.WriteRune(c) 1451 | c = getrune(finput) 1452 | if c == '\n' { 1453 | lineno++ 1454 | } 1455 | } else if c == match { 1456 | break swt 1457 | } 1458 | if c == '\n' { 1459 | errorf("newline in string or char const") 1460 | } 1461 | fcode.WriteRune(c) 1462 | c = getrune(finput) 1463 | } 1464 | errorf("EOF in string or character constant") 1465 | 1466 | case EOF: 1467 | lineno = lno 1468 | errorf("action does not terminate") 1469 | 1470 | case '\n': 1471 | fmt.Fprint(fcode, "\n\t") 1472 | lineno++ 1473 | continue loop 1474 | } 1475 | 1476 | fcode.WriteRune(c) 1477 | } 1478 | } 1479 | 1480 | func openup() { 1481 | infile = flag.Arg(0) 1482 | finput = open(infile) 1483 | if finput == nil { 1484 | errorf("cannot open %v", infile) 1485 | } 1486 | 1487 | foutput = nil 1488 | if vflag != "" { 1489 | foutput = create(vflag) 1490 | if foutput == nil { 1491 | errorf("can't create file %v", vflag) 1492 | } 1493 | } 1494 | 1495 | ftable = nil 1496 | if oflag == "" { 1497 | oflag = "y.go" 1498 | } 1499 | ftable = create(oflag) 1500 | if ftable == nil { 1501 | errorf("can't create file %v", oflag) 1502 | } 1503 | 1504 | } 1505 | 1506 | // 1507 | // return a pointer to the name of symbol i 1508 | // 1509 | func symnam(i int) string { 1510 | var s string 1511 | 1512 | if i >= NTBASE { 1513 | s = nontrst[i-NTBASE].name 1514 | } else { 1515 | s = tokset[i].name 1516 | } 1517 | return s 1518 | } 1519 | 1520 | // 1521 | // set elements 0 through n-1 to c 1522 | // 1523 | func aryfil(v []int, n, c int) { 1524 | for i := 0; i < n; i++ { 1525 | v[i] = c 1526 | } 1527 | } 1528 | 1529 | // 1530 | // compute an array with the beginnings of productions yielding given nonterminals 1531 | // The array pres points to these lists 1532 | // the array pyield has the lists: the total size is only NPROD+1 1533 | // 1534 | func cpres() { 1535 | pres = make([][][]int, nnonter+1) 1536 | curres := make([][]int, nprod) 1537 | 1538 | if false { 1539 | for j := 0; j <= nnonter; j++ { 1540 | fmt.Printf("nnonter[%v] = %v\n", j, nontrst[j].name) 1541 | } 1542 | for j := 0; j < nprod; j++ { 1543 | fmt.Printf("prdptr[%v][0] = %v+NTBASE\n", j, prdptr[j][0]-NTBASE) 1544 | } 1545 | } 1546 | 1547 | fatfl = 0 // make undefined symbols nonfatal 1548 | for i := 0; i <= nnonter; i++ { 1549 | n := 0 1550 | c := i + NTBASE 1551 | for j := 0; j < nprod; j++ { 1552 | if prdptr[j][0] == c { 1553 | curres[n] = prdptr[j][1:] 1554 | n++ 1555 | } 1556 | } 1557 | if n == 0 { 1558 | errorf("nonterminal %v not defined", nontrst[i].name) 1559 | continue 1560 | } 1561 | pres[i] = make([][]int, n) 1562 | copy(pres[i], curres) 1563 | } 1564 | fatfl = 1 1565 | if nerrors != 0 { 1566 | summary() 1567 | exit(1) 1568 | } 1569 | } 1570 | 1571 | func dumppres() { 1572 | for i := 0; i <= nnonter; i++ { 1573 | fmt.Printf("nonterm %d\n", i) 1574 | curres := pres[i] 1575 | for j := 0; j < len(curres); j++ { 1576 | fmt.Printf("\tproduction %d:", j) 1577 | prd := curres[j] 1578 | for k := 0; k < len(prd); k++ { 1579 | fmt.Printf(" %d", prd[k]) 1580 | } 1581 | fmt.Print("\n") 1582 | } 1583 | } 1584 | } 1585 | 1586 | // 1587 | // mark nonterminals which derive the empty string 1588 | // also, look for nonterminals which don't derive any token strings 1589 | // 1590 | func cempty() { 1591 | var i, p, np int 1592 | var prd []int 1593 | 1594 | pempty = make([]int, nnonter+1) 1595 | 1596 | // first, use the array pempty to detect productions that can never be reduced 1597 | // set pempty to WHONOWS 1598 | aryfil(pempty, nnonter+1, WHOKNOWS) 1599 | 1600 | // now, look at productions, marking nonterminals which derive something 1601 | more: 1602 | for { 1603 | for i = 0; i < nprod; i++ { 1604 | prd = prdptr[i] 1605 | if pempty[prd[0]-NTBASE] != 0 { 1606 | continue 1607 | } 1608 | np = len(prd) - 1 1609 | for p = 1; p < np; p++ { 1610 | if prd[p] >= NTBASE && pempty[prd[p]-NTBASE] == WHOKNOWS { 1611 | break 1612 | } 1613 | } 1614 | // production can be derived 1615 | if p == np { 1616 | pempty[prd[0]-NTBASE] = OK 1617 | continue more 1618 | } 1619 | } 1620 | break 1621 | } 1622 | 1623 | // now, look at the nonterminals, to see if they are all OK 1624 | for i = 0; i <= nnonter; i++ { 1625 | // the added production rises or falls as the start symbol ... 1626 | if i == 0 { 1627 | continue 1628 | } 1629 | if pempty[i] != OK { 1630 | fatfl = 0 1631 | errorf("nonterminal " + nontrst[i].name + " never derives any token string") 1632 | } 1633 | } 1634 | 1635 | if nerrors != 0 { 1636 | summary() 1637 | exit(1) 1638 | } 1639 | 1640 | // now, compute the pempty array, to see which nonterminals derive the empty string 1641 | // set pempty to WHOKNOWS 1642 | aryfil(pempty, nnonter+1, WHOKNOWS) 1643 | 1644 | // loop as long as we keep finding empty nonterminals 1645 | 1646 | again: 1647 | for { 1648 | next: 1649 | for i = 1; i < nprod; i++ { 1650 | // not known to be empty 1651 | prd = prdptr[i] 1652 | if pempty[prd[0]-NTBASE] != WHOKNOWS { 1653 | continue 1654 | } 1655 | np = len(prd) - 1 1656 | for p = 1; p < np; p++ { 1657 | if prd[p] < NTBASE || pempty[prd[p]-NTBASE] != EMPTY { 1658 | continue next 1659 | } 1660 | } 1661 | 1662 | // we have a nontrivially empty nonterminal 1663 | pempty[prd[0]-NTBASE] = EMPTY 1664 | 1665 | // got one ... try for another 1666 | continue again 1667 | } 1668 | return 1669 | } 1670 | } 1671 | 1672 | func dumpempty() { 1673 | for i := 0; i <= nnonter; i++ { 1674 | if pempty[i] == EMPTY { 1675 | fmt.Printf("non-term %d %s matches empty\n", i, symnam(i+NTBASE)) 1676 | } 1677 | } 1678 | } 1679 | 1680 | // 1681 | // compute an array with the first of nonterminals 1682 | // 1683 | func cpfir() { 1684 | var s, n, p, np, ch, i int 1685 | var curres [][]int 1686 | var prd []int 1687 | 1688 | wsets = make([]Wset, nnonter+WSETINC) 1689 | pfirst = make([]Lkset, nnonter+1) 1690 | for i = 0; i <= nnonter; i++ { 1691 | wsets[i].ws = mkset() 1692 | pfirst[i] = mkset() 1693 | curres = pres[i] 1694 | n = len(curres) 1695 | 1696 | // initially fill the sets 1697 | for s = 0; s < n; s++ { 1698 | prd = curres[s] 1699 | np = len(prd) - 1 1700 | for p = 0; p < np; p++ { 1701 | ch = prd[p] 1702 | if ch < NTBASE { 1703 | setbit(pfirst[i], ch) 1704 | break 1705 | } 1706 | if pempty[ch-NTBASE] == 0 { 1707 | break 1708 | } 1709 | } 1710 | } 1711 | } 1712 | 1713 | // now, reflect transitivity 1714 | changes := 1 1715 | for changes != 0 { 1716 | changes = 0 1717 | for i = 0; i <= nnonter; i++ { 1718 | curres = pres[i] 1719 | n = len(curres) 1720 | for s = 0; s < n; s++ { 1721 | prd = curres[s] 1722 | np = len(prd) - 1 1723 | for p = 0; p < np; p++ { 1724 | ch = prd[p] - NTBASE 1725 | if ch < 0 { 1726 | break 1727 | } 1728 | changes |= setunion(pfirst[i], pfirst[ch]) 1729 | if pempty[ch] == 0 { 1730 | break 1731 | } 1732 | } 1733 | } 1734 | } 1735 | } 1736 | 1737 | if indebug == 0 { 1738 | return 1739 | } 1740 | if foutput != nil { 1741 | for i = 0; i <= nnonter; i++ { 1742 | fmt.Fprintf(foutput, "\n%v: %v %v\n", 1743 | nontrst[i].name, pfirst[i], pempty[i]) 1744 | } 1745 | } 1746 | } 1747 | 1748 | // 1749 | // generate the states 1750 | // 1751 | func stagen() { 1752 | // initialize 1753 | nstate = 0 1754 | tstates = make([]int, ntokens+1) // states generated by terminal gotos 1755 | ntstates = make([]int, nnonter+1) // states generated by nonterminal gotos 1756 | amem = make([]int, ACTSIZE) 1757 | memp = 0 1758 | 1759 | clset = mkset() 1760 | pstate[0] = 0 1761 | pstate[1] = 0 1762 | aryfil(clset, tbitset, 0) 1763 | putitem(Pitem{prdptr[0], 0, 0, 0}, clset) 1764 | tystate[0] = MUSTDO 1765 | nstate = 1 1766 | pstate[2] = pstate[1] 1767 | 1768 | // 1769 | // now, the main state generation loop 1770 | // first pass generates all of the states 1771 | // later passes fix up lookahead 1772 | // could be sped up a lot by remembering 1773 | // results of the first pass rather than recomputing 1774 | // 1775 | first := 1 1776 | for more := 1; more != 0; first = 0 { 1777 | more = 0 1778 | for i := 0; i < nstate; i++ { 1779 | if tystate[i] != MUSTDO { 1780 | continue 1781 | } 1782 | 1783 | tystate[i] = DONE 1784 | aryfil(temp1, nnonter+1, 0) 1785 | 1786 | // take state i, close it, and do gotos 1787 | closure(i) 1788 | 1789 | // generate goto's 1790 | for p := 0; p < cwp; p++ { 1791 | pi := wsets[p] 1792 | if pi.flag != 0 { 1793 | continue 1794 | } 1795 | wsets[p].flag = 1 1796 | c := pi.pitem.first 1797 | if c <= 1 { 1798 | if pstate[i+1]-pstate[i] <= p { 1799 | tystate[i] = MUSTLOOKAHEAD 1800 | } 1801 | continue 1802 | } 1803 | 1804 | // do a goto on c 1805 | putitem(wsets[p].pitem, wsets[p].ws) 1806 | for q := p + 1; q < cwp; q++ { 1807 | // this item contributes to the goto 1808 | if c == wsets[q].pitem.first { 1809 | putitem(wsets[q].pitem, wsets[q].ws) 1810 | wsets[q].flag = 1 1811 | } 1812 | } 1813 | 1814 | if c < NTBASE { 1815 | state(c) // register new state 1816 | } else { 1817 | temp1[c-NTBASE] = state(c) 1818 | } 1819 | } 1820 | 1821 | if gsdebug != 0 && foutput != nil { 1822 | fmt.Fprintf(foutput, "%v: ", i) 1823 | for j := 0; j <= nnonter; j++ { 1824 | if temp1[j] != 0 { 1825 | fmt.Fprintf(foutput, "%v %v,", nontrst[j].name, temp1[j]) 1826 | } 1827 | } 1828 | fmt.Fprintf(foutput, "\n") 1829 | } 1830 | 1831 | if first != 0 { 1832 | indgo[i] = apack(temp1[1:], nnonter-1) - 1 1833 | } 1834 | 1835 | more++ 1836 | } 1837 | } 1838 | } 1839 | 1840 | // 1841 | // generate the closure of state i 1842 | // 1843 | func closure(i int) { 1844 | zzclose++ 1845 | 1846 | // first, copy kernel of state i to wsets 1847 | cwp = 0 1848 | q := pstate[i+1] 1849 | for p := pstate[i]; p < q; p++ { 1850 | wsets[cwp].pitem = statemem[p].pitem 1851 | wsets[cwp].flag = 1 // this item must get closed 1852 | copy(wsets[cwp].ws, statemem[p].look) 1853 | cwp++ 1854 | } 1855 | 1856 | // now, go through the loop, closing each item 1857 | work := 1 1858 | for work != 0 { 1859 | work = 0 1860 | for u := 0; u < cwp; u++ { 1861 | if wsets[u].flag == 0 { 1862 | continue 1863 | } 1864 | 1865 | // dot is before c 1866 | c := wsets[u].pitem.first 1867 | if c < NTBASE { 1868 | wsets[u].flag = 0 1869 | // only interesting case is where . is before nonterminal 1870 | continue 1871 | } 1872 | 1873 | // compute the lookahead 1874 | aryfil(clset, tbitset, 0) 1875 | 1876 | // find items involving c 1877 | for v := u; v < cwp; v++ { 1878 | if wsets[v].flag != 1 || wsets[v].pitem.first != c { 1879 | continue 1880 | } 1881 | pi := wsets[v].pitem.prod 1882 | ipi := wsets[v].pitem.off + 1 1883 | 1884 | wsets[v].flag = 0 1885 | if nolook != 0 { 1886 | continue 1887 | } 1888 | 1889 | ch := pi[ipi] 1890 | ipi++ 1891 | for ch > 0 { 1892 | // terminal symbol 1893 | if ch < NTBASE { 1894 | setbit(clset, ch) 1895 | break 1896 | } 1897 | 1898 | // nonterminal symbol 1899 | setunion(clset, pfirst[ch-NTBASE]) 1900 | if pempty[ch-NTBASE] == 0 { 1901 | break 1902 | } 1903 | ch = pi[ipi] 1904 | ipi++ 1905 | } 1906 | if ch <= 0 { 1907 | setunion(clset, wsets[v].ws) 1908 | } 1909 | } 1910 | 1911 | // 1912 | // now loop over productions derived from c 1913 | // 1914 | curres := pres[c-NTBASE] 1915 | n := len(curres) 1916 | 1917 | nexts: 1918 | // initially fill the sets 1919 | for s := 0; s < n; s++ { 1920 | prd := curres[s] 1921 | 1922 | // 1923 | // put these items into the closure 1924 | // is the item there 1925 | // 1926 | for v := 0; v < cwp; v++ { 1927 | // yes, it is there 1928 | if wsets[v].pitem.off == 0 && 1929 | aryeq(wsets[v].pitem.prod, prd) != 0 { 1930 | if nolook == 0 && 1931 | setunion(wsets[v].ws, clset) != 0 { 1932 | wsets[v].flag = 1 1933 | work = 1 1934 | } 1935 | continue nexts 1936 | } 1937 | } 1938 | 1939 | // not there; make a new entry 1940 | if cwp >= len(wsets) { 1941 | awsets := make([]Wset, cwp+WSETINC) 1942 | copy(awsets, wsets) 1943 | wsets = awsets 1944 | } 1945 | wsets[cwp].pitem = Pitem{prd, 0, prd[0], -prd[len(prd)-1]} 1946 | wsets[cwp].flag = 1 1947 | wsets[cwp].ws = mkset() 1948 | if nolook == 0 { 1949 | work = 1 1950 | copy(wsets[cwp].ws, clset) 1951 | } 1952 | cwp++ 1953 | } 1954 | } 1955 | } 1956 | 1957 | // have computed closure; flags are reset; return 1958 | if cldebug != 0 && foutput != nil { 1959 | fmt.Fprintf(foutput, "\nState %v, nolook = %v\n", i, nolook) 1960 | for u := 0; u < cwp; u++ { 1961 | if wsets[u].flag != 0 { 1962 | fmt.Fprintf(foutput, "flag set\n") 1963 | } 1964 | wsets[u].flag = 0 1965 | fmt.Fprintf(foutput, "\t%v", writem(wsets[u].pitem)) 1966 | prlook(wsets[u].ws) 1967 | fmt.Fprintf(foutput, "\n") 1968 | } 1969 | } 1970 | } 1971 | 1972 | // 1973 | // sorts last state,and sees if it equals earlier ones. returns state number 1974 | // 1975 | func state(c int) int { 1976 | zzstate++ 1977 | p1 := pstate[nstate] 1978 | p2 := pstate[nstate+1] 1979 | if p1 == p2 { 1980 | return 0 // null state 1981 | } 1982 | 1983 | // sort the items 1984 | var k, l int 1985 | for k = p1 + 1; k < p2; k++ { // make k the biggest 1986 | for l = k; l > p1; l-- { 1987 | if statemem[l].pitem.prodno < statemem[l-1].pitem.prodno || 1988 | statemem[l].pitem.prodno == statemem[l-1].pitem.prodno && 1989 | statemem[l].pitem.off < statemem[l-1].pitem.off { 1990 | s := statemem[l] 1991 | statemem[l] = statemem[l-1] 1992 | statemem[l-1] = s 1993 | } else { 1994 | break 1995 | } 1996 | } 1997 | } 1998 | 1999 | size1 := p2 - p1 // size of state 2000 | 2001 | var i int 2002 | if c >= NTBASE { 2003 | i = ntstates[c-NTBASE] 2004 | } else { 2005 | i = tstates[c] 2006 | } 2007 | 2008 | look: 2009 | for ; i != 0; i = mstates[i] { 2010 | // get ith state 2011 | q1 := pstate[i] 2012 | q2 := pstate[i+1] 2013 | size2 := q2 - q1 2014 | if size1 != size2 { 2015 | continue 2016 | } 2017 | k = p1 2018 | for l = q1; l < q2; l++ { 2019 | if aryeq(statemem[l].pitem.prod, statemem[k].pitem.prod) == 0 || 2020 | statemem[l].pitem.off != statemem[k].pitem.off { 2021 | continue look 2022 | } 2023 | k++ 2024 | } 2025 | 2026 | // found it 2027 | pstate[nstate+1] = pstate[nstate] // delete last state 2028 | 2029 | // fix up lookaheads 2030 | if nolook != 0 { 2031 | return i 2032 | } 2033 | k = p1 2034 | for l = q1; l < q2; l++ { 2035 | if setunion(statemem[l].look, statemem[k].look) != 0 { 2036 | tystate[i] = MUSTDO 2037 | } 2038 | k++ 2039 | } 2040 | return i 2041 | } 2042 | 2043 | // state is new 2044 | zznewstate++ 2045 | if nolook != 0 { 2046 | errorf("yacc state/nolook error") 2047 | } 2048 | pstate[nstate+2] = p2 2049 | if nstate+1 >= NSTATES { 2050 | errorf("too many states") 2051 | } 2052 | if c >= NTBASE { 2053 | mstates[nstate] = ntstates[c-NTBASE] 2054 | ntstates[c-NTBASE] = nstate 2055 | } else { 2056 | mstates[nstate] = tstates[c] 2057 | tstates[c] = nstate 2058 | } 2059 | tystate[nstate] = MUSTDO 2060 | nstate++ 2061 | return nstate - 1 2062 | } 2063 | 2064 | func putitem(p Pitem, set Lkset) { 2065 | p.off++ 2066 | p.first = p.prod[p.off] 2067 | 2068 | if pidebug != 0 && foutput != nil { 2069 | fmt.Fprintf(foutput, "putitem(%v), state %v\n", writem(p), nstate) 2070 | } 2071 | j := pstate[nstate+1] 2072 | if j >= len(statemem) { 2073 | asm := make([]Item, j+STATEINC) 2074 | copy(asm, statemem) 2075 | statemem = asm 2076 | } 2077 | statemem[j].pitem = p 2078 | if nolook == 0 { 2079 | s := mkset() 2080 | copy(s, set) 2081 | statemem[j].look = s 2082 | } 2083 | j++ 2084 | pstate[nstate+1] = j 2085 | } 2086 | 2087 | // 2088 | // creates output string for item pointed to by pp 2089 | // 2090 | func writem(pp Pitem) string { 2091 | var i int 2092 | 2093 | p := pp.prod 2094 | q := chcopy(nontrst[prdptr[pp.prodno][0]-NTBASE].name) + ": " 2095 | npi := pp.off 2096 | 2097 | pi := aryeq(p, prdptr[pp.prodno]) 2098 | 2099 | for { 2100 | c := ' ' 2101 | if pi == npi { 2102 | c = '.' 2103 | } 2104 | q += string(c) 2105 | 2106 | i = p[pi] 2107 | pi++ 2108 | if i <= 0 { 2109 | break 2110 | } 2111 | q += chcopy(symnam(i)) 2112 | } 2113 | 2114 | // an item calling for a reduction 2115 | i = p[npi] 2116 | if i < 0 { 2117 | q += fmt.Sprintf(" (%v)", -i) 2118 | } 2119 | 2120 | return q 2121 | } 2122 | 2123 | // 2124 | // pack state i from temp1 into amem 2125 | // 2126 | func apack(p []int, n int) int { 2127 | // 2128 | // we don't need to worry about checking because 2129 | // we will only look at entries known to be there... 2130 | // eliminate leading and trailing 0's 2131 | // 2132 | off := 0 2133 | pp := 0 2134 | for ; pp <= n && p[pp] == 0; pp++ { 2135 | off-- 2136 | } 2137 | 2138 | // no actions 2139 | if pp > n { 2140 | return 0 2141 | } 2142 | for ; n > pp && p[n] == 0; n-- { 2143 | } 2144 | p = p[pp : n+1] 2145 | 2146 | // now, find a place for the elements from p to q, inclusive 2147 | r := len(amem) - len(p) 2148 | 2149 | nextk: 2150 | for rr := 0; rr <= r; rr++ { 2151 | qq := rr 2152 | for pp = 0; pp < len(p); pp++ { 2153 | if p[pp] != 0 { 2154 | if p[pp] != amem[qq] && amem[qq] != 0 { 2155 | continue nextk 2156 | } 2157 | } 2158 | qq++ 2159 | } 2160 | 2161 | // we have found an acceptable k 2162 | if pkdebug != 0 && foutput != nil { 2163 | fmt.Fprintf(foutput, "off = %v, k = %v\n", off+rr, rr) 2164 | } 2165 | qq = rr 2166 | for pp = 0; pp < len(p); pp++ { 2167 | if p[pp] != 0 { 2168 | if qq > memp { 2169 | memp = qq 2170 | } 2171 | amem[qq] = p[pp] 2172 | } 2173 | qq++ 2174 | } 2175 | if pkdebug != 0 && foutput != nil { 2176 | for pp = 0; pp <= memp; pp += 10 { 2177 | fmt.Fprintf(foutput, "\n") 2178 | for qq = pp; qq <= pp+9; qq++ { 2179 | fmt.Fprintf(foutput, "%v ", amem[qq]) 2180 | } 2181 | fmt.Fprintf(foutput, "\n") 2182 | } 2183 | } 2184 | return off + rr 2185 | } 2186 | errorf("no space in action table") 2187 | return 0 2188 | } 2189 | 2190 | // 2191 | // print the output for the states 2192 | // 2193 | func output() { 2194 | var c, u, v int 2195 | 2196 | if !lflag { 2197 | fmt.Fprintf(ftable, "\n//line yacctab:1") 2198 | } 2199 | fmt.Fprintf(ftable, "\nvar %sExca = [...]int{\n", prefix) 2200 | 2201 | if len(errors) > 0 { 2202 | stateTable = make([]Row, nstate) 2203 | } 2204 | 2205 | noset := mkset() 2206 | 2207 | // output the stuff for state i 2208 | for i := 0; i < nstate; i++ { 2209 | nolook = 0 2210 | if tystate[i] != MUSTLOOKAHEAD { 2211 | nolook = 1 2212 | } 2213 | closure(i) 2214 | 2215 | // output actions 2216 | nolook = 1 2217 | aryfil(temp1, ntokens+nnonter+1, 0) 2218 | for u = 0; u < cwp; u++ { 2219 | c = wsets[u].pitem.first 2220 | if c > 1 && c < NTBASE && temp1[c] == 0 { 2221 | for v = u; v < cwp; v++ { 2222 | if c == wsets[v].pitem.first { 2223 | putitem(wsets[v].pitem, noset) 2224 | } 2225 | } 2226 | temp1[c] = state(c) 2227 | } else if c > NTBASE { 2228 | c -= NTBASE 2229 | if temp1[c+ntokens] == 0 { 2230 | temp1[c+ntokens] = amem[indgo[i]+c] 2231 | } 2232 | } 2233 | } 2234 | if i == 1 { 2235 | temp1[1] = ACCEPTCODE 2236 | } 2237 | 2238 | // now, we have the shifts; look at the reductions 2239 | lastred = 0 2240 | for u = 0; u < cwp; u++ { 2241 | c = wsets[u].pitem.first 2242 | 2243 | // reduction 2244 | if c > 0 { 2245 | continue 2246 | } 2247 | lastred = -c 2248 | us := wsets[u].ws 2249 | for k := 0; k <= ntokens; k++ { 2250 | if bitset(us, k) == 0 { 2251 | continue 2252 | } 2253 | if temp1[k] == 0 { 2254 | temp1[k] = c 2255 | } else if temp1[k] < 0 { // reduce/reduce conflict 2256 | if foutput != nil { 2257 | fmt.Fprintf(foutput, 2258 | "\n %v: reduce/reduce conflict (red'ns "+ 2259 | "%v and %v) on %v", 2260 | i, -temp1[k], lastred, symnam(k)) 2261 | } 2262 | if -temp1[k] > lastred { 2263 | temp1[k] = -lastred 2264 | } 2265 | zzrrconf++ 2266 | } else { 2267 | // potential shift/reduce conflict 2268 | precftn(lastred, k, i) 2269 | } 2270 | } 2271 | } 2272 | wract(i) 2273 | } 2274 | 2275 | fmt.Fprintf(ftable, "}\n") 2276 | ftable.WriteRune('\n') 2277 | fmt.Fprintf(ftable, "const %sNprod = %v\n", prefix, nprod) 2278 | fmt.Fprintf(ftable, "const %sPrivate = %v\n", prefix, PRIVATE) 2279 | ftable.WriteRune('\n') 2280 | fmt.Fprintf(ftable, "var %sTokenNames []string\n", prefix) 2281 | fmt.Fprintf(ftable, "var %sStates []string\n", prefix) 2282 | } 2283 | 2284 | // 2285 | // decide a shift/reduce conflict by precedence. 2286 | // r is a rule number, t a token number 2287 | // the conflict is in state s 2288 | // temp1[t] is changed to reflect the action 2289 | // 2290 | func precftn(r, t, s int) { 2291 | var action int 2292 | 2293 | lp := levprd[r] 2294 | lt := toklev[t] 2295 | if PLEVEL(lt) == 0 || PLEVEL(lp) == 0 { 2296 | // conflict 2297 | if foutput != nil { 2298 | fmt.Fprintf(foutput, 2299 | "\n%v: shift/reduce conflict (shift %v(%v), red'n %v(%v)) on %v", 2300 | s, temp1[t], PLEVEL(lt), r, PLEVEL(lp), symnam(t)) 2301 | } 2302 | zzsrconf++ 2303 | return 2304 | } 2305 | if PLEVEL(lt) == PLEVEL(lp) { 2306 | action = ASSOC(lt) 2307 | } else if PLEVEL(lt) > PLEVEL(lp) { 2308 | action = RASC // shift 2309 | } else { 2310 | action = LASC 2311 | } // reduce 2312 | switch action { 2313 | case BASC: // error action 2314 | temp1[t] = ERRCODE 2315 | case LASC: // reduce 2316 | temp1[t] = -r 2317 | } 2318 | } 2319 | 2320 | // 2321 | // output state i 2322 | // temp1 has the actions, lastred the default 2323 | // 2324 | func wract(i int) { 2325 | var p, p1 int 2326 | 2327 | // find the best choice for lastred 2328 | lastred = 0 2329 | ntimes := 0 2330 | for j := 0; j <= ntokens; j++ { 2331 | if temp1[j] >= 0 { 2332 | continue 2333 | } 2334 | if temp1[j]+lastred == 0 { 2335 | continue 2336 | } 2337 | // count the number of appearances of temp1[j] 2338 | count := 0 2339 | tred := -temp1[j] 2340 | levprd[tred] |= REDFLAG 2341 | for p = 0; p <= ntokens; p++ { 2342 | if temp1[p]+tred == 0 { 2343 | count++ 2344 | } 2345 | } 2346 | if count > ntimes { 2347 | lastred = tred 2348 | ntimes = count 2349 | } 2350 | } 2351 | 2352 | // 2353 | // for error recovery, arrange that, if there is a shift on the 2354 | // error recovery token, `error', that the default be the error action 2355 | // 2356 | if temp1[2] > 0 { 2357 | lastred = 0 2358 | } 2359 | 2360 | // clear out entries in temp1 which equal lastred 2361 | // count entries in optst table 2362 | n := 0 2363 | for p = 0; p <= ntokens; p++ { 2364 | p1 = temp1[p] 2365 | if p1+lastred == 0 { 2366 | temp1[p] = 0 2367 | p1 = 0 2368 | } 2369 | if p1 > 0 && p1 != ACCEPTCODE && p1 != ERRCODE { 2370 | n++ 2371 | } 2372 | } 2373 | 2374 | wrstate(i) 2375 | defact[i] = lastred 2376 | flag := 0 2377 | os := make([]int, n*2) 2378 | n = 0 2379 | for p = 0; p <= ntokens; p++ { 2380 | p1 = temp1[p] 2381 | if p1 != 0 { 2382 | if p1 < 0 { 2383 | p1 = -p1 2384 | } else if p1 == ACCEPTCODE { 2385 | p1 = -1 2386 | } else if p1 == ERRCODE { 2387 | p1 = 0 2388 | } else { 2389 | os[n] = p 2390 | n++ 2391 | os[n] = p1 2392 | n++ 2393 | zzacent++ 2394 | continue 2395 | } 2396 | if flag == 0 { 2397 | fmt.Fprintf(ftable, "\t-1, %v,\n", i) 2398 | } 2399 | flag++ 2400 | fmt.Fprintf(ftable, "\t%v, %v,\n", p, p1) 2401 | zzexcp++ 2402 | } 2403 | } 2404 | if flag != 0 { 2405 | defact[i] = -2 2406 | fmt.Fprintf(ftable, "\t-2, %v,\n", lastred) 2407 | } 2408 | optst[i] = os 2409 | } 2410 | 2411 | // 2412 | // writes state i 2413 | // 2414 | func wrstate(i int) { 2415 | var j0, j1, u int 2416 | var pp, qq int 2417 | 2418 | if len(errors) > 0 { 2419 | actions := append([]int(nil), temp1...) 2420 | defaultAction := ERRCODE 2421 | if lastred != 0 { 2422 | defaultAction = -lastred 2423 | } 2424 | stateTable[i] = Row{actions, defaultAction} 2425 | } 2426 | 2427 | if foutput == nil { 2428 | return 2429 | } 2430 | fmt.Fprintf(foutput, "\nstate %v\n", i) 2431 | qq = pstate[i+1] 2432 | for pp = pstate[i]; pp < qq; pp++ { 2433 | fmt.Fprintf(foutput, "\t%v\n", writem(statemem[pp].pitem)) 2434 | } 2435 | if tystate[i] == MUSTLOOKAHEAD { 2436 | // print out empty productions in closure 2437 | for u = pstate[i+1] - pstate[i]; u < cwp; u++ { 2438 | if wsets[u].pitem.first < 0 { 2439 | fmt.Fprintf(foutput, "\t%v\n", writem(wsets[u].pitem)) 2440 | } 2441 | } 2442 | } 2443 | 2444 | // check for state equal to another 2445 | for j0 = 0; j0 <= ntokens; j0++ { 2446 | j1 = temp1[j0] 2447 | if j1 != 0 { 2448 | fmt.Fprintf(foutput, "\n\t%v ", symnam(j0)) 2449 | 2450 | // shift, error, or accept 2451 | if j1 > 0 { 2452 | if j1 == ACCEPTCODE { 2453 | fmt.Fprintf(foutput, "accept") 2454 | } else if j1 == ERRCODE { 2455 | fmt.Fprintf(foutput, "error") 2456 | } else { 2457 | fmt.Fprintf(foutput, "shift %v", j1) 2458 | } 2459 | } else { 2460 | fmt.Fprintf(foutput, "reduce %v (src line %v)", -j1, rlines[-j1]) 2461 | } 2462 | } 2463 | } 2464 | 2465 | // output the final production 2466 | if lastred != 0 { 2467 | fmt.Fprintf(foutput, "\n\t. reduce %v (src line %v)\n\n", 2468 | lastred, rlines[lastred]) 2469 | } else { 2470 | fmt.Fprintf(foutput, "\n\t. error\n\n") 2471 | } 2472 | 2473 | // now, output nonterminal actions 2474 | j1 = ntokens 2475 | for j0 = 1; j0 <= nnonter; j0++ { 2476 | j1++ 2477 | if temp1[j1] != 0 { 2478 | fmt.Fprintf(foutput, "\t%v goto %v\n", symnam(j0+NTBASE), temp1[j1]) 2479 | } 2480 | } 2481 | } 2482 | 2483 | // 2484 | // output the gotos for the nontermninals 2485 | // 2486 | func go2out() { 2487 | for i := 1; i <= nnonter; i++ { 2488 | go2gen(i) 2489 | 2490 | // find the best one to make default 2491 | best := -1 2492 | times := 0 2493 | 2494 | // is j the most frequent 2495 | for j := 0; j < nstate; j++ { 2496 | if tystate[j] == 0 { 2497 | continue 2498 | } 2499 | if tystate[j] == best { 2500 | continue 2501 | } 2502 | 2503 | // is tystate[j] the most frequent 2504 | count := 0 2505 | cbest := tystate[j] 2506 | for k := j; k < nstate; k++ { 2507 | if tystate[k] == cbest { 2508 | count++ 2509 | } 2510 | } 2511 | if count > times { 2512 | best = cbest 2513 | times = count 2514 | } 2515 | } 2516 | 2517 | // best is now the default entry 2518 | zzgobest += times - 1 2519 | n := 0 2520 | for j := 0; j < nstate; j++ { 2521 | if tystate[j] != 0 && tystate[j] != best { 2522 | n++ 2523 | } 2524 | } 2525 | goent := make([]int, 2*n+1) 2526 | n = 0 2527 | for j := 0; j < nstate; j++ { 2528 | if tystate[j] != 0 && tystate[j] != best { 2529 | goent[n] = j 2530 | n++ 2531 | goent[n] = tystate[j] 2532 | n++ 2533 | zzgoent++ 2534 | } 2535 | } 2536 | 2537 | // now, the default 2538 | if best == -1 { 2539 | best = 0 2540 | } 2541 | 2542 | zzgoent++ 2543 | goent[n] = best 2544 | yypgo[i] = goent 2545 | } 2546 | } 2547 | 2548 | // 2549 | // output the gotos for nonterminal c 2550 | // 2551 | func go2gen(c int) { 2552 | var i, cc, p, q int 2553 | 2554 | // first, find nonterminals with gotos on c 2555 | aryfil(temp1, nnonter+1, 0) 2556 | temp1[c] = 1 2557 | work := 1 2558 | for work != 0 { 2559 | work = 0 2560 | for i = 0; i < nprod; i++ { 2561 | // cc is a nonterminal with a goto on c 2562 | cc = prdptr[i][1] - NTBASE 2563 | if cc >= 0 && temp1[cc] != 0 { 2564 | // thus, the left side of production i does too 2565 | cc = prdptr[i][0] - NTBASE 2566 | if temp1[cc] == 0 { 2567 | work = 1 2568 | temp1[cc] = 1 2569 | } 2570 | } 2571 | } 2572 | } 2573 | 2574 | // now, we have temp1[c] = 1 if a goto on c in closure of cc 2575 | if g2debug != 0 && foutput != nil { 2576 | fmt.Fprintf(foutput, "%v: gotos on ", nontrst[c].name) 2577 | for i = 0; i <= nnonter; i++ { 2578 | if temp1[i] != 0 { 2579 | fmt.Fprintf(foutput, "%v ", nontrst[i].name) 2580 | } 2581 | } 2582 | fmt.Fprintf(foutput, "\n") 2583 | } 2584 | 2585 | // now, go through and put gotos into tystate 2586 | aryfil(tystate, nstate, 0) 2587 | for i = 0; i < nstate; i++ { 2588 | q = pstate[i+1] 2589 | for p = pstate[i]; p < q; p++ { 2590 | cc = statemem[p].pitem.first 2591 | if cc >= NTBASE { 2592 | // goto on c is possible 2593 | if temp1[cc-NTBASE] != 0 { 2594 | tystate[i] = amem[indgo[i]+c] 2595 | break 2596 | } 2597 | } 2598 | } 2599 | } 2600 | } 2601 | 2602 | // 2603 | // in order to free up the mem and amem arrays for the optimizer, 2604 | // and still be able to output yyr1, etc., after the sizes of 2605 | // the action array is known, we hide the nonterminals 2606 | // derived by productions in levprd. 2607 | // 2608 | func hideprod() { 2609 | nred := 0 2610 | levprd[0] = 0 2611 | for i := 1; i < nprod; i++ { 2612 | if (levprd[i] & REDFLAG) == 0 { 2613 | if foutput != nil { 2614 | fmt.Fprintf(foutput, "Rule not reduced: %v\n", 2615 | writem(Pitem{prdptr[i], 0, 0, i})) 2616 | } 2617 | fmt.Printf("rule %v never reduced\n", writem(Pitem{prdptr[i], 0, 0, i})) 2618 | nred++ 2619 | } 2620 | levprd[i] = prdptr[i][0] - NTBASE 2621 | } 2622 | if nred != 0 { 2623 | fmt.Printf("%v rules never reduced\n", nred) 2624 | } 2625 | } 2626 | 2627 | func callopt() { 2628 | var j, k, p, q, i int 2629 | var v []int 2630 | 2631 | pgo = make([]int, nnonter+1) 2632 | pgo[0] = 0 2633 | maxoff = 0 2634 | maxspr = 0 2635 | for i = 0; i < nstate; i++ { 2636 | k = 32000 2637 | j = 0 2638 | v = optst[i] 2639 | q = len(v) 2640 | for p = 0; p < q; p += 2 { 2641 | if v[p] > j { 2642 | j = v[p] 2643 | } 2644 | if v[p] < k { 2645 | k = v[p] 2646 | } 2647 | } 2648 | 2649 | // nontrivial situation 2650 | if k <= j { 2651 | // j is now the range 2652 | // j -= k; // call scj 2653 | if k > maxoff { 2654 | maxoff = k 2655 | } 2656 | } 2657 | tystate[i] = q + 2*j 2658 | if j > maxspr { 2659 | maxspr = j 2660 | } 2661 | } 2662 | 2663 | // initialize ggreed table 2664 | ggreed = make([]int, nnonter+1) 2665 | for i = 1; i <= nnonter; i++ { 2666 | ggreed[i] = 1 2667 | j = 0 2668 | 2669 | // minimum entry index is always 0 2670 | v = yypgo[i] 2671 | q = len(v) - 1 2672 | for p = 0; p < q; p += 2 { 2673 | ggreed[i] += 2 2674 | if v[p] > j { 2675 | j = v[p] 2676 | } 2677 | } 2678 | ggreed[i] = ggreed[i] + 2*j 2679 | if j > maxoff { 2680 | maxoff = j 2681 | } 2682 | } 2683 | 2684 | // now, prepare to put the shift actions into the amem array 2685 | for i = 0; i < ACTSIZE; i++ { 2686 | amem[i] = 0 2687 | } 2688 | maxa = 0 2689 | for i = 0; i < nstate; i++ { 2690 | if tystate[i] == 0 && adb > 1 { 2691 | fmt.Fprintf(ftable, "State %v: null\n", i) 2692 | } 2693 | indgo[i] = yyFlag 2694 | } 2695 | 2696 | i = nxti() 2697 | for i != NOMORE { 2698 | if i >= 0 { 2699 | stin(i) 2700 | } else { 2701 | gin(-i) 2702 | } 2703 | i = nxti() 2704 | } 2705 | 2706 | // print amem array 2707 | if adb > 2 { 2708 | for p = 0; p <= maxa; p += 10 { 2709 | fmt.Fprintf(ftable, "%v ", p) 2710 | for i = 0; i < 10; i++ { 2711 | fmt.Fprintf(ftable, "%v ", amem[p+i]) 2712 | } 2713 | ftable.WriteRune('\n') 2714 | } 2715 | } 2716 | 2717 | aoutput() 2718 | osummary() 2719 | } 2720 | 2721 | // 2722 | // finds the next i 2723 | // 2724 | func nxti() int { 2725 | max := 0 2726 | maxi := 0 2727 | for i := 1; i <= nnonter; i++ { 2728 | if ggreed[i] >= max { 2729 | max = ggreed[i] 2730 | maxi = -i 2731 | } 2732 | } 2733 | for i := 0; i < nstate; i++ { 2734 | if tystate[i] >= max { 2735 | max = tystate[i] 2736 | maxi = i 2737 | } 2738 | } 2739 | if max == 0 { 2740 | return NOMORE 2741 | } 2742 | return maxi 2743 | } 2744 | 2745 | func gin(i int) { 2746 | var s int 2747 | 2748 | // enter gotos on nonterminal i into array amem 2749 | ggreed[i] = 0 2750 | 2751 | q := yypgo[i] 2752 | nq := len(q) - 1 2753 | 2754 | // now, find amem place for it 2755 | nextgp: 2756 | for p := 0; p < ACTSIZE; p++ { 2757 | if amem[p] != 0 { 2758 | continue 2759 | } 2760 | for r := 0; r < nq; r += 2 { 2761 | s = p + q[r] + 1 2762 | if s > maxa { 2763 | maxa = s 2764 | if maxa >= ACTSIZE { 2765 | errorf("a array overflow") 2766 | } 2767 | } 2768 | if amem[s] != 0 { 2769 | continue nextgp 2770 | } 2771 | } 2772 | 2773 | // we have found amem spot 2774 | amem[p] = q[nq] 2775 | if p > maxa { 2776 | maxa = p 2777 | } 2778 | for r := 0; r < nq; r += 2 { 2779 | s = p + q[r] + 1 2780 | amem[s] = q[r+1] 2781 | } 2782 | pgo[i] = p 2783 | if adb > 1 { 2784 | fmt.Fprintf(ftable, "Nonterminal %v, entry at %v\n", i, pgo[i]) 2785 | } 2786 | return 2787 | } 2788 | errorf("cannot place goto %v\n", i) 2789 | } 2790 | 2791 | func stin(i int) { 2792 | var s int 2793 | 2794 | tystate[i] = 0 2795 | 2796 | // enter state i into the amem array 2797 | q := optst[i] 2798 | nq := len(q) 2799 | 2800 | nextn: 2801 | // find an acceptable place 2802 | for n := -maxoff; n < ACTSIZE; n++ { 2803 | flag := 0 2804 | for r := 0; r < nq; r += 2 { 2805 | s = q[r] + n 2806 | if s < 0 || s > ACTSIZE { 2807 | continue nextn 2808 | } 2809 | if amem[s] == 0 { 2810 | flag++ 2811 | } else if amem[s] != q[r+1] { 2812 | continue nextn 2813 | } 2814 | } 2815 | 2816 | // check the position equals another only if the states are identical 2817 | for j := 0; j < nstate; j++ { 2818 | if indgo[j] == n { 2819 | 2820 | // we have some disagreement 2821 | if flag != 0 { 2822 | continue nextn 2823 | } 2824 | if nq == len(optst[j]) { 2825 | 2826 | // states are equal 2827 | indgo[i] = n 2828 | if adb > 1 { 2829 | fmt.Fprintf(ftable, "State %v: entry at"+ 2830 | "%v equals state %v\n", 2831 | i, n, j) 2832 | } 2833 | return 2834 | } 2835 | 2836 | // we have some disagreement 2837 | continue nextn 2838 | } 2839 | } 2840 | 2841 | for r := 0; r < nq; r += 2 { 2842 | s = q[r] + n 2843 | if s > maxa { 2844 | maxa = s 2845 | } 2846 | if amem[s] != 0 && amem[s] != q[r+1] { 2847 | errorf("clobber of a array, pos'n %v, by %v", s, q[r+1]) 2848 | } 2849 | amem[s] = q[r+1] 2850 | } 2851 | indgo[i] = n 2852 | if adb > 1 { 2853 | fmt.Fprintf(ftable, "State %v: entry at %v\n", i, indgo[i]) 2854 | } 2855 | return 2856 | } 2857 | errorf("Error; failure to place state %v", i) 2858 | } 2859 | 2860 | // 2861 | // this version is for limbo 2862 | // write out the optimized parser 2863 | // 2864 | func aoutput() { 2865 | ftable.WriteRune('\n') 2866 | fmt.Fprintf(ftable, "const %sLast = %v\n\n", prefix, maxa+1) 2867 | arout("Act", amem, maxa+1) 2868 | arout("Pact", indgo, nstate) 2869 | arout("Pgo", pgo, nnonter+1) 2870 | } 2871 | 2872 | // 2873 | // put out other arrays, copy the parsers 2874 | // 2875 | func others() { 2876 | var i, j int 2877 | 2878 | arout("R1", levprd, nprod) 2879 | aryfil(temp1, nprod, 0) 2880 | 2881 | // 2882 | //yyr2 is the number of rules for each production 2883 | // 2884 | for i = 1; i < nprod; i++ { 2885 | temp1[i] = len(prdptr[i]) - 2 2886 | } 2887 | arout("R2", temp1, nprod) 2888 | 2889 | aryfil(temp1, nstate, -1000) 2890 | for i = 0; i <= ntokens; i++ { 2891 | for j := tstates[i]; j != 0; j = mstates[j] { 2892 | temp1[j] = i 2893 | } 2894 | } 2895 | for i = 0; i <= nnonter; i++ { 2896 | for j = ntstates[i]; j != 0; j = mstates[j] { 2897 | temp1[j] = -i 2898 | } 2899 | } 2900 | arout("Chk", temp1, nstate) 2901 | arout("Def", defact, nstate) 2902 | 2903 | // put out token translation tables 2904 | // table 1 has 0-256 2905 | aryfil(temp1, 256, 0) 2906 | c := 0 2907 | for i = 1; i <= ntokens; i++ { 2908 | j = tokset[i].value 2909 | if j >= 0 && j < 256 { 2910 | if temp1[j] != 0 { 2911 | fmt.Print("yacc bug -- cannot have 2 different Ts with same value\n") 2912 | fmt.Printf(" %s and %s\n", tokset[i].name, tokset[temp1[j]].name) 2913 | nerrors++ 2914 | } 2915 | temp1[j] = i 2916 | if j > c { 2917 | c = j 2918 | } 2919 | } 2920 | } 2921 | for i = 0; i <= c; i++ { 2922 | if temp1[i] == 0 { 2923 | temp1[i] = YYLEXUNK 2924 | } 2925 | } 2926 | arout("Tok1", temp1, c+1) 2927 | 2928 | // table 2 has PRIVATE-PRIVATE+256 2929 | aryfil(temp1, 256, 0) 2930 | c = 0 2931 | for i = 1; i <= ntokens; i++ { 2932 | j = tokset[i].value - PRIVATE 2933 | if j >= 0 && j < 256 { 2934 | if temp1[j] != 0 { 2935 | fmt.Print("yacc bug -- cannot have 2 different Ts with same value\n") 2936 | fmt.Printf(" %s and %s\n", tokset[i].name, tokset[temp1[j]].name) 2937 | nerrors++ 2938 | } 2939 | temp1[j] = i 2940 | if j > c { 2941 | c = j 2942 | } 2943 | } 2944 | } 2945 | arout("Tok2", temp1, c+1) 2946 | 2947 | // table 3 has everything else 2948 | fmt.Fprintf(ftable, "var %sTok3 = [...]int{\n\t", prefix) 2949 | c = 0 2950 | for i = 1; i <= ntokens; i++ { 2951 | j = tokset[i].value 2952 | if j >= 0 && j < 256 { 2953 | continue 2954 | } 2955 | if j >= PRIVATE && j < 256+PRIVATE { 2956 | continue 2957 | } 2958 | 2959 | if c%5 != 0 { 2960 | ftable.WriteRune(' ') 2961 | } 2962 | fmt.Fprintf(ftable, "%d, %d,", j, i) 2963 | c++ 2964 | if c%5 == 0 { 2965 | fmt.Fprint(ftable, "\n\t") 2966 | } 2967 | } 2968 | if c%5 != 0 { 2969 | ftable.WriteRune(' ') 2970 | } 2971 | fmt.Fprintf(ftable, "%d,\n}\n", 0) 2972 | 2973 | // Custom error messages. 2974 | fmt.Fprintf(ftable, "\n") 2975 | fmt.Fprintf(ftable, "var %sErrorMessages = [...]struct {\n", prefix) 2976 | fmt.Fprintf(ftable, "\tstate int\n") 2977 | fmt.Fprintf(ftable, "\ttoken int\n") 2978 | fmt.Fprintf(ftable, "\tmsg string\n") 2979 | fmt.Fprintf(ftable, "}{\n") 2980 | for _, error := range errors { 2981 | lineno = error.lineno 2982 | state, token := runMachine(error.tokens) 2983 | fmt.Fprintf(ftable, "\t{%v, %v, %s},\n", state, token, error.msg) 2984 | } 2985 | fmt.Fprintf(ftable, "}\n") 2986 | 2987 | // copy parser text 2988 | ch := getrune(finput) 2989 | for ch != EOF { 2990 | ftable.WriteRune(ch) 2991 | ch = getrune(finput) 2992 | } 2993 | 2994 | // copy yaccpar 2995 | if !lflag { 2996 | fmt.Fprintf(ftable, "\n//line yaccpar:1\n") 2997 | } 2998 | 2999 | parts := strings.SplitN(yaccpar, prefix+"run()", 2) 3000 | fmt.Fprintf(ftable, "%v", parts[0]) 3001 | ftable.Write(fcode.Bytes()) 3002 | fmt.Fprintf(ftable, "%v", parts[1]) 3003 | } 3004 | 3005 | func runMachine(tokens []string) (state, token int) { 3006 | var stack []int 3007 | i := 0 3008 | token = -1 3009 | 3010 | Loop: 3011 | if token < 0 { 3012 | token = chfind(2, tokens[i]) 3013 | i++ 3014 | } 3015 | 3016 | row := stateTable[state] 3017 | 3018 | c := token 3019 | if token >= NTBASE { 3020 | c = token - NTBASE + ntokens 3021 | } 3022 | action := row.actions[c] 3023 | if action == 0 { 3024 | action = row.defaultAction 3025 | } 3026 | 3027 | switch { 3028 | case action == ACCEPTCODE: 3029 | errorf("tokens are accepted") 3030 | return 3031 | case action == ERRCODE: 3032 | if token >= NTBASE { 3033 | errorf("error at non-terminal token %s", symnam(token)) 3034 | } 3035 | return 3036 | case action > 0: 3037 | // Shift to state action. 3038 | stack = append(stack, state) 3039 | state = action 3040 | token = -1 3041 | goto Loop 3042 | default: 3043 | // Reduce by production -action. 3044 | prod := prdptr[-action] 3045 | if rhsLen := len(prod) - 2; rhsLen > 0 { 3046 | n := len(stack) - rhsLen 3047 | state = stack[n] 3048 | stack = stack[:n] 3049 | } 3050 | if token >= 0 { 3051 | i-- 3052 | } 3053 | token = prod[0] 3054 | goto Loop 3055 | } 3056 | } 3057 | 3058 | func arout(s string, v []int, n int) { 3059 | s = prefix + s 3060 | fmt.Fprintf(ftable, "var %v = [...]int{\n", s) 3061 | for i := 0; i < n; i++ { 3062 | if i%10 == 0 { 3063 | fmt.Fprintf(ftable, "\n\t") 3064 | } else { 3065 | ftable.WriteRune(' ') 3066 | } 3067 | fmt.Fprintf(ftable, "%d,", v[i]) 3068 | } 3069 | fmt.Fprintf(ftable, "\n}\n") 3070 | } 3071 | 3072 | // 3073 | // output the summary on y.output 3074 | // 3075 | func summary() { 3076 | if foutput != nil { 3077 | fmt.Fprintf(foutput, "\n%v terminals, %v nonterminals\n", ntokens, nnonter+1) 3078 | fmt.Fprintf(foutput, "%v grammar rules, %v/%v states\n", nprod, nstate, NSTATES) 3079 | fmt.Fprintf(foutput, "%v shift/reduce, %v reduce/reduce conflicts reported\n", zzsrconf, zzrrconf) 3080 | fmt.Fprintf(foutput, "%v working sets used\n", len(wsets)) 3081 | fmt.Fprintf(foutput, "memory: parser %v/%v\n", memp, ACTSIZE) 3082 | fmt.Fprintf(foutput, "%v extra closures\n", zzclose-2*nstate) 3083 | fmt.Fprintf(foutput, "%v shift entries, %v exceptions\n", zzacent, zzexcp) 3084 | fmt.Fprintf(foutput, "%v goto entries\n", zzgoent) 3085 | fmt.Fprintf(foutput, "%v entries saved by goto default\n", zzgobest) 3086 | } 3087 | if zzsrconf != 0 || zzrrconf != 0 { 3088 | fmt.Printf("\nconflicts: ") 3089 | if zzsrconf != 0 { 3090 | fmt.Printf("%v shift/reduce", zzsrconf) 3091 | } 3092 | if zzsrconf != 0 && zzrrconf != 0 { 3093 | fmt.Printf(", ") 3094 | } 3095 | if zzrrconf != 0 { 3096 | fmt.Printf("%v reduce/reduce", zzrrconf) 3097 | } 3098 | fmt.Printf("\n") 3099 | } 3100 | } 3101 | 3102 | // 3103 | // write optimizer summary 3104 | // 3105 | func osummary() { 3106 | if foutput == nil { 3107 | return 3108 | } 3109 | i := 0 3110 | for p := maxa; p >= 0; p-- { 3111 | if amem[p] == 0 { 3112 | i++ 3113 | } 3114 | } 3115 | 3116 | fmt.Fprintf(foutput, "Optimizer space used: output %v/%v\n", maxa+1, ACTSIZE) 3117 | fmt.Fprintf(foutput, "%v table entries, %v zero\n", maxa+1, i) 3118 | fmt.Fprintf(foutput, "maximum spread: %v, maximum offset: %v\n", maxspr, maxoff) 3119 | } 3120 | 3121 | // 3122 | // copies and protects "'s in q 3123 | // 3124 | func chcopy(q string) string { 3125 | s := "" 3126 | i := 0 3127 | j := 0 3128 | for i = 0; i < len(q); i++ { 3129 | if q[i] == '"' { 3130 | s += q[j:i] + "\\" 3131 | j = i 3132 | } 3133 | } 3134 | return s + q[j:i] 3135 | } 3136 | 3137 | func usage() { 3138 | fmt.Fprintf(stderr, "usage: yacc [-o output] [-v parsetable] input\n") 3139 | exit(1) 3140 | } 3141 | 3142 | func bitset(set Lkset, bit int) int { return set[bit>>5] & (1 << uint(bit&31)) } 3143 | 3144 | func setbit(set Lkset, bit int) { set[bit>>5] |= (1 << uint(bit&31)) } 3145 | 3146 | func mkset() Lkset { return make([]int, tbitset) } 3147 | 3148 | // 3149 | // set a to the union of a and b 3150 | // return 1 if b is not a subset of a, 0 otherwise 3151 | // 3152 | func setunion(a, b []int) int { 3153 | sub := 0 3154 | for i := 0; i < tbitset; i++ { 3155 | x := a[i] 3156 | y := x | b[i] 3157 | a[i] = y 3158 | if y != x { 3159 | sub = 1 3160 | } 3161 | } 3162 | return sub 3163 | } 3164 | 3165 | func prlook(p Lkset) { 3166 | if p == nil { 3167 | fmt.Fprintf(foutput, "\tNULL") 3168 | return 3169 | } 3170 | fmt.Fprintf(foutput, " { ") 3171 | for j := 0; j <= ntokens; j++ { 3172 | if bitset(p, j) != 0 { 3173 | fmt.Fprintf(foutput, "%v ", symnam(j)) 3174 | } 3175 | } 3176 | fmt.Fprintf(foutput, "}") 3177 | } 3178 | 3179 | // 3180 | // utility routines 3181 | // 3182 | var peekrune rune 3183 | 3184 | func isdigit(c rune) bool { return c >= '0' && c <= '9' } 3185 | 3186 | func isword(c rune) bool { 3187 | return c >= 0xa0 || c == '_' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') 3188 | } 3189 | 3190 | // 3191 | // return 1 if 2 arrays are equal 3192 | // return 0 if not equal 3193 | // 3194 | func aryeq(a []int, b []int) int { 3195 | n := len(a) 3196 | if len(b) != n { 3197 | return 0 3198 | } 3199 | for ll := 0; ll < n; ll++ { 3200 | if a[ll] != b[ll] { 3201 | return 0 3202 | } 3203 | } 3204 | return 1 3205 | } 3206 | 3207 | func getrune(f *bufio.Reader) rune { 3208 | var r rune 3209 | 3210 | if peekrune != 0 { 3211 | if peekrune == EOF { 3212 | return EOF 3213 | } 3214 | r = peekrune 3215 | peekrune = 0 3216 | return r 3217 | } 3218 | 3219 | c, n, err := f.ReadRune() 3220 | if n == 0 { 3221 | return EOF 3222 | } 3223 | if err != nil { 3224 | errorf("read error: %v", err) 3225 | } 3226 | //fmt.Printf("rune = %v n=%v\n", string(c), n); 3227 | return c 3228 | } 3229 | 3230 | func ungetrune(f *bufio.Reader, c rune) { 3231 | if f != finput { 3232 | panic("ungetc - not finput") 3233 | } 3234 | if peekrune != 0 { 3235 | panic("ungetc - 2nd unget") 3236 | } 3237 | peekrune = c 3238 | } 3239 | 3240 | func write(f *bufio.Writer, b []byte, n int) int { 3241 | panic("write") 3242 | } 3243 | 3244 | func open(s string) *bufio.Reader { 3245 | fi, err := os.Open(s) 3246 | if err != nil { 3247 | errorf("error opening %v: %v", s, err) 3248 | } 3249 | //fmt.Printf("open %v\n", s); 3250 | return bufio.NewReader(fi) 3251 | } 3252 | 3253 | func create(s string) *bufio.Writer { 3254 | fo, err := os.Create(s) 3255 | if err != nil { 3256 | errorf("error creating %v: %v", s, err) 3257 | } 3258 | //fmt.Printf("create %v mode %v\n", s); 3259 | return bufio.NewWriter(fo) 3260 | } 3261 | 3262 | // 3263 | // write out error comment 3264 | // 3265 | func lerrorf(lineno int, s string, v ...interface{}) { 3266 | nerrors++ 3267 | fmt.Fprintf(stderr, s, v...) 3268 | fmt.Fprintf(stderr, ": %v:%v\n", infile, lineno) 3269 | if fatfl != 0 { 3270 | summary() 3271 | exit(1) 3272 | } 3273 | } 3274 | 3275 | func errorf(s string, v ...interface{}) { 3276 | lerrorf(lineno, s, v...) 3277 | } 3278 | 3279 | func exit(status int) { 3280 | if ftable != nil { 3281 | ftable.Flush() 3282 | ftable = nil 3283 | gofmt() 3284 | } 3285 | if foutput != nil { 3286 | foutput.Flush() 3287 | foutput = nil 3288 | } 3289 | if stderr != nil { 3290 | stderr.Flush() 3291 | stderr = nil 3292 | } 3293 | os.Exit(status) 3294 | } 3295 | 3296 | func gofmt() { 3297 | src, err := ioutil.ReadFile(oflag) 3298 | if err != nil { 3299 | return 3300 | } 3301 | src, err = format.Source(src) 3302 | if err != nil { 3303 | return 3304 | } 3305 | ioutil.WriteFile(oflag, src, 0666) 3306 | } 3307 | 3308 | var yaccpar string // will be processed version of yaccpartext: s/$$/prefix/g 3309 | var yaccpartext = ` 3310 | /* parser for yacc output */ 3311 | 3312 | var ( 3313 | $$Debug = 0 3314 | $$ErrorVerbose = false 3315 | ) 3316 | 3317 | type $$Lexer interface { 3318 | Lex(lval *$$SymType) int 3319 | Error(s string) 3320 | } 3321 | 3322 | type $$Parser interface { 3323 | Parse($$Lexer) int 3324 | Lookahead() int 3325 | } 3326 | 3327 | type $$ParserImpl struct { 3328 | lval $$SymType 3329 | stack [$$InitialStackSize]$$SymType 3330 | char int 3331 | } 3332 | 3333 | func (p *$$ParserImpl) Lookahead() int { 3334 | return p.char 3335 | } 3336 | 3337 | func $$NewParser() $$Parser { 3338 | return &$$ParserImpl{} 3339 | } 3340 | 3341 | const $$Flag = -1000 3342 | 3343 | func $$Tokname(c int) string { 3344 | if c >= 1 && c-1 < len($$Toknames) { 3345 | if $$Toknames[c-1] != "" { 3346 | return $$Toknames[c-1] 3347 | } 3348 | } 3349 | return __yyfmt__.Sprintf("tok-%v", c) 3350 | } 3351 | 3352 | func $$Statname(s int) string { 3353 | if s >= 0 && s < len($$Statenames) { 3354 | if $$Statenames[s] != "" { 3355 | return $$Statenames[s] 3356 | } 3357 | } 3358 | return __yyfmt__.Sprintf("state-%v", s) 3359 | } 3360 | 3361 | func $$ErrorMessage(state, lookAhead int) string { 3362 | const TOKSTART = 4 3363 | 3364 | if !$$ErrorVerbose { 3365 | return "syntax error" 3366 | } 3367 | 3368 | for _, e := range $$ErrorMessages { 3369 | if e.state == state && e.token == lookAhead { 3370 | return "syntax error: " + e.msg 3371 | } 3372 | } 3373 | 3374 | res := "syntax error: unexpected " + $$Tokname(lookAhead) 3375 | 3376 | // To match Bison, suggest at most four expected tokens. 3377 | expected := make([]int, 0, 4) 3378 | 3379 | // Look for shiftable tokens. 3380 | base := $$Pact[state] 3381 | for tok := TOKSTART; tok-1 < len($$Toknames); tok++ { 3382 | if n := base + tok; n >= 0 && n < $$Last && $$Chk[$$Act[n]] == tok { 3383 | if len(expected) == cap(expected) { 3384 | return res 3385 | } 3386 | expected = append(expected, tok) 3387 | } 3388 | } 3389 | 3390 | if $$Def[state] == -2 { 3391 | i := 0 3392 | for $$Exca[i] != -1 || $$Exca[i+1] != state { 3393 | i += 2 3394 | } 3395 | 3396 | // Look for tokens that we accept or reduce. 3397 | for i += 2; $$Exca[i] >= 0; i += 2 { 3398 | tok := $$Exca[i] 3399 | if tok < TOKSTART || $$Exca[i+1] == 0 { 3400 | continue 3401 | } 3402 | if len(expected) == cap(expected) { 3403 | return res 3404 | } 3405 | expected = append(expected, tok) 3406 | } 3407 | 3408 | // If the default action is to accept or reduce, give up. 3409 | if $$Exca[i+1] != 0 { 3410 | return res 3411 | } 3412 | } 3413 | 3414 | for i, tok := range expected { 3415 | if i == 0 { 3416 | res += ", expecting " 3417 | } else { 3418 | res += " or " 3419 | } 3420 | res += $$Tokname(tok) 3421 | } 3422 | return res 3423 | } 3424 | 3425 | func $$lex1(lex $$Lexer, lval *$$SymType) (char, token int) { 3426 | token = 0 3427 | char = lex.Lex(lval) 3428 | if char <= 0 { 3429 | token = $$Tok1[0] 3430 | goto out 3431 | } 3432 | if char < len($$Tok1) { 3433 | token = $$Tok1[char] 3434 | goto out 3435 | } 3436 | if char >= $$Private { 3437 | if char < $$Private+len($$Tok2) { 3438 | token = $$Tok2[char-$$Private] 3439 | goto out 3440 | } 3441 | } 3442 | for i := 0; i < len($$Tok3); i += 2 { 3443 | token = $$Tok3[i+0] 3444 | if token == char { 3445 | token = $$Tok3[i+1] 3446 | goto out 3447 | } 3448 | } 3449 | 3450 | out: 3451 | if token == 0 { 3452 | token = $$Tok2[1] /* unknown char */ 3453 | } 3454 | if $$Debug >= 3 { 3455 | __yyfmt__.Printf("lex %s(%d)\n", $$Tokname(token), uint(char)) 3456 | } 3457 | return char, token 3458 | } 3459 | 3460 | func $$Parse($$lex $$Lexer) int { 3461 | return $$NewParser().Parse($$lex) 3462 | } 3463 | 3464 | func ($$rcvr *$$ParserImpl) Parse($$lex $$Lexer) int { 3465 | var $$n int 3466 | var $$VAL $$SymType 3467 | var $$Dollar []$$SymType 3468 | _ = $$Dollar // silence set and not used 3469 | $$S := $$rcvr.stack[:] 3470 | 3471 | Nerrs := 0 /* number of errors */ 3472 | Errflag := 0 /* error recovery flag */ 3473 | $$state := 0 3474 | $$rcvr.char = -1 3475 | $$token := -1 // $$rcvr.char translated into internal numbering 3476 | defer func() { 3477 | // Make sure we report no lookahead when not parsing. 3478 | $$state = -1 3479 | $$rcvr.char = -1 3480 | $$token = -1 3481 | }() 3482 | $$p := -1 3483 | goto $$stack 3484 | 3485 | ret0: 3486 | return 0 3487 | 3488 | ret1: 3489 | return 1 3490 | 3491 | $$stack: 3492 | /* put a state and value onto the stack */ 3493 | if $$Debug >= 4 { 3494 | __yyfmt__.Printf("char %v in %v\n", $$Tokname($$token), $$Statname($$state)) 3495 | } 3496 | 3497 | $$p++ 3498 | if $$p >= len($$S) { 3499 | nyys := make([]$$SymType, len($$S)*2) 3500 | copy(nyys, $$S) 3501 | $$S = nyys 3502 | } 3503 | $$S[$$p] = $$VAL 3504 | $$S[$$p].yys = $$state 3505 | 3506 | $$newstate: 3507 | $$n = $$Pact[$$state] 3508 | if $$n <= $$Flag { 3509 | goto $$default /* simple state */ 3510 | } 3511 | if $$rcvr.char < 0 { 3512 | $$rcvr.char, $$token = $$lex1($$lex, &$$rcvr.lval) 3513 | } 3514 | $$n += $$token 3515 | if $$n < 0 || $$n >= $$Last { 3516 | goto $$default 3517 | } 3518 | $$n = $$Act[$$n] 3519 | if $$Chk[$$n] == $$token { /* valid shift */ 3520 | $$rcvr.char = -1 3521 | $$token = -1 3522 | $$VAL = $$rcvr.lval 3523 | $$state = $$n 3524 | if Errflag > 0 { 3525 | Errflag-- 3526 | } 3527 | goto $$stack 3528 | } 3529 | 3530 | $$default: 3531 | /* default state action */ 3532 | $$n = $$Def[$$state] 3533 | if $$n == -2 { 3534 | if $$rcvr.char < 0 { 3535 | $$rcvr.char, $$token = $$lex1($$lex, &$$rcvr.lval) 3536 | } 3537 | 3538 | /* look through exception table */ 3539 | xi := 0 3540 | for { 3541 | if $$Exca[xi+0] == -1 && $$Exca[xi+1] == $$state { 3542 | break 3543 | } 3544 | xi += 2 3545 | } 3546 | for xi += 2; ; xi += 2 { 3547 | $$n = $$Exca[xi+0] 3548 | if $$n < 0 || $$n == $$token { 3549 | break 3550 | } 3551 | } 3552 | $$n = $$Exca[xi+1] 3553 | if $$n < 0 { 3554 | goto ret0 3555 | } 3556 | } 3557 | if $$n == 0 { 3558 | /* error ... attempt to resume parsing */ 3559 | switch Errflag { 3560 | case 0: /* brand new error */ 3561 | $$lex.Error($$ErrorMessage($$state, $$token)) 3562 | Nerrs++ 3563 | if $$Debug >= 1 { 3564 | __yyfmt__.Printf("%s", $$Statname($$state)) 3565 | __yyfmt__.Printf(" saw %s\n", $$Tokname($$token)) 3566 | } 3567 | fallthrough 3568 | 3569 | case 1, 2: /* incompletely recovered error ... try again */ 3570 | Errflag = 3 3571 | 3572 | /* find a state where "error" is a legal shift action */ 3573 | for $$p >= 0 { 3574 | $$n = $$Pact[$$S[$$p].yys] + $$ErrCode 3575 | if $$n >= 0 && $$n < $$Last { 3576 | $$state = $$Act[$$n] /* simulate a shift of "error" */ 3577 | if $$Chk[$$state] == $$ErrCode { 3578 | goto $$stack 3579 | } 3580 | } 3581 | 3582 | /* the current p has no shift on "error", pop stack */ 3583 | if $$Debug >= 2 { 3584 | __yyfmt__.Printf("error recovery pops state %d\n", $$S[$$p].yys) 3585 | } 3586 | $$p-- 3587 | } 3588 | /* there is no state on the stack with an error shift ... abort */ 3589 | goto ret1 3590 | 3591 | case 3: /* no shift yet; clobber input char */ 3592 | if $$Debug >= 2 { 3593 | __yyfmt__.Printf("error recovery discards %s\n", $$Tokname($$token)) 3594 | } 3595 | if $$token == $$EofCode { 3596 | goto ret1 3597 | } 3598 | $$rcvr.char = -1 3599 | $$token = -1 3600 | goto $$newstate /* try again in the same state */ 3601 | } 3602 | } 3603 | 3604 | /* reduction by production $$n */ 3605 | if $$Debug >= 2 { 3606 | __yyfmt__.Printf("reduce %v in:\n\t%v\n", $$n, $$Statname($$state)) 3607 | } 3608 | 3609 | $$nt := $$n 3610 | $$pt := $$p 3611 | _ = $$pt // guard against "declared and not used" 3612 | 3613 | $$p -= $$R2[$$n] 3614 | // $$p is now the index of $0. Perform the default action. Iff the 3615 | // reduced production is ε, $1 is possibly out of range. 3616 | if $$p+1 >= len($$S) { 3617 | nyys := make([]$$SymType, len($$S)*2) 3618 | copy(nyys, $$S) 3619 | $$S = nyys 3620 | } 3621 | $$VAL = $$S[$$p+1] 3622 | 3623 | /* consult goto table to find next state */ 3624 | $$n = $$R1[$$n] 3625 | $$g := $$Pgo[$$n] 3626 | $$j := $$g + $$S[$$p].yys + 1 3627 | 3628 | if $$j >= $$Last { 3629 | $$state = $$Act[$$g] 3630 | } else { 3631 | $$state = $$Act[$$j] 3632 | if $$Chk[$$state] != -$$n { 3633 | $$state = $$Act[$$g] 3634 | } 3635 | } 3636 | // dummy call; replaced with literal code 3637 | $$run() 3638 | goto $$stack /* stack new state and value */ 3639 | } 3640 | ` 3641 | --------------------------------------------------------------------------------