summaryrefslogtreecommitdiff
path: root/src/cmd/yacc
diff options
context:
space:
mode:
authorRob Pike <r@golang.org>2012-01-29 09:19:05 -0800
committerRob Pike <r@golang.org>2012-01-29 09:19:05 -0800
commite783e9ee47804dbd6d8d48a0b99570060b478231 (patch)
tree054a496d4b2500a4f558091fab9c3ffc7c4dab00 /src/cmd/yacc
parent1fd238ff924cd14f34773ad4c9983b19347dd4d3 (diff)
downloadgo-e783e9ee47804dbd6d8d48a0b99570060b478231.tar.gz
cmd/go: first piece of tool rearrangement
1) create go-tool dir in make.bash 2) clean up stale binaries in make.bash 3) add 'tool' command to go 4) convert goyacc->yacc as a first test tool Since goyacc stands alone, it's a safe trial. R=rsc CC=golang-dev http://codereview.appspot.com/5576061
Diffstat (limited to 'src/cmd/yacc')
-rw-r--r--src/cmd/yacc/Makefile18
-rw-r--r--src/cmd/yacc/doc.go48
-rw-r--r--src/cmd/yacc/units.txt576
-rw-r--r--src/cmd/yacc/units.y759
-rw-r--r--src/cmd/yacc/yacc.go3324
5 files changed, 4725 insertions, 0 deletions
diff --git a/src/cmd/yacc/Makefile b/src/cmd/yacc/Makefile
new file mode 100644
index 000000000..6ce9d54fb
--- /dev/null
+++ b/src/cmd/yacc/Makefile
@@ -0,0 +1,18 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=yacc
+GOFILES=\
+ yacc.go\
+
+include ../../Make.tool
+
+units: yacc units.y
+ ./yacc -p units_ units.y
+ $(GC) $(GCFLAGS) $(GCIMPORTS) y.go
+ $(LD) -o units y.$O
+
+CLEANFILES += units y.go y.output
diff --git a/src/cmd/yacc/doc.go b/src/cmd/yacc/doc.go
new file mode 100644
index 000000000..9874a2ae2
--- /dev/null
+++ b/src/cmd/yacc/doc.go
@@ -0,0 +1,48 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+
+Yacc is a version of yacc for Go. It is run with the command
+ go tool yacc args...
+It is written in Go and generates parsers written in Go.
+
+It is largely transliterated from the Inferno version written in Limbo
+which in turn was largely transliterated from the Plan 9 version
+written in C and documented at
+
+ http://plan9.bell-labs.com/magic/man2html/1/yacc
+
+Adepts of the original yacc will have no trouble adapting to this
+form of the tool.
+
+The file units.y in this directory is a yacc grammar for a version of
+the Unix tool units, also written in Go and largely transliterated
+from the Plan 9 C version. It needs the flag "-p units_" (see
+below).
+
+The generated parser is reentrant. Parse expects to be given an
+argument that conforms to the following interface:
+
+ type yyLexer interface {
+ Lex(lval *yySymType) int
+ Error(e string)
+ }
+
+Lex should return the token identifier, and place other token
+information in lval (which replaces the usual yylval).
+Error is equivalent to yyerror in the original yacc.
+
+Code inside the parser may refer to the variable yylex,
+which holds the yyLexer passed to Parse.
+
+Multiple grammars compiled into a single program should be placed in
+distinct packages. If that is impossible, the "-p prefix" flag to
+yacc sets the prefix, by default yy, that begins the names of
+symbols, including types, the parser, and the lexer, generated and
+referenced by yacc's generated code. Setting it to distinct values
+allows multiple grammars to be placed in a single package.
+
+*/
+package documentation
diff --git a/src/cmd/yacc/units.txt b/src/cmd/yacc/units.txt
new file mode 100644
index 000000000..ddb2bc294
--- /dev/null
+++ b/src/cmd/yacc/units.txt
@@ -0,0 +1,576 @@
+/ Plan 9's /lib/units
+/ http://plan9.bell-labs.com/sources/plan9/lib/units
+/
+/ Copyright (C) 2003, Lucent Technologies Inc. and others. All Rights Reserved.
+/ Distributed under the terms of the Lucent Public License Version 1.02
+/ See http://plan9.bell-labs.com/plan9/license.html
+/
+/order of evaluation
+/ + -
+/ * /
+/ juxtaposition (meaning *)
+/ ¹ ² ³ ^
+/ | (meaning /)
+/ name number ()
+
+/dimensions
+m #
+kg #
+sec #
+coul #
+candela #
+$ #
+radian #
+bit #
+erlang #
+°K #
+°C #
+°F #
+
+/constants
+
+π 3.14159265358979323846
+pi π
+c 2.997925e+8 m/sec
+g 9.80665 m/sec²
+au 1.49597871e+11 m
+mole 6.022169e+23
+e 1.6021917e-19 coul
+energy c²
+force g
+mercury 1.33322e+5 kg/m²sec²
+hg mercury
+h 6.62620e-34 m²kg/sec
+ℏ h/2 π
+hbar ℏ
+nonillion 1e30
+octillion 1e27
+septillion 1e24
+sextillion 1e21
+pentillion 1e18
+quadrillion 1e15
+trillion 1e12
+billion 1e9
+million 1e6
+thousand 1e3
+hundred 1e2
+
+/dimensionless
+
+° 1|180 π radian
+degree °
+circle 2 π radian
+turn 2 π radian
+grad .9 °
+arcdeg 1 °
+arcmin 1|60 °
+arcsec 1|3600 °
+ccs 1|36 erlang
+
+steradian radian²
+sphere 4 π steradian
+sr steradian
+giga 1024 1024 1024
+
+/Time
+
+second sec
+s sec
+minute 60 sec
+min minute
+hour 60 min
+hr hour
+day 24 hr
+da day
+week 7 day
+year 365.24219879 day
+yr year
+month 1|12 year
+ms millisec
+us microsec
+
+/Mass
+
+gram millikg
+gm gram
+mg milligram
+metricton kilokg
+
+/Avoirdupois
+
+lb .45359237 kg
+lbf lb g
+pound lb
+ounce 1|16 lb
+oz ounce
+dram 1|16 oz
+dr dram
+grain 1|7000 lb
+gr grain
+shortton 2000 lb
+ton shortton
+longton 2240 lb
+
+/Apothecary
+
+scruple 20 grain
+apdram 60 grain
+apounce 480 grain
+troyounce apounce
+appound 5760 grain
+troypound appound
+
+/Length
+
+meter m
+cm centimeter
+mm millimeter
+km kilometer
+nm nanometer
+micron micrometer
+µ micrometer
+Å decinanometer
+angstrom Å
+
+inch 2.54 cm
+" inch
+in inch
+inches inch
+' 12"
+foot 12 in
+feet foot
+ft foot
+yard 3 ft
+yd yard
+rod 5.5 yd
+rd rod
+mile 5280 ft
+mi mile
+
+british 1200|3937 m/ft
+nmile 1852 m
+
+acre 4840 yd²
+
+cc cm³
+liter kilocc
+ml milliliter
+
+/US Liquid
+
+gallon 231 in³
+imperial 1.20095
+epa 0.8
+gal gallon
+quart 1|4 gal
+qt quart
+pint 1|2 qt
+pt pint
+
+floz 1|16 pt
+fldr 1|8 floz
+
+/US Dry
+
+dry 268.8025 in³/gallon
+peck 8 dry quart
+pk peck
+bushel 4 peck
+bu bushel
+
+/British
+
+brgallon 277.420 in³
+brquart 1|4 brgallon
+brpint 1|2 brquart
+brfloz 1|20 brpint
+brpeck 554.84 in³
+brbushel 4 brpeck
+
+/Energy Work
+
+newton kg m/sec²
+nt newton
+joule nt m
+cal 4.1868 joule
+
+/Electrical
+
+coulomb coul
+ampere coul/sec
+amp ampere
+watt joule/sec
+volt watt/amp
+Ω volt/amp
+ohm Ω
+mho 1/Ω
+farad coul/volt
+henry sec²/farad
+weber volt sec
+
+/Light
+
+cd candela
+lumen cd sr
+lux cd sr/m²
+
+/ MONEY DATE
+/ Thu Sep 10 2009
+
+argentinapeso 1 | 0.2595 $
+australiadollar 1 | 0.8618 $
+boliviaboliviano 1 | 0.1425 $
+brazilreal 1 | 0.5522 $
+britainpound 1 | 1.6651 $
+canadadollar 1 | 0.9277 $
+chilepeso 1 | 0.0018 $
+chinayuan 1 | 0.1464 $
+colombiapeso 1 | 0.0005 $
+czechkoruna 1 | 0.0572 $
+denmarkkrone 1 | 0.1958 $
+dominicanpeso 1 | 0.0278 $
+egyptpound 1 | 0.181 $
+elsalvadorcolon 1 | 0.1143 $
+europeuro 1 | 1.4577 $
+guatemalaquetzal 1 | 0.121 $
+honduraslempira 1 | 0.0529 $
+hongkongdollar 1 | 0.129 $
+hungaryforint 1 | 0.0054 $
+indiarupee 1 | 0.0207 $
+indonesiarupiah 1 | 0.0001 $
+israelshekel 1 | 0.2643 $
+japanyen 1 | 0.0109 $
+kenyashilling 1 | 0.0132 $
+kuwaitdinar 1 | 3.4854 $
+lebanonpound 1 | 0.0007 $
+malaysiaringgit 1 | 0.286 $
+mexicopeso 1 | 0.0748 $
+newzealanddollar 1 | 0.7028 $
+nicaraguacordoba 1 | 0.0487 $
+norwaykrone 1 | 0.1681 $
+pakistanrupee 1 | 0.0121 $
+paraguayguarani 1 | 0.0002 $
+perunewsol 1 | 0.3384 $
+philippinespeso 1 | 0.0207 $
+polandzloty 1 | 0.352 $
+russiaruble 1 | 0.0324 $
+saudiarabiariyal 1 | 0.2666 $
+singaporedollar 1 | 0.7018 $
+slovakkoruna 1 | 0.0484 $
+southafricarand 1 | 0.132 $
+southkoreawon 1 | 0.0008 $
+swedenkrona 1 | 0.1429 $
+switzerlandfranc 1 | 0.9627 $
+taiwandollar 1 | 0.0306 $
+thailandbaht 1 | 0.0294 $
+turkeynewlira 1 | 0.6678 $
+uaedirham 1 | 0.2722 $
+uruguaynewpeso 1 | 0.0451 $
+vietnamdong 1 | 0.0001 $
+
+/ END MONEY
+
+€ europeuro
+£ britainpound
+¥ japanyen
+dollar $
+
+baht thailandbaht
+brpound britainpound
+dirham uaedirham
+euro europeuro
+forint hungaryforint
+krona swedenkrona
+peso mexicopeso
+rand southafricarand
+real brazilreal
+yuan chinayuan
+ringgit malaysiaringgit
+riyal saudiarabiariyal
+ruble russiaruble
+rupee indiarupee
+rupiah indonesiarupiah
+shekel israelshekel
+sol perunewsol
+won southkoreawon
+yen japanyen
+zloty polandzloty
+
+usdollar dollar
+sterling britainpound | pound
+poundsterling britainpound
+
+/bits
+
+baud bit/sec
+byte 8 bit
+short 2 byte
+long 4 byte
+vlong 8 bytes
+frame 2352 byte
+
+/Australian liquid measure
+
+pony 7 brfloz
+midie 10 brfloz
+pot midie
+handle midie
+schooner 15 brfloz
+jug 40 brfloz
+resch midie
+alf midie
+tinny 13 brfloz
+stubby tinny
+twisty 250 ml
+longneck 2 tinny
+slab 24 tinny
+sixpack 6 tinny
+nip brfloz
+
+/wine
+winebottle 750 ml
+balthazar 16 winebottle
+jeroboam 4 winebottle
+magnum 2 winebottle
+mathusalem 8 winebottle
+methuselah 8 winebottle
+nebuchadnezzar 20 winebottle
+rehoboam 6 winebottle
+salmanazar 12 winebottle
+split 0.25 winebottle
+jigger 1.5 floz
+
+/Trivia
+
+% 1|100
+admiraltyknot 6080 ft/hr
+ε₀ (1e-9/36π) farad/m
+α (1/4π ε₀) e²/ℏ c
+alpha α
+apostilb cd/π m²
+are 1e+2 m²
+arpentcan 27.52 mi
+arpentlin 191.835 ft
+astronomicalunit au
+atmosphere 1.01325e+5 nt/m²
+atm atmosphere
+atomicmassunit 1.66044e-27 kg
+amu atomicmassunit
+bag 94 lb
+bakersdozen 13
+bar 1e+5 nt/m²
+barie 1e-1 nt/m²
+barleycorn 1|3 in
+barn 1e-28 m²
+barrel 42 gal
+barye 1e-1 nt/m²
+bev 1e+9 e volt
+biot 10 amp
+blondel cd/π m²
+boardfoot 144 in³
+bolt 40 yd
+bottommeasure 1|40 in
+britishthermalunit 1.05506e+3 joule
+btu britishthermalunit
+quad 1.0e+15 btu
+refrigeration 12000 btu/ton hour
+buck dollar
+cable 720 ft
+caliber 1e-2 in
+calorie cal
+carat 205 mg
+cent centidollar
+cental 100 lb
+centesimalminute 1e-2 grad
+centesimalsecond 1e-4 grad
+century 100 year
+cfs ft³/sec
+chain 66 ft
+circularinch 1|4 π in²
+circularmil 1e-6|4 π in²
+clusec 1e-8 mm hg m³/s
+coomb 4 bu
+cord 128 ft³
+cordfoot cord
+crith 9.06e-2 gm
+cubit 18 in
+cup 1|2 pt
+curie 3.7e+10/sec
+cusec ft³/sec
+dalton amu
+decade 10 yr
+degK °K
+degC °C
+degF °F
+dipotre 1/m
+displacementton 35 ft³
+doppelzentner 100 kg
+dozen 12
+drop .03 cm³
+dyne cm gm/sec²
+electronvolt e volt
+ell 45 in
+engineerschain 100 ft
+engineerslink 100|100 ft
+equivalentfootcandle lumen/π ft²
+equivalentlux lumen/π m²
+equivalentphot cd/π cm²
+erg cm²gm/sec²
+ev e volt
+faraday 9.652e+4 coul
+fathom 6 ft
+fermi 1e-15 m
+fifth 4|5 qt
+fin 5 dollar
+finger 7|8 in
+firkin 9 gal
+footcandle lumen/ft²
+footlambert cd/π ft²
+fortnight 14 da
+franklin 3.33564e-10 coul
+frigorie kilocal
+furlong 220 yd
+galileo 1e-2 m/sec²
+gamma 1e-9 weber/m²
+gauss 1e-4 weber/m²
+geodeticfoot british ft
+geographicalmile 1852 m
+gilbert 7.95775e-1 amp
+gill 1|4 pt
+gross 144
+gunterschain 22 yd
+hand 4 in
+hectare 1e+4 m²
+hefnercandle .92 cd
+hertz 1/sec
+hogshead 2 barrel
+hd hogshead
+homestead 1|4 mi²
+horsepower 550 ft lb g/sec
+hp horsepower
+hyl gm force sec²/m
+hz 1/sec
+imaginarycubicfoot 1.4 ft³
+karat 1|24
+kcal kilocal
+kcalorie kilocal
+kev 1e+3 e volt
+key kg
+khz 1e+3/sec
+kilderkin 18 gal
+knot nmile/hr
+kwh kilowatt hour
+lambert cd/π cm²
+langley cal/cm²
+last 80 bu
+league 3 mi
+lightyear c yr
+ly lightyear
+lightsecond c sec
+line 1|12 in
+link 66|100 ft
+longhundredweight 112 lb
+longquarter 28 lb
+lusec 1e-6 mm hg m³/s
+mach 331.46 m/sec
+marineleague 3 nmile
+maxwell 1e-8 weber
+metriccarat 200 mg
+mev 1e+6 e volt
+mgd megagal/day
+mh millihenry
+mhz 1e+6/sec
+mil 1e-3 in
+millenium 1000 year
+minersinch 1.5 ft³/min
+minim 1|60 fldr
+mo month
+mpg mile/gal
+mph mile/hr
+nail 1|16 yd
+nauticalmile nmile
+nit cd/m²
+noggin 1|8 qt
+nox 1e-3 lux
+ns nanosec
+oersted 2.5e+2 amp/m π
+oe oersted
+pace 36 in
+palm 3 in
+parasang 3.5 mi
+parsec au radian/arcsec
+pascal nt/m²
+pc parsec
+pennyweight 1|20 oz
+percent %
+perch rd
+pf picofarad
+phot lumen/cm²
+pica 1|6 in
+pieze 1e+3 nt/m²
+pipe 4 barrel
+point 1|72 in
+poise gm/cm sec
+pole rd
+poundal ft lb/sec²
+pdl poundal
+proof 1/200
+psi lb g/in²
+quarter 9 in
+quartersection 1|4 mi²
+quintal 100 kg
+quire 25
+rad 100 erg/gm
+ream 500
+registerton 100 ft³
+rhe 10 m²/nt sec
+rontgen 2.58e-4 curie/kg
+rood 1.21e+3 yd
+rope 20 ft
+rutherford 1e+6/sec
+rydberg 1.36054e+1 ev
+sabin 1 ft²
+sack 3 bu
+seam 8 bu
+section mi²
+shippington 40 ft³
+shorthundredweight 100 lb
+shortquarter 25 lb
+siemens 1/Ω
+σ 5.66956e-5 erg/cm² °K^4 sec
+sigma σ
+skein 120 yd
+skot 1e-3 apostilb
+slug lb g sec²/ft
+span 9 in
+spat 4 π sr
+spindle 14400 yd
+square 100 ft²
+squidge 1|972 inch
+catsquidge 1|432 inch
+stere m³
+sthene 1e+3 nt
+stilb cd/cm²
+stoke 1e-4 m²/sec
+stone 14 lb
+strike 2 bu
+surveyfoot british ft
+surveyorschain 66 ft
+surveyorslink 66|100 ft
+tablespoon 4 fldr
+teaspoon 4|3 fldr
+tesla weber/m²
+therm 1e+5 btu
+thermie 1e+6 cal
+timberfoot ft³
+tnt 4.6e+6 m²/sec²
+tonne 1e+6 gm
+torr mm hg
+township 36 mi²
+tun 8 barrel
+water .22491|2.54 kg/m²sec²
+wey 40 bu
+weymass 252 lb
+Xunit 1.00202e-13 m
+k 1.38047e-16 erg/°K
+foal 9223372036854775807
diff --git a/src/cmd/yacc/units.y b/src/cmd/yacc/units.y
new file mode 100644
index 000000000..f10cb7c7d
--- /dev/null
+++ b/src/cmd/yacc/units.y
@@ -0,0 +1,759 @@
+// Derived from Plan 9's /sys/src/cmd/units.y
+// http://plan9.bell-labs.com/sources/plan9/sys/src/cmd/units.y
+//
+// Copyright (C) 2003, Lucent Technologies Inc. and others. All Rights Reserved.
+// Portions Copyright 2009 The Go Authors. All Rights Reserved.
+// Distributed under the terms of the Lucent Public License Version 1.02
+// See http://plan9.bell-labs.com/plan9/license.html
+
+// Generate parser with prefix "units_":
+// go tool yacc -p "units_"
+
+%{
+
+// units.y
+// example of a Go yacc program
+// usage is
+// go tool yacc -p "units_" units.y (produces y.go)
+// 6g y.go
+// 6l y.6
+// ./6.out $GOROOT/src/cmd/yacc/units
+// you have: c
+// you want: furlongs/fortnight
+// * 1.8026178e+12
+// / 5.5474878e-13
+// you have:
+
+package main
+
+import (
+ "flag"
+ "fmt"
+ "bufio"
+ "os"
+ "math"
+ "strconv"
+ "unicode/utf8"
+)
+
+const (
+ Ndim = 15 // number of dimensions
+ Maxe = 695 // log of largest number
+)
+
+type Node struct {
+ vval float64
+ dim [Ndim]int8
+}
+
+type Var struct {
+ name string
+ node Node
+}
+
+var fi *bufio.Reader // input
+var fund [Ndim]*Var // names of fundamental units
+var line string // current input line
+var lineno int // current input line number
+var linep int // index to next rune in unput
+var nerrors int // error count
+var one Node // constant one
+var peekrune rune // backup runt from input
+var retnode1 Node
+var retnode2 Node
+var retnode Node
+var sym string
+var vflag bool
+%}
+
+%union {
+ node Node
+ vvar *Var
+ numb int
+ vval float64
+}
+
+%type <node> prog expr expr0 expr1 expr2 expr3 expr4
+
+%token <vval> VAL
+%token <vvar> VAR
+%token <numb> SUP
+%%
+prog:
+ ':' VAR expr
+ {
+ var f int
+ f = int($2.node.dim[0])
+ $2.node = $3
+ $2.node.dim[0] = 1
+ if f != 0 {
+ Errorf("redefinition of %v", $2.name)
+ } else if vflag {
+ fmt.Printf("%v\t%v\n", $2.name, &$2.node)
+ }
+ }
+| ':' VAR '#'
+ {
+ var f, i int
+ for i = 1; i < Ndim; i++ {
+ if fund[i] == nil {
+ break
+ }
+ }
+ if i >= Ndim {
+ Error("too many dimensions")
+ i = Ndim - 1
+ }
+ fund[i] = $2
+ f = int($2.node.dim[0])
+ $2.node = one
+ $2.node.dim[0] = 1
+ $2.node.dim[i] = 1
+ if f != 0 {
+ Errorf("redefinition of %v", $2.name)
+ } else if vflag {
+ fmt.Printf("%v\t#\n", $2.name)
+ }
+ }
+| ':'
+ {
+ }
+| '?' expr
+ {
+ retnode1 = $2
+ }
+| '?'
+ {
+ retnode1 = one
+ }
+
+expr:
+ expr4
+| expr '+' expr4
+ {
+ add(&$$, &$1, &$3)
+ }
+| expr '-' expr4
+ {
+ sub(&$$, &$1, &$3)
+ }
+
+expr4:
+ expr3
+| expr4 '*' expr3
+ {
+ mul(&$$, &$1, &$3)
+ }
+| expr4 '/' expr3
+ {
+ div(&$$, &$1, &$3)
+ }
+
+expr3:
+ expr2
+| expr3 expr2
+ {
+ mul(&$$, &$1, &$2)
+ }
+
+expr2:
+ expr1
+| expr2 SUP
+ {
+ xpn(&$$, &$1, $2)
+ }
+| expr2 '^' expr1
+ {
+ var i int
+ for i = 1; i < Ndim; i++ {
+ if $3.dim[i] != 0 {
+ Error("exponent has units")
+ $$ = $1
+ break
+ }
+ }
+ if i >= Ndim {
+ i = int($3.vval)
+ if float64(i) != $3.vval {
+ Error("exponent not integral")
+ }
+ xpn(&$$, &$1, i)
+ }
+ }
+
+expr1:
+ expr0
+| expr1 '|' expr0
+ {
+ div(&$$, &$1, &$3)
+ }
+
+expr0:
+ VAR
+ {
+ if $1.node.dim[0] == 0 {
+ Errorf("undefined %v", $1.name)
+ $$ = one
+ } else {
+ $$ = $1.node
+ }
+ }
+| VAL
+ {
+ $$ = one
+ $$.vval = $1
+ }
+| '(' expr ')'
+ {
+ $$ = $2
+ }
+%%
+
+type UnitsLex int
+
+func (UnitsLex) Lex(yylval *units_SymType) int {
+ var c rune
+ var i int
+
+ c = peekrune
+ peekrune = ' '
+
+loop:
+ if (c >= '0' && c <= '9') || c == '.' {
+ goto numb
+ }
+ if ralpha(c) {
+ goto alpha
+ }
+ switch c {
+ case ' ', '\t':
+ c = getrune()
+ goto loop
+ case '×':
+ return '*'
+ case '÷':
+ return '/'
+ case '¹', 'ⁱ':
+ yylval.numb = 1
+ return SUP
+ case '²', '⁲':
+ yylval.numb = 2
+ return SUP
+ case '³', '⁳':
+ yylval.numb = 3
+ return SUP
+ }
+ return int(c)
+
+alpha:
+ sym = ""
+ for i = 0; ; i++ {
+ sym += string(c)
+ c = getrune()
+ if !ralpha(c) {
+ break
+ }
+ }
+ peekrune = c
+ yylval.vvar = lookup(0)
+ return VAR
+
+numb:
+ sym = ""
+ for i = 0; ; i++ {
+ sym += string(c)
+ c = getrune()
+ if !rdigit(c) {
+ break
+ }
+ }
+ peekrune = c
+ f, err := strconv.ParseFloat(sym, 64)
+ if err != nil {
+ fmt.Printf("error converting %v\n", sym)
+ f = 0
+ }
+ yylval.vval = f
+ return VAL
+}
+
+func (UnitsLex) Error(s string) {
+ Errorf("syntax error, last name: %v", sym)
+}
+
+func main() {
+ var file string
+
+ flag.BoolVar(&vflag, "v", false, "verbose")
+
+ flag.Parse()
+
+ file = os.Getenv("GOROOT") + "/src/cmd/yacc/units.txt"
+ if flag.NArg() > 0 {
+ file = flag.Arg(0)
+ }
+
+ f, err := os.Open(file)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "error opening %v: %v\n", file, err)
+ os.Exit(1)
+ }
+ fi = bufio.NewReader(f)
+
+ one.vval = 1
+
+ /*
+ * read the 'units' file to
+ * develope a database
+ */
+ lineno = 0
+ for {
+ lineno++
+ if readline() {
+ break
+ }
+ if len(line) == 0 || line[0] == '/' {
+ continue
+ }
+ peekrune = ':'
+ units_Parse(UnitsLex(0))
+ }
+
+ /*
+ * read the console to
+ * print ratio of pairs
+ */
+ fi = bufio.NewReader(os.NewFile(0, "stdin"))
+
+ lineno = 0
+ for {
+ if (lineno & 1) != 0 {
+ fmt.Printf("you want: ")
+ } else {
+ fmt.Printf("you have: ")
+ }
+ if readline() {
+ break
+ }
+ peekrune = '?'
+ nerrors = 0
+ units_Parse(UnitsLex(0))
+ if nerrors != 0 {
+ continue
+ }
+ if (lineno & 1) != 0 {
+ if specialcase(&retnode, &retnode2, &retnode1) {
+ fmt.Printf("\tis %v\n", &retnode)
+ } else {
+ div(&retnode, &retnode2, &retnode1)
+ fmt.Printf("\t* %v\n", &retnode)
+ div(&retnode, &retnode1, &retnode2)
+ fmt.Printf("\t/ %v\n", &retnode)
+ }
+ } else {
+ retnode2 = retnode1
+ }
+ lineno++
+ }
+ fmt.Printf("\n")
+ os.Exit(0)
+}
+
+/*
+ * all characters that have some
+ * meaning. rest are usable as names
+ */
+func ralpha(c rune) bool {
+ switch c {
+ case 0, '+', '-', '*', '/', '[', ']', '(', ')',
+ '^', ':', '?', ' ', '\t', '.', '|', '#',
+ '×', '÷', '¹', 'ⁱ', '²', '⁲', '³', '⁳':
+ return false
+ }
+ return true
+}
+
+/*
+ * number forming character
+ */
+func rdigit(c rune) bool {
+ switch c {
+ case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ '.', 'e', '+', '-':
+ return true
+ }
+ return false
+}
+
+func Errorf(s string, v ...interface{}) {
+ fmt.Printf("%v: %v\n\t", lineno, line)
+ fmt.Printf(s, v...)
+ fmt.Printf("\n")
+
+ nerrors++
+ if nerrors > 5 {
+ fmt.Printf("too many errors\n")
+ os.Exit(1)
+ }
+}
+
+func Error(s string) {
+ Errorf("%s", s)
+}
+
+func add(c, a, b *Node) {
+ var i int
+ var d int8
+
+ for i = 0; i < Ndim; i++ {
+ d = a.dim[i]
+ c.dim[i] = d
+ if d != b.dim[i] {
+ Error("add must be like units")
+ }
+ }
+ c.vval = fadd(a.vval, b.vval)
+}
+
+func sub(c, a, b *Node) {
+ var i int
+ var d int8
+
+ for i = 0; i < Ndim; i++ {
+ d = a.dim[i]
+ c.dim[i] = d
+ if d != b.dim[i] {
+ Error("sub must be like units")
+ }
+ }
+ c.vval = fadd(a.vval, -b.vval)
+}
+
+func mul(c, a, b *Node) {
+ var i int
+
+ for i = 0; i < Ndim; i++ {
+ c.dim[i] = a.dim[i] + b.dim[i]
+ }
+ c.vval = fmul(a.vval, b.vval)
+}
+
+func div(c, a, b *Node) {
+ var i int
+
+ for i = 0; i < Ndim; i++ {
+ c.dim[i] = a.dim[i] - b.dim[i]
+ }
+ c.vval = fdiv(a.vval, b.vval)
+}
+
+func xpn(c, a *Node, b int) {
+ var i int
+
+ *c = one
+ if b < 0 {
+ b = -b
+ for i = 0; i < b; i++ {
+ div(c, c, a)
+ }
+ } else {
+ for i = 0; i < b; i++ {
+ mul(c, c, a)
+ }
+ }
+}
+
+func specialcase(c, a, b *Node) bool {
+ var i int
+ var d, d1, d2 int8
+
+ d1 = 0
+ d2 = 0
+ for i = 1; i < Ndim; i++ {
+ d = a.dim[i]
+ if d != 0 {
+ if d != 1 || d1 != 0 {
+ return false
+ }
+ d1 = int8(i)
+ }
+ d = b.dim[i]
+ if d != 0 {
+ if d != 1 || d2 != 0 {
+ return false
+ }
+ d2 = int8(i)
+ }
+ }
+ if d1 == 0 || d2 == 0 {
+ return false
+ }
+
+ if fund[d1].name == "°C" && fund[d2].name == "°F" &&
+ b.vval == 1 {
+ for ll := 0; ll < len(c.dim); ll++ {
+ c.dim[ll] = b.dim[ll]
+ }
+ c.vval = a.vval*9./5. + 32.
+ return true
+ }
+
+ if fund[d1].name == "°F" && fund[d2].name == "°C" &&
+ b.vval == 1 {
+ for ll := 0; ll < len(c.dim); ll++ {
+ c.dim[ll] = b.dim[ll]
+ }
+ c.vval = (a.vval - 32.) * 5. / 9.
+ return true
+ }
+ return false
+}
+
+func printdim(str string, d, n int) string {
+ var v *Var
+
+ if n != 0 {
+ v = fund[d]
+ if v != nil {
+ str += fmt.Sprintf("%v", v.name)
+ } else {
+ str += fmt.Sprintf("[%d]", d)
+ }
+ switch n {
+ case 1:
+ break
+ case 2:
+ str += "²"
+ case 3:
+ str += "³"
+ default:
+ str += fmt.Sprintf("^%d", n)
+ }
+ }
+ return str
+}
+
+func (n Node) String() string {
+ var str string
+ var f, i, d int
+
+ str = fmt.Sprintf("%.7e ", n.vval)
+
+ f = 0
+ for i = 1; i < Ndim; i++ {
+ d = int(n.dim[i])
+ if d > 0 {
+ str = printdim(str, i, d)
+ } else if d < 0 {
+ f = 1
+ }
+ }
+
+ if f != 0 {
+ str += " /"
+ for i = 1; i < Ndim; i++ {
+ d = int(n.dim[i])
+ if d < 0 {
+ str = printdim(str, i, -d)
+ }
+ }
+ }
+
+ return str
+}
+
+func (v *Var) String() string {
+ var str string
+ str = fmt.Sprintf("%v %v", v.name, v.node)
+ return str
+}
+
+func readline() bool {
+ s, err := fi.ReadString('\n')
+ if err != nil {
+ return true
+ }
+ line = s
+ linep = 0
+ return false
+}
+
+func getrune() rune {
+ var c rune
+ var n int
+
+ if linep >= len(line) {
+ return 0
+ }
+ c, n = utf8.DecodeRuneInString(line[linep:len(line)])
+ linep += n
+ if c == '\n' {
+ c = 0
+ }
+ return c
+}
+
+var symmap = make(map[string]*Var) // symbol table
+
+func lookup(f int) *Var {
+ var p float64
+ var w *Var
+
+ v, ok := symmap[sym]
+ if ok {
+ return v
+ }
+ if f != 0 {
+ return nil
+ }
+ v = new(Var)
+ v.name = sym
+ symmap[sym] = v
+
+ p = 1
+ for {
+ p = fmul(p, pname())
+ if p == 0 {
+ break
+ }
+ w = lookup(1)
+ if w != nil {
+ v.node = w.node
+ v.node.vval = fmul(v.node.vval, p)
+ break
+ }
+ }
+ return v
+}
+
+type Prefix struct {
+ vval float64
+ name string
+}
+
+var prefix = []Prefix{ // prefix table
+ {1e-24, "yocto"},
+ {1e-21, "zepto"},
+ {1e-18, "atto"},
+ {1e-15, "femto"},
+ {1e-12, "pico"},
+ {1e-9, "nano"},
+ {1e-6, "micro"},
+ {1e-6, "μ"},
+ {1e-3, "milli"},
+ {1e-2, "centi"},
+ {1e-1, "deci"},
+ {1e1, "deka"},
+ {1e2, "hecta"},
+ {1e2, "hecto"},
+ {1e3, "kilo"},
+ {1e6, "mega"},
+ {1e6, "meg"},
+ {1e9, "giga"},
+ {1e12, "tera"},
+ {1e15, "peta"},
+ {1e18, "exa"},
+ {1e21, "zetta"},
+ {1e24, "yotta"},
+}
+
+func pname() float64 {
+ var i, j, n int
+ var s string
+
+ /*
+ * rip off normal prefixs
+ */
+ n = len(sym)
+ for i = 0; i < len(prefix); i++ {
+ s = prefix[i].name
+ j = len(s)
+ if j < n && sym[0:j] == s {
+ sym = sym[j:n]
+ return prefix[i].vval
+ }
+ }
+
+ /*
+ * rip off 's' suffixes
+ */
+ if n > 2 && sym[n-1] == 's' {
+ sym = sym[0 : n-1]
+ return 1
+ }
+
+ return 0
+}
+
+// careful multiplication
+// exponents (log) are checked before multiply
+func fmul(a, b float64) float64 {
+ var l float64
+
+ if b <= 0 {
+ if b == 0 {
+ return 0
+ }
+ l = math.Log(-b)
+ } else {
+ l = math.Log(b)
+ }
+
+ if a <= 0 {
+ if a == 0 {
+ return 0
+ }
+ l += math.Log(-a)
+ } else {
+ l += math.Log(a)
+ }
+
+ if l > Maxe {
+ Error("overflow in multiply")
+ return 1
+ }
+ if l < -Maxe {
+ Error("underflow in multiply")
+ return 0
+ }
+ return a * b
+}
+
+// careful division
+// exponents (log) are checked before divide
+func fdiv(a, b float64) float64 {
+ var l float64
+
+ if b <= 0 {
+ if b == 0 {
+ Errorf("division by zero: %v %v", a, b)
+ return 1
+ }
+ l = math.Log(-b)
+ } else {
+ l = math.Log(b)
+ }
+
+ if a <= 0 {
+ if a == 0 {
+ return 0
+ }
+ l -= math.Log(-a)
+ } else {
+ l -= math.Log(a)
+ }
+
+ if l < -Maxe {
+ Error("overflow in divide")
+ return 1
+ }
+ if l > Maxe {
+ Error("underflow in divide")
+ return 0
+ }
+ return a / b
+}
+
+func fadd(a, b float64) float64 {
+ return a + b
+}
diff --git a/src/cmd/yacc/yacc.go b/src/cmd/yacc/yacc.go
new file mode 100644
index 000000000..c91a72123
--- /dev/null
+++ b/src/cmd/yacc/yacc.go
@@ -0,0 +1,3324 @@
+/*
+Derived from Inferno's utils/iyacc/yacc.c
+http://code.google.com/p/inferno-os/source/browse/utils/iyacc/yacc.c
+
+This copyright NOTICE applies to all files in this directory and
+subdirectories, unless another copyright notice appears in a given
+file or subdirectory. If you take substantial code from this software to use in
+other programs, you must somehow include with it an appropriate
+copyright notice that includes the copyright notice and the other
+notices below. It is fine (and often tidier) to do that in a separate
+file such as NOTICE, LICENCE or COPYING.
+
+ Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+ Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+ Portions Copyright © 1997-1999 Vita Nuova Limited
+ Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+ Portions Copyright © 2004,2006 Bruce Ellis
+ Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+ Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+ Portions Copyright © 2009 The Go Authors. All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+package main
+
+// yacc
+// major difference is lack of stem ("y" variable)
+//
+
+import (
+ "bufio"
+ "bytes"
+ "flag"
+ "fmt"
+ "os"
+ "strings"
+)
+
+// the following are adjustable
+// according to memory size
+const (
+ ACTSIZE = 30000
+ NSTATES = 2000
+ TEMPSIZE = 2000
+
+ SYMINC = 50 // increase for non-term or term
+ RULEINC = 50 // increase for max rule length prodptr[i]
+ PRODINC = 100 // increase for productions prodptr
+ WSETINC = 50 // increase for working sets wsets
+ STATEINC = 200 // increase for states statemem
+
+ NAMESIZE = 50
+ NTYPES = 63
+ ISIZE = 400
+
+ PRIVATE = 0xE000 // unicode private use
+
+ // relationships which must hold:
+ // TEMPSIZE >= NTERMS + NNONTERM + 1;
+ // TEMPSIZE >= NSTATES;
+ //
+
+ NTBASE = 010000
+ ERRCODE = 8190
+ ACCEPTCODE = 8191
+ YYLEXUNK = 3
+ TOKSTART = 4 //index of first defined token
+)
+
+// no, left, right, binary assoc.
+const (
+ NOASC = iota
+ LASC
+ RASC
+ BASC
+)
+
+// flags for state generation
+const (
+ DONE = iota
+ MUSTDO
+ MUSTLOOKAHEAD
+)
+
+// flags for a rule having an action, and being reduced
+const (
+ ACTFLAG = 1 << (iota + 2)
+ REDFLAG
+)
+
+// output parser flags
+const yyFlag = -1000
+
+// parse tokens
+const (
+ IDENTIFIER = PRIVATE + iota
+ MARK
+ TERM
+ LEFT
+ RIGHT
+ BINARY
+ PREC
+ LCURLY
+ IDENTCOLON
+ NUMBER
+ START
+ TYPEDEF
+ TYPENAME
+ UNION
+)
+
+const ENDFILE = 0
+const EMPTY = 1
+const WHOKNOWS = 0
+const OK = 1
+const NOMORE = -1000
+
+// macros for getting associativity and precedence levels
+func ASSOC(i int) int { return i & 3 }
+
+func PLEVEL(i int) int { return (i >> 4) & 077 }
+
+func TYPE(i int) int { return (i >> 10) & 077 }
+
+// macros for setting associativity and precedence levels
+func SETASC(i, j int) int { return i | j }
+
+func SETPLEV(i, j int) int { return i | (j << 4) }
+
+func SETTYPE(i, j int) int { return i | (j << 10) }
+
+// I/O descriptors
+var finput *bufio.Reader // input file
+var stderr *bufio.Writer
+var ftable *bufio.Writer // y.go file
+var fcode = &bytes.Buffer{} // saved code
+var foutput *bufio.Writer // y.output file
+
+var oflag string // -o [y.go] - y.go file
+var vflag string // -v [y.output] - y.output file
+var lflag bool // -l - disable line directives
+var prefix string // name prefix for identifiers, default yy
+
+func init() {
+ flag.StringVar(&oflag, "o", "y.go", "parser output")
+ flag.StringVar(&prefix, "p", "yy", "name prefix to use in generated code")
+ flag.StringVar(&vflag, "v", "y.output", "create parsing tables")
+ flag.BoolVar(&lflag, "l", false, "disable line directives")
+}
+
+var stacksize = 200
+
+// communication variables between various I/O routines
+var infile string // input file name
+var numbval int // value of an input number
+var tokname string // input token name, slop for runes and 0
+var tokflag = false
+
+// structure declarations
+type Lkset []int
+
+type Pitem struct {
+ prod []int
+ off int // offset within the production
+ first int // first term or non-term in item
+ prodno int // production number for sorting
+}
+
+type Item struct {
+ pitem Pitem
+ look Lkset
+}
+
+type Symb struct {
+ name string
+ value int
+}
+
+type Wset struct {
+ pitem Pitem
+ flag int
+ ws Lkset
+}
+
+// storage of types
+var ntypes int // number of types defined
+var typeset [NTYPES]string // pointers to type tags
+
+// token information
+
+var ntokens = 0 // number of tokens
+var tokset []Symb
+var toklev []int // vector with the precedence of the terminals
+
+// nonterminal information
+
+var nnonter = -1 // the number of nonterminals
+var nontrst []Symb
+var start int // start symbol
+
+// state information
+
+var nstate = 0 // number of states
+var pstate = make([]int, NSTATES+2) // index into statemem to the descriptions of the states
+var statemem []Item
+var tystate = make([]int, NSTATES) // contains type information about the states
+var tstates []int // states generated by terminal gotos
+var ntstates []int // states generated by nonterminal gotos
+var mstates = make([]int, NSTATES) // chain of overflows of term/nonterm generation lists
+var lastred int // number of last reduction of a state
+var defact = make([]int, NSTATES) // default actions of states
+
+// lookahead set information
+
+var lkst []Lkset
+var nolook = 0 // flag to turn off lookahead computations
+var tbitset = 0 // size of lookahead sets
+var clset Lkset // temporary storage for lookahead computations
+
+// working set information
+
+var wsets []Wset
+var cwp int
+
+// storage for action table
+
+var amem []int // action table storage
+var memp int // next free action table position
+var indgo = make([]int, NSTATES) // index to the stored goto table
+
+// temporary vector, indexable by states, terms, or ntokens
+
+var temp1 = make([]int, TEMPSIZE) // temporary storage, indexed by terms + ntokens or states
+var lineno = 1 // current input line number
+var fatfl = 1 // if on, error is fatal
+var nerrors = 0 // number of errors
+
+// assigned token type values
+
+var extval = 0
+
+// grammar rule information
+
+var nprod = 1 // number of productions
+var prdptr [][]int // pointers to descriptions of productions
+var levprd []int // precedence levels for the productions
+var rlines []int // line number for this rule
+
+// statistics collection variables
+
+var zzgoent = 0
+var zzgobest = 0
+var zzacent = 0
+var zzexcp = 0
+var zzclose = 0
+var zzrrconf = 0
+var zzsrconf = 0
+var zzstate = 0
+
+// optimizer arrays
+
+var yypgo [][]int
+var optst [][]int
+var ggreed []int
+var pgo []int
+
+var maxspr int // maximum spread of any entry
+var maxoff int // maximum offset into a array
+var maxa int
+
+// storage for information about the nonterminals
+
+var pres [][][]int // vector of pointers to productions yielding each nonterminal
+var pfirst []Lkset
+var pempty []int // vector of nonterminals nontrivially deriving e
+
+// random stuff picked out from between functions
+
+var indebug = 0 // debugging flag for cpfir
+var pidebug = 0 // debugging flag for putitem
+var gsdebug = 0 // debugging flag for stagen
+var cldebug = 0 // debugging flag for closure
+var pkdebug = 0 // debugging flag for apack
+var g2debug = 0 // debugging for go2gen
+var adb = 0 // debugging for callopt
+
+type Resrv struct {
+ name string
+ value int
+}
+
+var resrv = []Resrv{
+ {"binary", BINARY},
+ {"left", LEFT},
+ {"nonassoc", BINARY},
+ {"prec", PREC},
+ {"right", RIGHT},
+ {"start", START},
+ {"term", TERM},
+ {"token", TERM},
+ {"type", TYPEDEF},
+ {"union", UNION},
+ {"struct", UNION},
+}
+
+var zznewstate = 0
+
+const EOF = -1
+const UTFmax = 0x3f
+
+func main() {
+
+ setup() // initialize and read productions
+
+ tbitset = (ntokens + 32) / 32
+ cpres() // make table of which productions yield a given nonterminal
+ cempty() // make a table of which nonterminals can match the empty string
+ cpfir() // make a table of firsts of nonterminals
+
+ stagen() // generate the states
+
+ yypgo = make([][]int, nnonter+1)
+ optst = make([][]int, nstate)
+ output() // write the states and the tables
+ go2out()
+
+ hideprod()
+ summary()
+
+ callopt()
+
+ others()
+
+ exit(0)
+}
+
+func setup() {
+ var j, ty int
+
+ stderr = bufio.NewWriter(os.NewFile(2, "stderr"))
+ foutput = nil
+
+ flag.Parse()
+ if flag.NArg() != 1 {
+ usage()
+ }
+ if stacksize < 1 {
+ // never set so cannot happen
+ fmt.Fprintf(stderr, "yacc: stack size too small\n")
+ usage()
+ }
+ yaccpar = strings.Replace(yaccpartext, "$$", prefix, -1)
+ openup()
+
+ defin(0, "$end")
+ extval = PRIVATE // tokens start in unicode 'private use'
+ defin(0, "error")
+ defin(1, "$accept")
+ defin(0, "$unk")
+ i := 0
+
+ t := gettok()
+
+outer:
+ for {
+ switch t {
+ default:
+ errorf("syntax error tok=%v", t-PRIVATE)
+
+ case MARK, ENDFILE:
+ break outer
+
+ case ';':
+
+ case START:
+ t = gettok()
+ if t != IDENTIFIER {
+ errorf("bad %%start construction")
+ }
+ start = chfind(1, tokname)
+
+ case TYPEDEF:
+ t = gettok()
+ if t != TYPENAME {
+ errorf("bad syntax in %%type")
+ }
+ ty = numbval
+ for {
+ t = gettok()
+ switch t {
+ case IDENTIFIER:
+ t = chfind(1, tokname)
+ if t < NTBASE {
+ j = TYPE(toklev[t])
+ if j != 0 && j != ty {
+ errorf("type redeclaration of token %s",
+ tokset[t].name)
+ } else {
+ toklev[t] = SETTYPE(toklev[t], ty)
+ }
+ } else {
+ j = nontrst[t-NTBASE].value
+ if j != 0 && j != ty {
+ errorf("type redeclaration of nonterminal %v",
+ nontrst[t-NTBASE].name)
+ } else {
+ nontrst[t-NTBASE].value = ty
+ }
+ }
+ continue
+
+ case ',':
+ continue
+ }
+ break
+ }
+ continue
+
+ case UNION:
+ cpyunion()
+
+ case LEFT, BINARY, RIGHT, TERM:
+ // nonzero means new prec. and assoc.
+ lev := t - TERM
+ if lev != 0 {
+ i++
+ }
+ ty = 0
+
+ // get identifiers so defined
+ t = gettok()
+
+ // there is a type defined
+ if t == TYPENAME {
+ ty = numbval
+ t = gettok()
+ }
+ for {
+ switch t {
+ case ',':
+ t = gettok()
+ continue
+
+ case ';':
+ break
+
+ case IDENTIFIER:
+ j = chfind(0, tokname)
+ if j >= NTBASE {
+ errorf("%v defined earlier as nonterminal", tokname)
+ }
+ if lev != 0 {
+ if ASSOC(toklev[j]) != 0 {
+ errorf("redeclaration of precedence of %v", tokname)
+ }
+ toklev[j] = SETASC(toklev[j], lev)
+ toklev[j] = SETPLEV(toklev[j], i)
+ }
+ if ty != 0 {
+ if TYPE(toklev[j]) != 0 {
+ errorf("redeclaration of type of %v", tokname)
+ }
+ toklev[j] = SETTYPE(toklev[j], ty)
+ }
+ t = gettok()
+ if t == NUMBER {
+ tokset[j].value = numbval
+ t = gettok()
+ }
+
+ continue
+ }
+ break
+ }
+ continue
+
+ case LCURLY:
+ cpycode()
+ }
+ t = gettok()
+ }
+
+ if t == ENDFILE {
+ errorf("unexpected EOF before %%")
+ }
+
+ // put out non-literal terminals
+ for i := TOKSTART; i <= ntokens; i++ {
+ // non-literals
+ c := tokset[i].name[0]
+ if c != ' ' && c != '$' {
+ fmt.Fprintf(ftable, "const %v = %v\n", tokset[i].name, tokset[i].value)
+ }
+ }
+
+ // put out names of token names
+ ftable.WriteRune('\n')
+ fmt.Fprintf(ftable, "var %sToknames = []string{\n", prefix)
+ for i := TOKSTART; i <= ntokens; i++ {
+ fmt.Fprintf(ftable, "\t\"%v\",\n", tokset[i].name)
+ }
+ fmt.Fprintf(ftable, "}\n")
+
+ // put out names of state names
+ fmt.Fprintf(ftable, "var %sStatenames = []string{", prefix)
+ // for i:=TOKSTART; i<=ntokens; i++ {
+ // fmt.Fprintf(ftable, "\t\"%v\",\n", tokset[i].name);
+ // }
+ fmt.Fprintf(ftable, "}\n")
+
+ fmt.Fprintf(fcode, "switch %snt {\n", prefix)
+
+ moreprod()
+ prdptr[0] = []int{NTBASE, start, 1, 0}
+
+ nprod = 1
+ curprod := make([]int, RULEINC)
+ t = gettok()
+ if t != IDENTCOLON {
+ errorf("bad syntax on first rule")
+ }
+
+ if start == 0 {
+ prdptr[0][1] = chfind(1, tokname)
+ }
+
+ // read rules
+ // put into prdptr array in the format
+ // target
+ // followed by id's of terminals and non-terminals
+ // followd by -nprod
+
+ for t != MARK && t != ENDFILE {
+ mem := 0
+
+ // process a rule
+ rlines[nprod] = lineno
+ if t == '|' {
+ curprod[mem] = prdptr[nprod-1][0]
+ mem++
+ } else if t == IDENTCOLON {
+ curprod[mem] = chfind(1, tokname)
+ if curprod[mem] < NTBASE {
+ errorf("token illegal on LHS of grammar rule")
+ }
+ mem++
+ } else {
+ errorf("illegal rule: missing semicolon or | ?")
+ }
+
+ // read rule body
+ t = gettok()
+ for {
+ for t == IDENTIFIER {
+ curprod[mem] = chfind(1, tokname)
+ if curprod[mem] < NTBASE {
+ levprd[nprod] = toklev[curprod[mem]]
+ }
+ mem++
+ if mem >= len(curprod) {
+ ncurprod := make([]int, mem+RULEINC)
+ copy(ncurprod, curprod)
+ curprod = ncurprod
+ }
+ t = gettok()
+ }
+ if t == PREC {
+ if gettok() != IDENTIFIER {
+ errorf("illegal %%prec syntax")
+ }
+ j = chfind(2, tokname)
+ if j >= NTBASE {
+ errorf("nonterminal " + nontrst[j-NTBASE].name + " illegal after %%prec")
+ }
+ levprd[nprod] = toklev[j]
+ t = gettok()
+ }
+ if t != '=' {
+ break
+ }
+ levprd[nprod] |= ACTFLAG
+ fmt.Fprintf(fcode, "\n\tcase %v:", nprod)
+ cpyact(curprod, mem)
+
+ // action within rule...
+ t = gettok()
+ if t == IDENTIFIER {
+ // make it a nonterminal
+ j = chfind(1, fmt.Sprintf("$$%v", nprod))
+
+ //
+ // the current rule will become rule number nprod+1
+ // enter null production for action
+ //
+ prdptr[nprod] = make([]int, 2)
+ prdptr[nprod][0] = j
+ prdptr[nprod][1] = -nprod
+
+ // update the production information
+ nprod++
+ moreprod()
+ levprd[nprod] = levprd[nprod-1] & ^ACTFLAG
+ levprd[nprod-1] = ACTFLAG
+ rlines[nprod] = lineno
+
+ // make the action appear in the original rule
+ curprod[mem] = j
+ mem++
+ if mem >= len(curprod) {
+ ncurprod := make([]int, mem+RULEINC)
+ copy(ncurprod, curprod)
+ curprod = ncurprod
+ }
+ }
+ }
+
+ for t == ';' {
+ t = gettok()
+ }
+ curprod[mem] = -nprod
+ mem++
+
+ // check that default action is reasonable
+ if ntypes != 0 && (levprd[nprod]&ACTFLAG) == 0 &&
+ nontrst[curprod[0]-NTBASE].value != 0 {
+ // no explicit action, LHS has value
+ tempty := curprod[1]
+ if tempty < 0 {
+ errorf("must return a value, since LHS has a type")
+ }
+ if tempty >= NTBASE {
+ tempty = nontrst[tempty-NTBASE].value
+ } else {
+ tempty = TYPE(toklev[tempty])
+ }
+ if tempty != nontrst[curprod[0]-NTBASE].value {
+ errorf("default action causes potential type clash")
+ }
+ fmt.Fprintf(fcode, "\n\tcase %v:", nprod)
+ fmt.Fprintf(fcode, "\n\t\t%sVAL.%v = %sS[%spt-0].%v",
+ prefix, typeset[tempty], prefix, prefix, typeset[tempty])
+ }
+ moreprod()
+ prdptr[nprod] = make([]int, mem)
+ copy(prdptr[nprod], curprod)
+ nprod++
+ moreprod()
+ levprd[nprod] = 0
+ }
+
+ //
+ // end of all rules
+ // dump out the prefix code
+ //
+
+ fmt.Fprintf(fcode, "\n\t}")
+
+ ftable.WriteRune('\n')
+ fmt.Fprintf(ftable, "const %sEofCode = 1\n", prefix)
+ fmt.Fprintf(ftable, "const %sErrCode = 2\n", prefix)
+ fmt.Fprintf(ftable, "const %sMaxDepth = %v\n", prefix, stacksize)
+
+ //
+ // copy any postfix code
+ //
+ if t == MARK {
+ if !lflag {
+ fmt.Fprintf(ftable, "\n//line %v:%v\n", infile, lineno)
+ }
+ for {
+ c := getrune(finput)
+ if c == EOF {
+ break
+ }
+ ftable.WriteRune(c)
+ }
+ }
+}
+
+//
+// allocate enough room to hold another production
+//
+func moreprod() {
+ n := len(prdptr)
+ if nprod >= n {
+ nn := n + PRODINC
+ aprod := make([][]int, nn)
+ alevprd := make([]int, nn)
+ arlines := make([]int, nn)
+
+ copy(aprod, prdptr)
+ copy(alevprd, levprd)
+ copy(arlines, rlines)
+
+ prdptr = aprod
+ levprd = alevprd
+ rlines = arlines
+ }
+}
+
+//
+// define s to be a terminal if t=0
+// or a nonterminal if t=1
+//
+func defin(nt int, s string) int {
+ val := 0
+ if nt != 0 {
+ nnonter++
+ if nnonter >= len(nontrst) {
+ anontrst := make([]Symb, nnonter+SYMINC)
+ copy(anontrst, nontrst)
+ nontrst = anontrst
+ }
+ nontrst[nnonter] = Symb{s, 0}
+ return NTBASE + nnonter
+ }
+
+ // must be a token
+ ntokens++
+ if ntokens >= len(tokset) {
+ nn := ntokens + SYMINC
+ atokset := make([]Symb, nn)
+ atoklev := make([]int, nn)
+
+ copy(atoklev, toklev)
+ copy(atokset, tokset)
+
+ tokset = atokset
+ toklev = atoklev
+ }
+ tokset[ntokens].name = s
+ toklev[ntokens] = 0
+
+ // establish value for token
+ // single character literal
+ if s[0] == ' ' && len(s) == 1+1 {
+ val = int(s[1])
+ } else if s[0] == ' ' && s[1] == '\\' { // escape sequence
+ if len(s) == 2+1 {
+ // single character escape sequence
+ switch s[2] {
+ case '\'':
+ val = '\''
+ case '"':
+ val = '"'
+ case '\\':
+ val = '\\'
+ case 'a':
+ val = '\a'
+ case 'b':
+ val = '\b'
+ case 'n':
+ val = '\n'
+ case 'r':
+ val = '\r'
+ case 't':
+ val = '\t'
+ case 'v':
+ val = '\v'
+ default:
+ errorf("invalid escape %v", s[1:3])
+ }
+ } else if s[2] == 'u' && len(s) == 2+1+4 { // \unnnn sequence
+ val = 0
+ s = s[3:]
+ for s != "" {
+ c := int(s[0])
+ switch {
+ case c >= '0' && c <= '9':
+ c -= '0'
+ case c >= 'a' && c <= 'f':
+ c -= 'a' - 10
+ case c >= 'A' && c <= 'F':
+ c -= 'A' - 10
+ default:
+ errorf("illegal \\unnnn construction")
+ }
+ val = val*16 + c
+ s = s[1:]
+ }
+ if val == 0 {
+ errorf("'\\u0000' is illegal")
+ }
+ } else {
+ errorf("unknown escape")
+ }
+ } else {
+ val = extval
+ extval++
+ }
+
+ tokset[ntokens].value = val
+ return ntokens
+}
+
+var peekline = 0
+
+func gettok() int {
+ var i int
+ var match, c rune
+
+ tokname = ""
+ for {
+ lineno += peekline
+ peekline = 0
+ c = getrune(finput)
+ for c == ' ' || c == '\n' || c == '\t' || c == '\v' || c == '\r' {
+ if c == '\n' {
+ lineno++
+ }
+ c = getrune(finput)
+ }
+
+ // skip comment -- fix
+ if c != '/' {
+ break
+ }
+ lineno += skipcom()
+ }
+
+ switch c {
+ case EOF:
+ if tokflag {
+ fmt.Printf(">>> ENDFILE %v\n", lineno)
+ }
+ return ENDFILE
+
+ case '{':
+ ungetrune(finput, c)
+ if tokflag {
+ fmt.Printf(">>> ={ %v\n", lineno)
+ }
+ return '='
+
+ case '<':
+ // get, and look up, a type name (union member name)
+ c = getrune(finput)
+ for c != '>' && c != EOF && c != '\n' {
+ tokname += string(c)
+ c = getrune(finput)
+ }
+
+ if c != '>' {
+ errorf("unterminated < ... > clause")
+ }
+
+ for i = 1; i <= ntypes; i++ {
+ if typeset[i] == tokname {
+ numbval = i
+ if tokflag {
+ fmt.Printf(">>> TYPENAME old <%v> %v\n", tokname, lineno)
+ }
+ return TYPENAME
+ }
+ }
+ ntypes++
+ numbval = ntypes
+ typeset[numbval] = tokname
+ if tokflag {
+ fmt.Printf(">>> TYPENAME new <%v> %v\n", tokname, lineno)
+ }
+ return TYPENAME
+
+ case '"', '\'':
+ match = c
+ tokname = " "
+ for {
+ c = getrune(finput)
+ if c == '\n' || c == EOF {
+ errorf("illegal or missing ' or \"")
+ }
+ if c == '\\' {
+ tokname += string('\\')
+ c = getrune(finput)
+ } else if c == match {
+ if tokflag {
+ fmt.Printf(">>> IDENTIFIER \"%v\" %v\n", tokname, lineno)
+ }
+ return IDENTIFIER
+ }
+ tokname += string(c)
+ }
+
+ case '%':
+ c = getrune(finput)
+ switch c {
+ case '%':
+ if tokflag {
+ fmt.Printf(">>> MARK %%%% %v\n", lineno)
+ }
+ return MARK
+ case '=':
+ if tokflag {
+ fmt.Printf(">>> PREC %%= %v\n", lineno)
+ }
+ return PREC
+ case '{':
+ if tokflag {
+ fmt.Printf(">>> LCURLY %%{ %v\n", lineno)
+ }
+ return LCURLY
+ }
+
+ getword(c)
+ // find a reserved word
+ for i := range resrv {
+ if tokname == resrv[i].name {
+ if tokflag {
+ fmt.Printf(">>> %%%v %v %v\n", tokname,
+ resrv[i].value-PRIVATE, lineno)
+ }
+ return resrv[i].value
+ }
+ }
+ errorf("invalid escape, or illegal reserved word: %v", tokname)
+
+ case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ numbval = int(c - '0')
+ for {
+ c = getrune(finput)
+ if !isdigit(c) {
+ break
+ }
+ numbval = numbval*10 + int(c-'0')
+ }
+ ungetrune(finput, c)
+ if tokflag {
+ fmt.Printf(">>> NUMBER %v %v\n", numbval, lineno)
+ }
+ return NUMBER
+
+ default:
+ if isword(c) || c == '.' || c == '$' {
+ getword(c)
+ break
+ }
+ if tokflag {
+ fmt.Printf(">>> OPERATOR %v %v\n", string(c), lineno)
+ }
+ return int(c)
+ }
+
+ // look ahead to distinguish IDENTIFIER from IDENTCOLON
+ c = getrune(finput)
+ for c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\r' || c == '/' {
+ if c == '\n' {
+ peekline++
+ }
+ // look for comments
+ if c == '/' {
+ peekline += skipcom()
+ }
+ c = getrune(finput)
+ }
+ if c == ':' {
+ if tokflag {
+ fmt.Printf(">>> IDENTCOLON %v: %v\n", tokname, lineno)
+ }
+ return IDENTCOLON
+ }
+
+ ungetrune(finput, c)
+ if tokflag {
+ fmt.Printf(">>> IDENTIFIER %v %v\n", tokname, lineno)
+ }
+ return IDENTIFIER
+}
+
+func getword(c rune) {
+ tokname = ""
+ for isword(c) || isdigit(c) || c == '_' || c == '.' || c == '$' {
+ tokname += string(c)
+ c = getrune(finput)
+ }
+ ungetrune(finput, c)
+}
+
+//
+// determine the type of a symbol
+//
+func fdtype(t int) int {
+ var v int
+ var s string
+
+ if t >= NTBASE {
+ v = nontrst[t-NTBASE].value
+ s = nontrst[t-NTBASE].name
+ } else {
+ v = TYPE(toklev[t])
+ s = tokset[t].name
+ }
+ if v <= 0 {
+ errorf("must specify type for %v", s)
+ }
+ return v
+}
+
+func chfind(t int, s string) int {
+ if s[0] == ' ' {
+ t = 0
+ }
+ for i := 0; i <= ntokens; i++ {
+ if s == tokset[i].name {
+ return i
+ }
+ }
+ for i := 0; i <= nnonter; i++ {
+ if s == nontrst[i].name {
+ return NTBASE + i
+ }
+ }
+
+ // cannot find name
+ if t > 1 {
+ errorf("%v should have been defined earlier", s)
+ }
+ return defin(t, s)
+}
+
+//
+// copy the union declaration to the output, and the define file if present
+//
+func cpyunion() {
+
+ if !lflag {
+ fmt.Fprintf(ftable, "\n//line %v:%v\n", infile, lineno)
+ }
+ fmt.Fprintf(ftable, "type %sSymType struct", prefix)
+
+ level := 0
+
+out:
+ for {
+ c := getrune(finput)
+ if c == EOF {
+ errorf("EOF encountered while processing %%union")
+ }
+ ftable.WriteRune(c)
+ switch c {
+ case '\n':
+ lineno++
+ case '{':
+ if level == 0 {
+ fmt.Fprintf(ftable, "\n\tyys int")
+ }
+ level++
+ case '}':
+ level--
+ if level == 0 {
+ break out
+ }
+ }
+ }
+ fmt.Fprintf(ftable, "\n\n")
+}
+
+//
+// saves code between %{ and %}
+//
+func cpycode() {
+ lno := lineno
+
+ c := getrune(finput)
+ if c == '\n' {
+ c = getrune(finput)
+ lineno++
+ }
+ if !lflag {
+ fmt.Fprintf(ftable, "\n//line %v:%v\n", infile, lineno)
+ }
+ for c != EOF {
+ if c == '%' {
+ c = getrune(finput)
+ if c == '}' {
+ return
+ }
+ ftable.WriteRune('%')
+ }
+ ftable.WriteRune(c)
+ if c == '\n' {
+ lineno++
+ }
+ c = getrune(finput)
+ }
+ lineno = lno
+ errorf("eof before %%}")
+}
+
+//
+// skip over comments
+// skipcom is called after reading a '/'
+//
+func skipcom() int {
+ var c rune
+
+ c = getrune(finput)
+ if c == '/' {
+ for c != EOF {
+ if c == '\n' {
+ return 1
+ }
+ c = getrune(finput)
+ }
+ errorf("EOF inside comment")
+ return 0
+ }
+ if c != '*' {
+ errorf("illegal comment")
+ }
+
+ nl := 0 // lines skipped
+ c = getrune(finput)
+
+l1:
+ switch c {
+ case '*':
+ c = getrune(finput)
+ if c == '/' {
+ break
+ }
+ goto l1
+
+ case '\n':
+ nl++
+ fallthrough
+
+ default:
+ c = getrune(finput)
+ goto l1
+ }
+ return nl
+}
+
+func dumpprod(curprod []int, max int) {
+ fmt.Printf("\n")
+ for i := 0; i < max; i++ {
+ p := curprod[i]
+ if p < 0 {
+ fmt.Printf("[%v] %v\n", i, p)
+ } else {
+ fmt.Printf("[%v] %v\n", i, symnam(p))
+ }
+ }
+}
+
+//
+// copy action to the next ; or closing }
+//
+func cpyact(curprod []int, max int) {
+
+ if !lflag {
+ fmt.Fprintf(fcode, "\n\t\t//line %v:%v\n\t\t", infile, lineno)
+ }
+
+ lno := lineno
+ brac := 0
+
+loop:
+ for {
+ c := getrune(finput)
+
+ swt:
+ switch c {
+ case ';':
+ if brac == 0 {
+ fcode.WriteRune(c)
+ return
+ }
+
+ case '{':
+ if brac == 0 {
+ }
+ brac++
+
+ case '$':
+ s := 1
+ tok := -1
+ c = getrune(finput)
+
+ // type description
+ if c == '<' {
+ ungetrune(finput, c)
+ if gettok() != TYPENAME {
+ errorf("bad syntax on $<ident> clause")
+ }
+ tok = numbval
+ c = getrune(finput)
+ }
+ if c == '$' {
+ fmt.Fprintf(fcode, "%sVAL", prefix)
+
+ // put out the proper tag...
+ if ntypes != 0 {
+ if tok < 0 {
+ tok = fdtype(curprod[0])
+ }
+ fmt.Fprintf(fcode, ".%v", typeset[tok])
+ }
+ continue loop
+ }
+ if c == '-' {
+ s = -s
+ c = getrune(finput)
+ }
+ j := 0
+ if isdigit(c) {
+ for isdigit(c) {
+ j = j*10 + int(c-'0')
+ c = getrune(finput)
+ }
+ ungetrune(finput, c)
+ j = j * s
+ if j >= max {
+ errorf("Illegal use of $%v", j)
+ }
+ } else if isword(c) || c == '_' || c == '.' {
+ // look for $name
+ ungetrune(finput, c)
+ if gettok() != IDENTIFIER {
+ errorf("$ must be followed by an identifier")
+ }
+ tokn := chfind(2, tokname)
+ fnd := -1
+ c = getrune(finput)
+ if c != '@' {
+ ungetrune(finput, c)
+ } else if gettok() != NUMBER {
+ errorf("@ must be followed by number")
+ } else {
+ fnd = numbval
+ }
+ for j = 1; j < max; j++ {
+ if tokn == curprod[j] {
+ fnd--
+ if fnd <= 0 {
+ break
+ }
+ }
+ }
+ if j >= max {
+ errorf("$name or $name@number not found")
+ }
+ } else {
+ fcode.WriteRune('$')
+ if s < 0 {
+ fcode.WriteRune('-')
+ }
+ ungetrune(finput, c)
+ continue loop
+ }
+ fmt.Fprintf(fcode, "%sS[%spt-%v]", prefix, prefix, max-j-1)
+
+ // put out the proper tag
+ if ntypes != 0 {
+ if j <= 0 && tok < 0 {
+ errorf("must specify type of $%v", j)
+ }
+ if tok < 0 {
+ tok = fdtype(curprod[j])
+ }
+ fmt.Fprintf(fcode, ".%v", typeset[tok])
+ }
+ continue loop
+
+ case '}':
+ brac--
+ if brac != 0 {
+ break
+ }
+ fcode.WriteRune(c)
+ return
+
+ case '/':
+ nc := getrune(finput)
+ if nc != '/' && nc != '*' {
+ ungetrune(finput, nc)
+ break
+ }
+ // a comment
+ fcode.WriteRune(c)
+ fcode.WriteRune(nc)
+ c = getrune(finput)
+ for c != EOF {
+ switch {
+ case c == '\n':
+ lineno++
+ if nc == '/' { // end of // comment
+ break swt
+ }
+ case c == '*' && nc == '*': // end of /* comment?
+ nnc := getrune(finput)
+ if nnc == '/' {
+ fcode.WriteRune('*')
+ fcode.WriteRune('/')
+ c = getrune(finput)
+ break swt
+ }
+ ungetrune(finput, nnc)
+ }
+ fcode.WriteRune(c)
+ c = getrune(finput)
+ }
+ errorf("EOF inside comment")
+
+ case '\'', '"':
+ // character string or constant
+ match := c
+ fcode.WriteRune(c)
+ c = getrune(finput)
+ for c != EOF {
+ if c == '\\' {
+ fcode.WriteRune(c)
+ c = getrune(finput)
+ if c == '\n' {
+ lineno++
+ }
+ } else if c == match {
+ break swt
+ }
+ if c == '\n' {
+ errorf("newline in string or char const")
+ }
+ fcode.WriteRune(c)
+ c = getrune(finput)
+ }
+ errorf("EOF in string or character constant")
+
+ case EOF:
+ lineno = lno
+ errorf("action does not terminate")
+
+ case '\n':
+ fmt.Fprint(fcode, "\n\t")
+ lineno++
+ continue loop
+ }
+
+ fcode.WriteRune(c)
+ }
+}
+
+func openup() {
+ infile = flag.Arg(0)
+ finput = open(infile)
+ if finput == nil {
+ errorf("cannot open %v", infile)
+ }
+
+ foutput = nil
+ if vflag != "" {
+ foutput = create(vflag)
+ if foutput == nil {
+ errorf("can't create file %v", vflag)
+ }
+ }
+
+ ftable = nil
+ if oflag == "" {
+ oflag = "y.go"
+ }
+ ftable = create(oflag)
+ if ftable == nil {
+ errorf("can't create file %v", oflag)
+ }
+
+}
+
+//
+// return a pointer to the name of symbol i
+//
+func symnam(i int) string {
+ var s string
+
+ if i >= NTBASE {
+ s = nontrst[i-NTBASE].name
+ } else {
+ s = tokset[i].name
+ }
+ if s[0] == ' ' {
+ s = s[1:]
+ }
+ return s
+}
+
+//
+// set elements 0 through n-1 to c
+//
+func aryfil(v []int, n, c int) {
+ for i := 0; i < n; i++ {
+ v[i] = c
+ }
+}
+
+//
+// compute an array with the beginnings of productions yielding given nonterminals
+// The array pres points to these lists
+// the array pyield has the lists: the total size is only NPROD+1
+//
+func cpres() {
+ pres = make([][][]int, nnonter+1)
+ curres := make([][]int, nprod)
+
+ if false {
+ for j := 0; j <= nnonter; j++ {
+ fmt.Printf("nnonter[%v] = %v\n", j, nontrst[j].name)
+ }
+ for j := 0; j < nprod; j++ {
+ fmt.Printf("prdptr[%v][0] = %v+NTBASE\n", j, prdptr[j][0]-NTBASE)
+ }
+ }
+
+ fatfl = 0 // make undefined symbols nonfatal
+ for i := 0; i <= nnonter; i++ {
+ n := 0
+ c := i + NTBASE
+ for j := 0; j < nprod; j++ {
+ if prdptr[j][0] == c {
+ curres[n] = prdptr[j][1:]
+ n++
+ }
+ }
+ if n == 0 {
+ errorf("nonterminal %v not defined", nontrst[i].name)
+ continue
+ }
+ pres[i] = make([][]int, n)
+ copy(pres[i], curres)
+ }
+ fatfl = 1
+ if nerrors != 0 {
+ summary()
+ exit(1)
+ }
+}
+
+func dumppres() {
+ for i := 0; i <= nnonter; i++ {
+ fmt.Printf("nonterm %d\n", i)
+ curres := pres[i]
+ for j := 0; j < len(curres); j++ {
+ fmt.Printf("\tproduction %d:", j)
+ prd := curres[j]
+ for k := 0; k < len(prd); k++ {
+ fmt.Printf(" %d", prd[k])
+ }
+ fmt.Print("\n")
+ }
+ }
+}
+
+//
+// mark nonterminals which derive the empty string
+// also, look for nonterminals which don't derive any token strings
+//
+func cempty() {
+ var i, p, np int
+ var prd []int
+
+ pempty = make([]int, nnonter+1)
+
+ // first, use the array pempty to detect productions that can never be reduced
+ // set pempty to WHONOWS
+ aryfil(pempty, nnonter+1, WHOKNOWS)
+
+ // now, look at productions, marking nonterminals which derive something
+more:
+ for {
+ for i = 0; i < nprod; i++ {
+ prd = prdptr[i]
+ if pempty[prd[0]-NTBASE] != 0 {
+ continue
+ }
+ np = len(prd) - 1
+ for p = 1; p < np; p++ {
+ if prd[p] >= NTBASE && pempty[prd[p]-NTBASE] == WHOKNOWS {
+ break
+ }
+ }
+ // production can be derived
+ if p == np {
+ pempty[prd[0]-NTBASE] = OK
+ continue more
+ }
+ }
+ break
+ }
+
+ // now, look at the nonterminals, to see if they are all OK
+ for i = 0; i <= nnonter; i++ {
+ // the added production rises or falls as the start symbol ...
+ if i == 0 {
+ continue
+ }
+ if pempty[i] != OK {
+ fatfl = 0
+ errorf("nonterminal " + nontrst[i].name + " never derives any token string")
+ }
+ }
+
+ if nerrors != 0 {
+ summary()
+ exit(1)
+ }
+
+ // now, compute the pempty array, to see which nonterminals derive the empty string
+ // set pempty to WHOKNOWS
+ aryfil(pempty, nnonter+1, WHOKNOWS)
+
+ // loop as long as we keep finding empty nonterminals
+
+again:
+ for {
+ next:
+ for i = 1; i < nprod; i++ {
+ // not known to be empty
+ prd = prdptr[i]
+ if pempty[prd[0]-NTBASE] != WHOKNOWS {
+ continue
+ }
+ np = len(prd) - 1
+ for p = 1; p < np; p++ {
+ if prd[p] < NTBASE || pempty[prd[p]-NTBASE] != EMPTY {
+ continue next
+ }
+ }
+
+ // we have a nontrivially empty nonterminal
+ pempty[prd[0]-NTBASE] = EMPTY
+
+ // got one ... try for another
+ continue again
+ }
+ return
+ }
+}
+
+func dumpempty() {
+ for i := 0; i <= nnonter; i++ {
+ if pempty[i] == EMPTY {
+ fmt.Printf("non-term %d %s matches empty\n", i, symnam(i+NTBASE))
+ }
+ }
+}
+
+//
+// compute an array with the first of nonterminals
+//
+func cpfir() {
+ var s, n, p, np, ch, i int
+ var curres [][]int
+ var prd []int
+
+ wsets = make([]Wset, nnonter+WSETINC)
+ pfirst = make([]Lkset, nnonter+1)
+ for i = 0; i <= nnonter; i++ {
+ wsets[i].ws = mkset()
+ pfirst[i] = mkset()
+ curres = pres[i]
+ n = len(curres)
+
+ // initially fill the sets
+ for s = 0; s < n; s++ {
+ prd = curres[s]
+ np = len(prd) - 1
+ for p = 0; p < np; p++ {
+ ch = prd[p]
+ if ch < NTBASE {
+ setbit(pfirst[i], ch)
+ break
+ }
+ if pempty[ch-NTBASE] == 0 {
+ break
+ }
+ }
+ }
+ }
+
+ // now, reflect transitivity
+ changes := 1
+ for changes != 0 {
+ changes = 0
+ for i = 0; i <= nnonter; i++ {
+ curres = pres[i]
+ n = len(curres)
+ for s = 0; s < n; s++ {
+ prd = curres[s]
+ np = len(prd) - 1
+ for p = 0; p < np; p++ {
+ ch = prd[p] - NTBASE
+ if ch < 0 {
+ break
+ }
+ changes |= setunion(pfirst[i], pfirst[ch])
+ if pempty[ch] == 0 {
+ break
+ }
+ }
+ }
+ }
+ }
+
+ if indebug == 0 {
+ return
+ }
+ if foutput != nil {
+ for i = 0; i <= nnonter; i++ {
+ fmt.Fprintf(foutput, "\n%v: %v %v\n",
+ nontrst[i].name, pfirst[i], pempty[i])
+ }
+ }
+}
+
+//
+// generate the states
+//
+func stagen() {
+ // initialize
+ nstate = 0
+ tstates = make([]int, ntokens+1) // states generated by terminal gotos
+ ntstates = make([]int, nnonter+1) // states generated by nonterminal gotos
+ amem = make([]int, ACTSIZE)
+ memp = 0
+
+ clset = mkset()
+ pstate[0] = 0
+ pstate[1] = 0
+ aryfil(clset, tbitset, 0)
+ putitem(Pitem{prdptr[0], 0, 0, 0}, clset)
+ tystate[0] = MUSTDO
+ nstate = 1
+ pstate[2] = pstate[1]
+
+ //
+ // now, the main state generation loop
+ // first pass generates all of the states
+ // later passes fix up lookahead
+ // could be sped up a lot by remembering
+ // results of the first pass rather than recomputing
+ //
+ first := 1
+ for more := 1; more != 0; first = 0 {
+ more = 0
+ for i := 0; i < nstate; i++ {
+ if tystate[i] != MUSTDO {
+ continue
+ }
+
+ tystate[i] = DONE
+ aryfil(temp1, nnonter+1, 0)
+
+ // take state i, close it, and do gotos
+ closure(i)
+
+ // generate goto's
+ for p := 0; p < cwp; p++ {
+ pi := wsets[p]
+ if pi.flag != 0 {
+ continue
+ }
+ wsets[p].flag = 1
+ c := pi.pitem.first
+ if c <= 1 {
+ if pstate[i+1]-pstate[i] <= p {
+ tystate[i] = MUSTLOOKAHEAD
+ }
+ continue
+ }
+
+ // do a goto on c
+ putitem(wsets[p].pitem, wsets[p].ws)
+ for q := p + 1; q < cwp; q++ {
+ // this item contributes to the goto
+ if c == wsets[q].pitem.first {
+ putitem(wsets[q].pitem, wsets[q].ws)
+ wsets[q].flag = 1
+ }
+ }
+
+ if c < NTBASE {
+ state(c) // register new state
+ } else {
+ temp1[c-NTBASE] = state(c)
+ }
+ }
+
+ if gsdebug != 0 && foutput != nil {
+ fmt.Fprintf(foutput, "%v: ", i)
+ for j := 0; j <= nnonter; j++ {
+ if temp1[j] != 0 {
+ fmt.Fprintf(foutput, "%v %v,", nontrst[j].name, temp1[j])
+ }
+ }
+ fmt.Fprintf(foutput, "\n")
+ }
+
+ if first != 0 {
+ indgo[i] = apack(temp1[1:], nnonter-1) - 1
+ }
+
+ more++
+ }
+ }
+}
+
+//
+// generate the closure of state i
+//
+func closure(i int) {
+ zzclose++
+
+ // first, copy kernel of state i to wsets
+ cwp = 0
+ q := pstate[i+1]
+ for p := pstate[i]; p < q; p++ {
+ wsets[cwp].pitem = statemem[p].pitem
+ wsets[cwp].flag = 1 // this item must get closed
+ copy(wsets[cwp].ws, statemem[p].look)
+ cwp++
+ }
+
+ // now, go through the loop, closing each item
+ work := 1
+ for work != 0 {
+ work = 0
+ for u := 0; u < cwp; u++ {
+ if wsets[u].flag == 0 {
+ continue
+ }
+
+ // dot is before c
+ c := wsets[u].pitem.first
+ if c < NTBASE {
+ wsets[u].flag = 0
+ // only interesting case is where . is before nonterminal
+ continue
+ }
+
+ // compute the lookahead
+ aryfil(clset, tbitset, 0)
+
+ // find items involving c
+ for v := u; v < cwp; v++ {
+ if wsets[v].flag != 1 || wsets[v].pitem.first != c {
+ continue
+ }
+ pi := wsets[v].pitem.prod
+ ipi := wsets[v].pitem.off + 1
+
+ wsets[v].flag = 0
+ if nolook != 0 {
+ continue
+ }
+
+ ch := pi[ipi]
+ ipi++
+ for ch > 0 {
+ // terminal symbol
+ if ch < NTBASE {
+ setbit(clset, ch)
+ break
+ }
+
+ // nonterminal symbol
+ setunion(clset, pfirst[ch-NTBASE])
+ if pempty[ch-NTBASE] == 0 {
+ break
+ }
+ ch = pi[ipi]
+ ipi++
+ }
+ if ch <= 0 {
+ setunion(clset, wsets[v].ws)
+ }
+ }
+
+ //
+ // now loop over productions derived from c
+ //
+ curres := pres[c-NTBASE]
+ n := len(curres)
+
+ nexts:
+ // initially fill the sets
+ for s := 0; s < n; s++ {
+ prd := curres[s]
+
+ //
+ // put these items into the closure
+ // is the item there
+ //
+ for v := 0; v < cwp; v++ {
+ // yes, it is there
+ if wsets[v].pitem.off == 0 &&
+ aryeq(wsets[v].pitem.prod, prd) != 0 {
+ if nolook == 0 &&
+ setunion(wsets[v].ws, clset) != 0 {
+ wsets[v].flag = 1
+ work = 1
+ }
+ continue nexts
+ }
+ }
+
+ // not there; make a new entry
+ if cwp >= len(wsets) {
+ awsets := make([]Wset, cwp+WSETINC)
+ copy(awsets, wsets)
+ wsets = awsets
+ }
+ wsets[cwp].pitem = Pitem{prd, 0, prd[0], -prd[len(prd)-1]}
+ wsets[cwp].flag = 1
+ wsets[cwp].ws = mkset()
+ if nolook == 0 {
+ work = 1
+ copy(wsets[cwp].ws, clset)
+ }
+ cwp++
+ }
+ }
+ }
+
+ // have computed closure; flags are reset; return
+ if cldebug != 0 && foutput != nil {
+ fmt.Fprintf(foutput, "\nState %v, nolook = %v\n", i, nolook)
+ for u := 0; u < cwp; u++ {
+ if wsets[u].flag != 0 {
+ fmt.Fprintf(foutput, "flag set\n")
+ }
+ wsets[u].flag = 0
+ fmt.Fprintf(foutput, "\t%v", writem(wsets[u].pitem))
+ prlook(wsets[u].ws)
+ fmt.Fprintf(foutput, "\n")
+ }
+ }
+}
+
+//
+// sorts last state,and sees if it equals earlier ones. returns state number
+//
+func state(c int) int {
+ zzstate++
+ p1 := pstate[nstate]
+ p2 := pstate[nstate+1]
+ if p1 == p2 {
+ return 0 // null state
+ }
+
+ // sort the items
+ var k, l int
+ for k = p1 + 1; k < p2; k++ { // make k the biggest
+ for l = k; l > p1; l-- {
+ if statemem[l].pitem.prodno < statemem[l-1].pitem.prodno ||
+ statemem[l].pitem.prodno == statemem[l-1].pitem.prodno &&
+ statemem[l].pitem.off < statemem[l-1].pitem.off {
+ s := statemem[l]
+ statemem[l] = statemem[l-1]
+ statemem[l-1] = s
+ } else {
+ break
+ }
+ }
+ }
+
+ size1 := p2 - p1 // size of state
+
+ var i int
+ if c >= NTBASE {
+ i = ntstates[c-NTBASE]
+ } else {
+ i = tstates[c]
+ }
+
+look:
+ for ; i != 0; i = mstates[i] {
+ // get ith state
+ q1 := pstate[i]
+ q2 := pstate[i+1]
+ size2 := q2 - q1
+ if size1 != size2 {
+ continue
+ }
+ k = p1
+ for l = q1; l < q2; l++ {
+ if aryeq(statemem[l].pitem.prod, statemem[k].pitem.prod) == 0 ||
+ statemem[l].pitem.off != statemem[k].pitem.off {
+ continue look
+ }
+ k++
+ }
+
+ // found it
+ pstate[nstate+1] = pstate[nstate] // delete last state
+
+ // fix up lookaheads
+ if nolook != 0 {
+ return i
+ }
+ k = p1
+ for l = q1; l < q2; l++ {
+ if setunion(statemem[l].look, statemem[k].look) != 0 {
+ tystate[i] = MUSTDO
+ }
+ k++
+ }
+ return i
+ }
+
+ // state is new
+ zznewstate++
+ if nolook != 0 {
+ errorf("yacc state/nolook error")
+ }
+ pstate[nstate+2] = p2
+ if nstate+1 >= NSTATES {
+ errorf("too many states")
+ }
+ if c >= NTBASE {
+ mstates[nstate] = ntstates[c-NTBASE]
+ ntstates[c-NTBASE] = nstate
+ } else {
+ mstates[nstate] = tstates[c]
+ tstates[c] = nstate
+ }
+ tystate[nstate] = MUSTDO
+ nstate++
+ return nstate - 1
+}
+
+func putitem(p Pitem, set Lkset) {
+ p.off++
+ p.first = p.prod[p.off]
+
+ if pidebug != 0 && foutput != nil {
+ fmt.Fprintf(foutput, "putitem(%v), state %v\n", writem(p), nstate)
+ }
+ j := pstate[nstate+1]
+ if j >= len(statemem) {
+ asm := make([]Item, j+STATEINC)
+ copy(asm, statemem)
+ statemem = asm
+ }
+ statemem[j].pitem = p
+ if nolook == 0 {
+ s := mkset()
+ copy(s, set)
+ statemem[j].look = s
+ }
+ j++
+ pstate[nstate+1] = j
+}
+
+//
+// creates output string for item pointed to by pp
+//
+func writem(pp Pitem) string {
+ var i int
+
+ p := pp.prod
+ q := chcopy(nontrst[prdptr[pp.prodno][0]-NTBASE].name) + ": "
+ npi := pp.off
+
+ pi := aryeq(p, prdptr[pp.prodno])
+
+ for {
+ c := ' '
+ if pi == npi {
+ c = '.'
+ }
+ q += string(c)
+
+ i = p[pi]
+ pi++
+ if i <= 0 {
+ break
+ }
+ q += chcopy(symnam(i))
+ }
+
+ // an item calling for a reduction
+ i = p[npi]
+ if i < 0 {
+ q += fmt.Sprintf(" (%v)", -i)
+ }
+
+ return q
+}
+
+//
+// pack state i from temp1 into amem
+//
+func apack(p []int, n int) int {
+ //
+ // we don't need to worry about checking because
+ // we will only look at entries known to be there...
+ // eliminate leading and trailing 0's
+ //
+ off := 0
+ pp := 0
+ for ; pp <= n && p[pp] == 0; pp++ {
+ off--
+ }
+
+ // no actions
+ if pp > n {
+ return 0
+ }
+ for ; n > pp && p[n] == 0; n-- {
+ }
+ p = p[pp : n+1]
+
+ // now, find a place for the elements from p to q, inclusive
+ r := len(amem) - len(p)
+
+nextk:
+ for rr := 0; rr <= r; rr++ {
+ qq := rr
+ for pp = 0; pp < len(p); pp++ {
+ if p[pp] != 0 {
+ if p[pp] != amem[qq] && amem[qq] != 0 {
+ continue nextk
+ }
+ }
+ qq++
+ }
+
+ // we have found an acceptable k
+ if pkdebug != 0 && foutput != nil {
+ fmt.Fprintf(foutput, "off = %v, k = %v\n", off+rr, rr)
+ }
+ qq = rr
+ for pp = 0; pp < len(p); pp++ {
+ if p[pp] != 0 {
+ if qq > memp {
+ memp = qq
+ }
+ amem[qq] = p[pp]
+ }
+ qq++
+ }
+ if pkdebug != 0 && foutput != nil {
+ for pp = 0; pp <= memp; pp += 10 {
+ fmt.Fprintf(foutput, "\n")
+ for qq = pp; qq <= pp+9; qq++ {
+ fmt.Fprintf(foutput, "%v ", amem[qq])
+ }
+ fmt.Fprintf(foutput, "\n")
+ }
+ }
+ return off + rr
+ }
+ errorf("no space in action table")
+ return 0
+}
+
+//
+// print the output for the states
+//
+func output() {
+ var c, u, v int
+
+ fmt.Fprintf(ftable, "\n//line yacctab:1\n")
+ fmt.Fprintf(ftable, "var %sExca = []int{\n", prefix)
+
+ noset := mkset()
+
+ // output the stuff for state i
+ for i := 0; i < nstate; i++ {
+ nolook = 0
+ if tystate[i] != MUSTLOOKAHEAD {
+ nolook = 1
+ }
+ closure(i)
+
+ // output actions
+ nolook = 1
+ aryfil(temp1, ntokens+nnonter+1, 0)
+ for u = 0; u < cwp; u++ {
+ c = wsets[u].pitem.first
+ if c > 1 && c < NTBASE && temp1[c] == 0 {
+ for v = u; v < cwp; v++ {
+ if c == wsets[v].pitem.first {
+ putitem(wsets[v].pitem, noset)
+ }
+ }
+ temp1[c] = state(c)
+ } else if c > NTBASE {
+ c -= NTBASE
+ if temp1[c+ntokens] == 0 {
+ temp1[c+ntokens] = amem[indgo[i]+c]
+ }
+ }
+ }
+ if i == 1 {
+ temp1[1] = ACCEPTCODE
+ }
+
+ // now, we have the shifts; look at the reductions
+ lastred = 0
+ for u = 0; u < cwp; u++ {
+ c = wsets[u].pitem.first
+
+ // reduction
+ if c > 0 {
+ continue
+ }
+ lastred = -c
+ us := wsets[u].ws
+ for k := 0; k <= ntokens; k++ {
+ if bitset(us, k) == 0 {
+ continue
+ }
+ if temp1[k] == 0 {
+ temp1[k] = c
+ } else if temp1[k] < 0 { // reduce/reduce conflict
+ if foutput != nil {
+ fmt.Fprintf(foutput,
+ "\n %v: reduce/reduce conflict (red'ns "+
+ "%v and %v) on %v",
+ i, -temp1[k], lastred, symnam(k))
+ }
+ if -temp1[k] > lastred {
+ temp1[k] = -lastred
+ }
+ zzrrconf++
+ } else {
+ // potential shift/reduce conflict
+ precftn(lastred, k, i)
+ }
+ }
+ }
+ wract(i)
+ }
+
+ fmt.Fprintf(ftable, "}\n")
+ ftable.WriteRune('\n')
+ fmt.Fprintf(ftable, "const %sNprod = %v\n", prefix, nprod)
+ fmt.Fprintf(ftable, "const %sPrivate = %v\n", prefix, PRIVATE)
+ ftable.WriteRune('\n')
+ fmt.Fprintf(ftable, "var %sTokenNames []string\n", prefix)
+ fmt.Fprintf(ftable, "var %sStates []string\n", prefix)
+}
+
+//
+// decide a shift/reduce conflict by precedence.
+// r is a rule number, t a token number
+// the conflict is in state s
+// temp1[t] is changed to reflect the action
+//
+func precftn(r, t, s int) {
+ var action int
+
+ lp := levprd[r]
+ lt := toklev[t]
+ if PLEVEL(lt) == 0 || PLEVEL(lp) == 0 {
+ // conflict
+ if foutput != nil {
+ fmt.Fprintf(foutput,
+ "\n%v: shift/reduce conflict (shift %v(%v), red'n %v(%v)) on %v",
+ s, temp1[t], PLEVEL(lt), r, PLEVEL(lp), symnam(t))
+ }
+ zzsrconf++
+ return
+ }
+ if PLEVEL(lt) == PLEVEL(lp) {
+ action = ASSOC(lt)
+ } else if PLEVEL(lt) > PLEVEL(lp) {
+ action = RASC // shift
+ } else {
+ action = LASC
+ } // reduce
+ switch action {
+ case BASC: // error action
+ temp1[t] = ERRCODE
+ case LASC: // reduce
+ temp1[t] = -r
+ }
+}
+
+//
+// output state i
+// temp1 has the actions, lastred the default
+//
+func wract(i int) {
+ var p, p1 int
+
+ // find the best choice for lastred
+ lastred = 0
+ ntimes := 0
+ for j := 0; j <= ntokens; j++ {
+ if temp1[j] >= 0 {
+ continue
+ }
+ if temp1[j]+lastred == 0 {
+ continue
+ }
+ // count the number of appearances of temp1[j]
+ count := 0
+ tred := -temp1[j]
+ levprd[tred] |= REDFLAG
+ for p = 0; p <= ntokens; p++ {
+ if temp1[p]+tred == 0 {
+ count++
+ }
+ }
+ if count > ntimes {
+ lastred = tred
+ ntimes = count
+ }
+ }
+
+ //
+ // for error recovery, arrange that, if there is a shift on the
+ // error recovery token, `error', that the default be the error action
+ //
+ if temp1[2] > 0 {
+ lastred = 0
+ }
+
+ // clear out entries in temp1 which equal lastred
+ // count entries in optst table
+ n := 0
+ for p = 0; p <= ntokens; p++ {
+ p1 = temp1[p]
+ if p1+lastred == 0 {
+ temp1[p] = 0
+ p1 = 0
+ }
+ if p1 > 0 && p1 != ACCEPTCODE && p1 != ERRCODE {
+ n++
+ }
+ }
+
+ wrstate(i)
+ defact[i] = lastred
+ flag := 0
+ os := make([]int, n*2)
+ n = 0
+ for p = 0; p <= ntokens; p++ {
+ p1 = temp1[p]
+ if p1 != 0 {
+ if p1 < 0 {
+ p1 = -p1
+ } else if p1 == ACCEPTCODE {
+ p1 = -1
+ } else if p1 == ERRCODE {
+ p1 = 0
+ } else {
+ os[n] = p
+ n++
+ os[n] = p1
+ n++
+ zzacent++
+ continue
+ }
+ if flag == 0 {
+ fmt.Fprintf(ftable, "\t-1, %v,\n", i)
+ }
+ flag++
+ fmt.Fprintf(ftable, "\t%v, %v,\n", p, p1)
+ zzexcp++
+ }
+ }
+ if flag != 0 {
+ defact[i] = -2
+ fmt.Fprintf(ftable, "\t-2, %v,\n", lastred)
+ }
+ optst[i] = os
+}
+
+//
+// writes state i
+//
+func wrstate(i int) {
+ var j0, j1, u int
+ var pp, qq int
+
+ if foutput == nil {
+ return
+ }
+ fmt.Fprintf(foutput, "\nstate %v\n", i)
+ qq = pstate[i+1]
+ for pp = pstate[i]; pp < qq; pp++ {
+ fmt.Fprintf(foutput, "\t%v\n", writem(statemem[pp].pitem))
+ }
+ if tystate[i] == MUSTLOOKAHEAD {
+ // print out empty productions in closure
+ for u = pstate[i+1] - pstate[i]; u < cwp; u++ {
+ if wsets[u].pitem.first < 0 {
+ fmt.Fprintf(foutput, "\t%v\n", writem(wsets[u].pitem))
+ }
+ }
+ }
+
+ // check for state equal to another
+ for j0 = 0; j0 <= ntokens; j0++ {
+ j1 = temp1[j0]
+ if j1 != 0 {
+ fmt.Fprintf(foutput, "\n\t%v ", symnam(j0))
+
+ // shift, error, or accept
+ if j1 > 0 {
+ if j1 == ACCEPTCODE {
+ fmt.Fprintf(foutput, "accept")
+ } else if j1 == ERRCODE {
+ fmt.Fprintf(foutput, "error")
+ } else {
+ fmt.Fprintf(foutput, "shift %v", j1)
+ }
+ } else {
+ fmt.Fprintf(foutput, "reduce %v (src line %v)", -j1, rlines[-j1])
+ }
+ }
+ }
+
+ // output the final production
+ if lastred != 0 {
+ fmt.Fprintf(foutput, "\n\t. reduce %v (src line %v)\n\n",
+ lastred, rlines[lastred])
+ } else {
+ fmt.Fprintf(foutput, "\n\t. error\n\n")
+ }
+
+ // now, output nonterminal actions
+ j1 = ntokens
+ for j0 = 1; j0 <= nnonter; j0++ {
+ j1++
+ if temp1[j1] != 0 {
+ fmt.Fprintf(foutput, "\t%v goto %v\n", symnam(j0+NTBASE), temp1[j1])
+ }
+ }
+}
+
+//
+// output the gotos for the nontermninals
+//
+func go2out() {
+ for i := 1; i <= nnonter; i++ {
+ go2gen(i)
+
+ // find the best one to make default
+ best := -1
+ times := 0
+
+ // is j the most frequent
+ for j := 0; j < nstate; j++ {
+ if tystate[j] == 0 {
+ continue
+ }
+ if tystate[j] == best {
+ continue
+ }
+
+ // is tystate[j] the most frequent
+ count := 0
+ cbest := tystate[j]
+ for k := j; k < nstate; k++ {
+ if tystate[k] == cbest {
+ count++
+ }
+ }
+ if count > times {
+ best = cbest
+ times = count
+ }
+ }
+
+ // best is now the default entry
+ zzgobest += times - 1
+ n := 0
+ for j := 0; j < nstate; j++ {
+ if tystate[j] != 0 && tystate[j] != best {
+ n++
+ }
+ }
+ goent := make([]int, 2*n+1)
+ n = 0
+ for j := 0; j < nstate; j++ {
+ if tystate[j] != 0 && tystate[j] != best {
+ goent[n] = j
+ n++
+ goent[n] = tystate[j]
+ n++
+ zzgoent++
+ }
+ }
+
+ // now, the default
+ if best == -1 {
+ best = 0
+ }
+
+ zzgoent++
+ goent[n] = best
+ yypgo[i] = goent
+ }
+}
+
+//
+// output the gotos for nonterminal c
+//
+func go2gen(c int) {
+ var i, cc, p, q int
+
+ // first, find nonterminals with gotos on c
+ aryfil(temp1, nnonter+1, 0)
+ temp1[c] = 1
+ work := 1
+ for work != 0 {
+ work = 0
+ for i = 0; i < nprod; i++ {
+ // cc is a nonterminal with a goto on c
+ cc = prdptr[i][1] - NTBASE
+ if cc >= 0 && temp1[cc] != 0 {
+ // thus, the left side of production i does too
+ cc = prdptr[i][0] - NTBASE
+ if temp1[cc] == 0 {
+ work = 1
+ temp1[cc] = 1
+ }
+ }
+ }
+ }
+
+ // now, we have temp1[c] = 1 if a goto on c in closure of cc
+ if g2debug != 0 && foutput != nil {
+ fmt.Fprintf(foutput, "%v: gotos on ", nontrst[c].name)
+ for i = 0; i <= nnonter; i++ {
+ if temp1[i] != 0 {
+ fmt.Fprintf(foutput, "%v ", nontrst[i].name)
+ }
+ }
+ fmt.Fprintf(foutput, "\n")
+ }
+
+ // now, go through and put gotos into tystate
+ aryfil(tystate, nstate, 0)
+ for i = 0; i < nstate; i++ {
+ q = pstate[i+1]
+ for p = pstate[i]; p < q; p++ {
+ cc = statemem[p].pitem.first
+ if cc >= NTBASE {
+ // goto on c is possible
+ if temp1[cc-NTBASE] != 0 {
+ tystate[i] = amem[indgo[i]+c]
+ break
+ }
+ }
+ }
+ }
+}
+
+//
+// in order to free up the mem and amem arrays for the optimizer,
+// and still be able to output yyr1, etc., after the sizes of
+// the action array is known, we hide the nonterminals
+// derived by productions in levprd.
+//
+func hideprod() {
+ nred := 0
+ levprd[0] = 0
+ for i := 1; i < nprod; i++ {
+ if (levprd[i] & REDFLAG) == 0 {
+ if foutput != nil {
+ fmt.Fprintf(foutput, "Rule not reduced: %v\n",
+ writem(Pitem{prdptr[i], 0, 0, i}))
+ }
+ fmt.Printf("rule %v never reduced\n", writem(Pitem{prdptr[i], 0, 0, i}))
+ nred++
+ }
+ levprd[i] = prdptr[i][0] - NTBASE
+ }
+ if nred != 0 {
+ fmt.Printf("%v rules never reduced\n", nred)
+ }
+}
+
+func callopt() {
+ var j, k, p, q, i int
+ var v []int
+
+ pgo = make([]int, nnonter+1)
+ pgo[0] = 0
+ maxoff = 0
+ maxspr = 0
+ for i = 0; i < nstate; i++ {
+ k = 32000
+ j = 0
+ v = optst[i]
+ q = len(v)
+ for p = 0; p < q; p += 2 {
+ if v[p] > j {
+ j = v[p]
+ }
+ if v[p] < k {
+ k = v[p]
+ }
+ }
+
+ // nontrivial situation
+ if k <= j {
+ // j is now the range
+ // j -= k; // call scj
+ if k > maxoff {
+ maxoff = k
+ }
+ }
+ tystate[i] = q + 2*j
+ if j > maxspr {
+ maxspr = j
+ }
+ }
+
+ // initialize ggreed table
+ ggreed = make([]int, nnonter+1)
+ for i = 1; i <= nnonter; i++ {
+ ggreed[i] = 1
+ j = 0
+
+ // minimum entry index is always 0
+ v = yypgo[i]
+ q = len(v) - 1
+ for p = 0; p < q; p += 2 {
+ ggreed[i] += 2
+ if v[p] > j {
+ j = v[p]
+ }
+ }
+ ggreed[i] = ggreed[i] + 2*j
+ if j > maxoff {
+ maxoff = j
+ }
+ }
+
+ // now, prepare to put the shift actions into the amem array
+ for i = 0; i < ACTSIZE; i++ {
+ amem[i] = 0
+ }
+ maxa = 0
+ for i = 0; i < nstate; i++ {
+ if tystate[i] == 0 && adb > 1 {
+ fmt.Fprintf(ftable, "State %v: null\n", i)
+ }
+ indgo[i] = yyFlag
+ }
+
+ i = nxti()
+ for i != NOMORE {
+ if i >= 0 {
+ stin(i)
+ } else {
+ gin(-i)
+ }
+ i = nxti()
+ }
+
+ // print amem array
+ if adb > 2 {
+ for p = 0; p <= maxa; p += 10 {
+ fmt.Fprintf(ftable, "%v ", p)
+ for i = 0; i < 10; i++ {
+ fmt.Fprintf(ftable, "%v ", amem[p+i])
+ }
+ ftable.WriteRune('\n')
+ }
+ }
+
+ aoutput()
+ osummary()
+}
+
+//
+// finds the next i
+//
+func nxti() int {
+ max := 0
+ maxi := 0
+ for i := 1; i <= nnonter; i++ {
+ if ggreed[i] >= max {
+ max = ggreed[i]
+ maxi = -i
+ }
+ }
+ for i := 0; i < nstate; i++ {
+ if tystate[i] >= max {
+ max = tystate[i]
+ maxi = i
+ }
+ }
+ if max == 0 {
+ return NOMORE
+ }
+ return maxi
+}
+
+func gin(i int) {
+ var s int
+
+ // enter gotos on nonterminal i into array amem
+ ggreed[i] = 0
+
+ q := yypgo[i]
+ nq := len(q) - 1
+
+ // now, find amem place for it
+nextgp:
+ for p := 0; p < ACTSIZE; p++ {
+ if amem[p] != 0 {
+ continue
+ }
+ for r := 0; r < nq; r += 2 {
+ s = p + q[r] + 1
+ if s > maxa {
+ maxa = s
+ if maxa >= ACTSIZE {
+ errorf("a array overflow")
+ }
+ }
+ if amem[s] != 0 {
+ continue nextgp
+ }
+ }
+
+ // we have found amem spot
+ amem[p] = q[nq]
+ if p > maxa {
+ maxa = p
+ }
+ for r := 0; r < nq; r += 2 {
+ s = p + q[r] + 1
+ amem[s] = q[r+1]
+ }
+ pgo[i] = p
+ if adb > 1 {
+ fmt.Fprintf(ftable, "Nonterminal %v, entry at %v\n", i, pgo[i])
+ }
+ return
+ }
+ errorf("cannot place goto %v\n", i)
+}
+
+func stin(i int) {
+ var s int
+
+ tystate[i] = 0
+
+ // enter state i into the amem array
+ q := optst[i]
+ nq := len(q)
+
+nextn:
+ // find an acceptable place
+ for n := -maxoff; n < ACTSIZE; n++ {
+ flag := 0
+ for r := 0; r < nq; r += 2 {
+ s = q[r] + n
+ if s < 0 || s > ACTSIZE {
+ continue nextn
+ }
+ if amem[s] == 0 {
+ flag++
+ } else if amem[s] != q[r+1] {
+ continue nextn
+ }
+ }
+
+ // check the position equals another only if the states are identical
+ for j := 0; j < nstate; j++ {
+ if indgo[j] == n {
+
+ // we have some disagreement
+ if flag != 0 {
+ continue nextn
+ }
+ if nq == len(optst[j]) {
+
+ // states are equal
+ indgo[i] = n
+ if adb > 1 {
+ fmt.Fprintf(ftable, "State %v: entry at"+
+ "%v equals state %v\n",
+ i, n, j)
+ }
+ return
+ }
+
+ // we have some disagreement
+ continue nextn
+ }
+ }
+
+ for r := 0; r < nq; r += 2 {
+ s = q[r] + n
+ if s > maxa {
+ maxa = s
+ }
+ if amem[s] != 0 && amem[s] != q[r+1] {
+ errorf("clobber of a array, pos'n %v, by %v", s, q[r+1])
+ }
+ amem[s] = q[r+1]
+ }
+ indgo[i] = n
+ if adb > 1 {
+ fmt.Fprintf(ftable, "State %v: entry at %v\n", i, indgo[i])
+ }
+ return
+ }
+ errorf("Error; failure to place state %v", i)
+}
+
+//
+// this version is for limbo
+// write out the optimized parser
+//
+func aoutput() {
+ ftable.WriteRune('\n')
+ fmt.Fprintf(ftable, "const %sLast = %v\n\n", prefix, maxa+1)
+ arout("Act", amem, maxa+1)
+ arout("Pact", indgo, nstate)
+ arout("Pgo", pgo, nnonter+1)
+}
+
+//
+// put out other arrays, copy the parsers
+//
+func others() {
+ var i, j int
+
+ arout("R1", levprd, nprod)
+ aryfil(temp1, nprod, 0)
+
+ //
+ //yyr2 is the number of rules for each production
+ //
+ for i = 1; i < nprod; i++ {
+ temp1[i] = len(prdptr[i]) - 2
+ }
+ arout("R2", temp1, nprod)
+
+ aryfil(temp1, nstate, -1000)
+ for i = 0; i <= ntokens; i++ {
+ for j := tstates[i]; j != 0; j = mstates[j] {
+ temp1[j] = i
+ }
+ }
+ for i = 0; i <= nnonter; i++ {
+ for j = ntstates[i]; j != 0; j = mstates[j] {
+ temp1[j] = -i
+ }
+ }
+ arout("Chk", temp1, nstate)
+ arout("Def", defact, nstate)
+
+ // put out token translation tables
+ // table 1 has 0-256
+ aryfil(temp1, 256, 0)
+ c := 0
+ for i = 1; i <= ntokens; i++ {
+ j = tokset[i].value
+ if j >= 0 && j < 256 {
+ if temp1[j] != 0 {
+ fmt.Print("yacc bug -- cant have 2 different Ts with same value\n")
+ fmt.Printf(" %s and %s\n", tokset[i].name, tokset[temp1[j]].name)
+ nerrors++
+ }
+ temp1[j] = i
+ if j > c {
+ c = j
+ }
+ }
+ }
+ for i = 0; i <= c; i++ {
+ if temp1[i] == 0 {
+ temp1[i] = YYLEXUNK
+ }
+ }
+ arout("Tok1", temp1, c+1)
+
+ // table 2 has PRIVATE-PRIVATE+256
+ aryfil(temp1, 256, 0)
+ c = 0
+ for i = 1; i <= ntokens; i++ {
+ j = tokset[i].value - PRIVATE
+ if j >= 0 && j < 256 {
+ if temp1[j] != 0 {
+ fmt.Print("yacc bug -- cant have 2 different Ts with same value\n")
+ fmt.Printf(" %s and %s\n", tokset[i].name, tokset[temp1[j]].name)
+ nerrors++
+ }
+ temp1[j] = i
+ if j > c {
+ c = j
+ }
+ }
+ }
+ arout("Tok2", temp1, c+1)
+
+ // table 3 has everything else
+ fmt.Fprintf(ftable, "var %sTok3 = []int{\n\t", prefix)
+ c = 0
+ for i = 1; i <= ntokens; i++ {
+ j = tokset[i].value
+ if j >= 0 && j < 256 {
+ continue
+ }
+ if j >= PRIVATE && j < 256+PRIVATE {
+ continue
+ }
+
+ if c%5 != 0 {
+ ftable.WriteRune(' ')
+ }
+ fmt.Fprintf(ftable, "%d, %d,", j, i)
+ c++
+ if c%5 == 0 {
+ fmt.Fprint(ftable, "\n\t")
+ }
+ }
+ if c%5 != 0 {
+ ftable.WriteRune(' ')
+ }
+ fmt.Fprintf(ftable, "%d,\n}\n", 0)
+
+ // copy parser text
+ ch := getrune(finput)
+ for ch != EOF {
+ ftable.WriteRune(ch)
+ ch = getrune(finput)
+ }
+
+ // copy yaccpar
+ fmt.Fprintf(ftable, "\n//line yaccpar:1\n")
+
+ parts := strings.SplitN(yaccpar, prefix+"run()", 2)
+ fmt.Fprintf(ftable, "%v", parts[0])
+ ftable.Write(fcode.Bytes())
+ fmt.Fprintf(ftable, "%v", parts[1])
+}
+
+func arout(s string, v []int, n int) {
+ s = prefix + s
+ fmt.Fprintf(ftable, "var %v = []int{\n", s)
+ for i := 0; i < n; i++ {
+ if i%10 == 0 {
+ fmt.Fprintf(ftable, "\n\t")
+ } else {
+ ftable.WriteRune(' ')
+ }
+ fmt.Fprintf(ftable, "%d,", v[i])
+ }
+ fmt.Fprintf(ftable, "\n}\n")
+}
+
+//
+// output the summary on y.output
+//
+func summary() {
+ if foutput != nil {
+ fmt.Fprintf(foutput, "\n%v terminals, %v nonterminals\n", ntokens, nnonter+1)
+ fmt.Fprintf(foutput, "%v grammar rules, %v/%v states\n", nprod, nstate, NSTATES)
+ fmt.Fprintf(foutput, "%v shift/reduce, %v reduce/reduce conflicts reported\n", zzsrconf, zzrrconf)
+ fmt.Fprintf(foutput, "%v working sets used\n", len(wsets))
+ fmt.Fprintf(foutput, "memory: parser %v/%v\n", memp, ACTSIZE)
+ fmt.Fprintf(foutput, "%v extra closures\n", zzclose-2*nstate)
+ fmt.Fprintf(foutput, "%v shift entries, %v exceptions\n", zzacent, zzexcp)
+ fmt.Fprintf(foutput, "%v goto entries\n", zzgoent)
+ fmt.Fprintf(foutput, "%v entries saved by goto default\n", zzgobest)
+ }
+ if zzsrconf != 0 || zzrrconf != 0 {
+ fmt.Printf("\nconflicts: ")
+ if zzsrconf != 0 {
+ fmt.Printf("%v shift/reduce", zzsrconf)
+ }
+ if zzsrconf != 0 && zzrrconf != 0 {
+ fmt.Printf(", ")
+ }
+ if zzrrconf != 0 {
+ fmt.Printf("%v reduce/reduce", zzrrconf)
+ }
+ fmt.Printf("\n")
+ }
+}
+
+//
+// write optimizer summary
+//
+func osummary() {
+ if foutput == nil {
+ return
+ }
+ i := 0
+ for p := maxa; p >= 0; p-- {
+ if amem[p] == 0 {
+ i++
+ }
+ }
+
+ fmt.Fprintf(foutput, "Optimizer space used: output %v/%v\n", maxa+1, ACTSIZE)
+ fmt.Fprintf(foutput, "%v table entries, %v zero\n", maxa+1, i)
+ fmt.Fprintf(foutput, "maximum spread: %v, maximum offset: %v\n", maxspr, maxoff)
+}
+
+//
+// copies and protects "'s in q
+//
+func chcopy(q string) string {
+ s := ""
+ i := 0
+ j := 0
+ for i = 0; i < len(q); i++ {
+ if q[i] == '"' {
+ s += q[j:i] + "\\"
+ j = i
+ }
+ }
+ return s + q[j:i]
+}
+
+func usage() {
+ fmt.Fprintf(stderr, "usage: yacc [-o output] [-v parsetable] input\n")
+ exit(1)
+}
+
+func bitset(set Lkset, bit int) int { return set[bit>>5] & (1 << uint(bit&31)) }
+
+func setbit(set Lkset, bit int) { set[bit>>5] |= (1 << uint(bit&31)) }
+
+func mkset() Lkset { return make([]int, tbitset) }
+
+//
+// set a to the union of a and b
+// return 1 if b is not a subset of a, 0 otherwise
+//
+func setunion(a, b []int) int {
+ sub := 0
+ for i := 0; i < tbitset; i++ {
+ x := a[i]
+ y := x | b[i]
+ a[i] = y
+ if y != x {
+ sub = 1
+ }
+ }
+ return sub
+}
+
+func prlook(p Lkset) {
+ if p == nil {
+ fmt.Fprintf(foutput, "\tNULL")
+ return
+ }
+ fmt.Fprintf(foutput, " { ")
+ for j := 0; j <= ntokens; j++ {
+ if bitset(p, j) != 0 {
+ fmt.Fprintf(foutput, "%v ", symnam(j))
+ }
+ }
+ fmt.Fprintf(foutput, "}")
+}
+
+//
+// utility routines
+//
+var peekrune rune
+
+func isdigit(c rune) bool { return c >= '0' && c <= '9' }
+
+func isword(c rune) bool {
+ return c >= 0xa0 || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
+}
+
+func mktemp(t string) string { return t }
+
+//
+// return 1 if 2 arrays are equal
+// return 0 if not equal
+//
+func aryeq(a []int, b []int) int {
+ n := len(a)
+ if len(b) != n {
+ return 0
+ }
+ for ll := 0; ll < n; ll++ {
+ if a[ll] != b[ll] {
+ return 0
+ }
+ }
+ return 1
+}
+
+func putrune(f *bufio.Writer, c int) {
+ s := string(c)
+ for i := 0; i < len(s); i++ {
+ f.WriteByte(s[i])
+ }
+}
+
+func getrune(f *bufio.Reader) rune {
+ var r rune
+
+ if peekrune != 0 {
+ if peekrune == EOF {
+ return EOF
+ }
+ r = peekrune
+ peekrune = 0
+ return r
+ }
+
+ c, n, err := f.ReadRune()
+ if n == 0 {
+ return EOF
+ }
+ if err != nil {
+ errorf("read error: %v", err)
+ }
+ //fmt.Printf("rune = %v n=%v\n", string(c), n);
+ return c
+}
+
+func ungetrune(f *bufio.Reader, c rune) {
+ if f != finput {
+ panic("ungetc - not finput")
+ }
+ if peekrune != 0 {
+ panic("ungetc - 2nd unget")
+ }
+ peekrune = c
+}
+
+func write(f *bufio.Writer, b []byte, n int) int {
+ panic("write")
+ return 0
+}
+
+func open(s string) *bufio.Reader {
+ fi, err := os.Open(s)
+ if err != nil {
+ errorf("error opening %v: %v", s, err)
+ }
+ //fmt.Printf("open %v\n", s);
+ return bufio.NewReader(fi)
+}
+
+func create(s string) *bufio.Writer {
+ fo, err := os.Create(s)
+ if err != nil {
+ errorf("error creating %v: %v", s, err)
+ }
+ //fmt.Printf("create %v mode %v\n", s);
+ return bufio.NewWriter(fo)
+}
+
+//
+// write out error comment
+//
+func errorf(s string, v ...interface{}) {
+ nerrors++
+ fmt.Fprintf(stderr, s, v...)
+ fmt.Fprintf(stderr, ": %v:%v\n", infile, lineno)
+ if fatfl != 0 {
+ summary()
+ exit(1)
+ }
+}
+
+func exit(status int) {
+ if ftable != nil {
+ ftable.Flush()
+ ftable = nil
+ }
+ if foutput != nil {
+ foutput.Flush()
+ foutput = nil
+ }
+ if stderr != nil {
+ stderr.Flush()
+ stderr = nil
+ }
+ os.Exit(status)
+}
+
+var yaccpar string // will be processed version of yaccpartext: s/$$/prefix/g
+var yaccpartext = `
+/* parser for yacc output */
+
+var $$Debug = 0
+
+type $$Lexer interface {
+ Lex(lval *$$SymType) int
+ Error(s string)
+}
+
+const $$Flag = -1000
+
+func $$Tokname(c int) string {
+ if c > 0 && c <= len($$Toknames) {
+ if $$Toknames[c-1] != "" {
+ return $$Toknames[c-1]
+ }
+ }
+ return fmt.Sprintf("tok-%v", c)
+}
+
+func $$Statname(s int) string {
+ if s >= 0 && s < len($$Statenames) {
+ if $$Statenames[s] != "" {
+ return $$Statenames[s]
+ }
+ }
+ return fmt.Sprintf("state-%v", s)
+}
+
+func $$lex1(lex $$Lexer, lval *$$SymType) int {
+ c := 0
+ char := lex.Lex(lval)
+ if char <= 0 {
+ c = $$Tok1[0]
+ goto out
+ }
+ if char < len($$Tok1) {
+ c = $$Tok1[char]
+ goto out
+ }
+ if char >= $$Private {
+ if char < $$Private+len($$Tok2) {
+ c = $$Tok2[char-$$Private]
+ goto out
+ }
+ }
+ for i := 0; i < len($$Tok3); i += 2 {
+ c = $$Tok3[i+0]
+ if c == char {
+ c = $$Tok3[i+1]
+ goto out
+ }
+ }
+
+out:
+ if c == 0 {
+ c = $$Tok2[1] /* unknown char */
+ }
+ if $$Debug >= 3 {
+ fmt.Printf("lex %U %s\n", uint(char), $$Tokname(c))
+ }
+ return c
+}
+
+func $$Parse($$lex $$Lexer) int {
+ var $$n int
+ var $$lval $$SymType
+ var $$VAL $$SymType
+ $$S := make([]$$SymType, $$MaxDepth)
+
+ Nerrs := 0 /* number of errors */
+ Errflag := 0 /* error recovery flag */
+ $$state := 0
+ $$char := -1
+ $$p := -1
+ goto $$stack
+
+ret0:
+ return 0
+
+ret1:
+ return 1
+
+$$stack:
+ /* put a state and value onto the stack */
+ if $$Debug >= 4 {
+ fmt.Printf("char %v in %v\n", $$Tokname($$char), $$Statname($$state))
+ }
+
+ $$p++
+ if $$p >= len($$S) {
+ nyys := make([]$$SymType, len($$S)*2)
+ copy(nyys, $$S)
+ $$S = nyys
+ }
+ $$S[$$p] = $$VAL
+ $$S[$$p].yys = $$state
+
+$$newstate:
+ $$n = $$Pact[$$state]
+ if $$n <= $$Flag {
+ goto $$default /* simple state */
+ }
+ if $$char < 0 {
+ $$char = $$lex1($$lex, &$$lval)
+ }
+ $$n += $$char
+ if $$n < 0 || $$n >= $$Last {
+ goto $$default
+ }
+ $$n = $$Act[$$n]
+ if $$Chk[$$n] == $$char { /* valid shift */
+ $$char = -1
+ $$VAL = $$lval
+ $$state = $$n
+ if Errflag > 0 {
+ Errflag--
+ }
+ goto $$stack
+ }
+
+$$default:
+ /* default state action */
+ $$n = $$Def[$$state]
+ if $$n == -2 {
+ if $$char < 0 {
+ $$char = $$lex1($$lex, &$$lval)
+ }
+
+ /* look through exception table */
+ xi := 0
+ for {
+ if $$Exca[xi+0] == -1 && $$Exca[xi+1] == $$state {
+ break
+ }
+ xi += 2
+ }
+ for xi += 2; ; xi += 2 {
+ $$n = $$Exca[xi+0]
+ if $$n < 0 || $$n == $$char {
+ break
+ }
+ }
+ $$n = $$Exca[xi+1]
+ if $$n < 0 {
+ goto ret0
+ }
+ }
+ if $$n == 0 {
+ /* error ... attempt to resume parsing */
+ switch Errflag {
+ case 0: /* brand new error */
+ $$lex.Error("syntax error")
+ Nerrs++
+ if $$Debug >= 1 {
+ fmt.Printf("%s", $$Statname($$state))
+ fmt.Printf("saw %s\n", $$Tokname($$char))
+ }
+ fallthrough
+
+ case 1, 2: /* incompletely recovered error ... try again */
+ Errflag = 3
+
+ /* find a state where "error" is a legal shift action */
+ for $$p >= 0 {
+ $$n = $$Pact[$$S[$$p].yys] + $$ErrCode
+ if $$n >= 0 && $$n < $$Last {
+ $$state = $$Act[$$n] /* simulate a shift of "error" */
+ if $$Chk[$$state] == $$ErrCode {
+ goto $$stack
+ }
+ }
+
+ /* the current p has no shift on "error", pop stack */
+ if $$Debug >= 2 {
+ fmt.Printf("error recovery pops state %d\n", $$S[$$p].yys)
+ }
+ $$p--
+ }
+ /* there is no state on the stack with an error shift ... abort */
+ goto ret1
+
+ case 3: /* no shift yet; clobber input char */
+ if $$Debug >= 2 {
+ fmt.Printf("error recovery discards %s\n", $$Tokname($$char))
+ }
+ if $$char == $$EofCode {
+ goto ret1
+ }
+ $$char = -1
+ goto $$newstate /* try again in the same state */
+ }
+ }
+
+ /* reduction by production $$n */
+ if $$Debug >= 2 {
+ fmt.Printf("reduce %v in:\n\t%v\n", $$n, $$Statname($$state))
+ }
+
+ $$nt := $$n
+ $$pt := $$p
+ _ = $$pt // guard against "declared and not used"
+
+ $$p -= $$R2[$$n]
+ $$VAL = $$S[$$p+1]
+
+ /* consult goto table to find next state */
+ $$n = $$R1[$$n]
+ $$g := $$Pgo[$$n]
+ $$j := $$g + $$S[$$p].yys + 1
+
+ if $$j >= $$Last {
+ $$state = $$Act[$$g]
+ } else {
+ $$state = $$Act[$$j]
+ if $$Chk[$$state] != -$$n {
+ $$state = $$Act[$$g]
+ }
+ }
+ // dummy call; replaced with literal code
+ $$run()
+ goto $$stack /* stack new state and value */
+}
+`