diff options
Diffstat (limited to 'src/cmd/goyacc')
-rw-r--r-- | src/cmd/goyacc/Makefile | 17 | ||||
-rw-r--r-- | src/cmd/goyacc/doc.go | 46 | ||||
-rw-r--r-- | src/cmd/goyacc/goyacc.go | 3311 | ||||
-rw-r--r-- | src/cmd/goyacc/units.txt | 576 | ||||
-rw-r--r-- | src/cmd/goyacc/units.y | 765 |
5 files changed, 0 insertions, 4715 deletions
diff --git a/src/cmd/goyacc/Makefile b/src/cmd/goyacc/Makefile deleted file mode 100644 index ac0f427cc..000000000 --- a/src/cmd/goyacc/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -# 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=goyacc -GOFILES=\ - goyacc.go\ - -include ../../Make.cmd - -units: goyacc units.y - ./goyacc -p units_ units.y - $(GC) y.go - $(LD) -o units y.$O - diff --git a/src/cmd/goyacc/doc.go b/src/cmd/goyacc/doc.go deleted file mode 100644 index 5dd6abe69..000000000 --- a/src/cmd/goyacc/doc.go +++ /dev/null @@ -1,46 +0,0 @@ -// 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. - -/* - -Goyacc is a version of yacc for Go. -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 - -Yacc adepts 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 -goyacc sets the prefix, by default yy, that begins the names of -symbols, including types, the parser, and the lexer, generated and -referenced by goyacc'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/goyacc/goyacc.go b/src/cmd/goyacc/goyacc.go deleted file mode 100644 index 481540188..000000000 --- a/src/cmd/goyacc/goyacc.go +++ /dev/null @@ -1,3311 +0,0 @@ -/* -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 ( - "flag" - "fmt" - "bufio" - "os" - "strings" - "bytes" -) - -// 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\t%v\t= %v\n", tokset[i].name, tokset[i].value) - } - } - - // put out names of token names - fmt.Fprintf(ftable, "var\t%sToknames\t =[]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\t%sStatenames\t =[]string {\n", 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, "\ncase %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, "\ncase %v:", nprod) - fmt.Fprintf(fcode, "\n\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}") - - 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, match, c int - - 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 c = 0; c < len(resrv); c++ { - if tokname == resrv[c].name { - if tokflag { - fmt.Printf(">>> %%%v %v %v\n", tokname, - resrv[c].value-PRIVATE, lineno) - } - return resrv[c].value - } - } - errorf("invalid escape, or illegal reserved word: %v", tokname) - - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - numbval = c - '0' - for { - c = getrune(finput) - if !isdigit(c) { - break - } - numbval = numbval*10 + 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 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 int) { - 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\t%sSymType\tstruct", 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\tint;") - } - level++ - case '}': - level-- - if level == 0 { - break out - } - } - } - fmt.Fprintf(ftable, "\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 int - - 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//line %v:%v\n", infile, lineno) - } - - lno := lineno - brac := 0 - -loop: - for { - c := getrune(finput) - - swt: - switch c { - case ';': - if brac == 0 { - ftable.WriteRune(c) - return - } - - case '{': - if brac == 0 { - } - ftable.WriteRune('\t') - 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 + 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': - lineno++ - } - - 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\t%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") - fmt.Fprintf(ftable, "const\t%sNprod\t= %v\n", prefix, nprod) - fmt.Fprintf(ftable, "const\t%sPrivate\t= %v\n", prefix, PRIVATE) - fmt.Fprintf(ftable, "var\t%sTokenNames []string\n", prefix) - fmt.Fprintf(ftable, "var\t%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, "-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() { - fmt.Fprintf(ftable, "const\t%sLast\t= %v\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\t%sTok3\t= []int {\n", 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 - } - - fmt.Fprintf(ftable, "%4d,%4d,", j, i) - c++ - if c%5 == 0 { - ftable.WriteRune('\n') - } - } - fmt.Fprintf(ftable, "%4d,\n };\n", 0) - - // copy parser text - c = getrune(finput) - for c != EOF { - ftable.WriteRune(c) - c = 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\t%v\t= []int {\n", s) - for i := 0; i < n; i++ { - if i%10 == 0 { - ftable.WriteRune('\n') - } - fmt.Fprintf(ftable, "%4d", v[i]) - ftable.WriteRune(',') - } - 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: goyacc [-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 int - -func isdigit(c int) bool { return c >= '0' && c <= '9' } - -func isword(c int) 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) int { - var r int - - 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 int) { - 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 onn "error", pop stack */ - if $$Debug >= 2 { - fmt.Printf("error recovery pops state %d, uncovers %d\n", - $$S[$$p].yys, $$S[$$p-1].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 */ -} -` diff --git a/src/cmd/goyacc/units.txt b/src/cmd/goyacc/units.txt deleted file mode 100644 index ddb2bc294..000000000 --- a/src/cmd/goyacc/units.txt +++ /dev/null @@ -1,576 +0,0 @@ -/ 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/goyacc/units.y b/src/cmd/goyacc/units.y deleted file mode 100644 index d9ef663d9..000000000 --- a/src/cmd/goyacc/units.y +++ /dev/null @@ -1,765 +0,0 @@ -// 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_": -// goyacc -p "units_" - -%{ - -// units.y -// example of a goyacc program -// usage is -// goyacc units.y (produces y.go) -// 6g y.go -// 6l y.6 -// ./6.out $GOROOT/src/cmd/goyacc/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" - "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 int // 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, 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 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.Atof64(sym) - 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/goyacc/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 int) bool { - switch c { - case 0, '+', '-', '*', '/', '[', ']', '(', ')', - '^', ':', '?', ' ', '\t', '.', '|', '#', - '×', '÷', '¹', 'ⁱ', '²', '', '³', '': - return false - } - return true -} - -/* - * number forming character - */ -func rdigit(c int) 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() int { - var c, 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 -} |