diff options
Diffstat (limited to 'src/cmd/yacc')
-rw-r--r-- | src/cmd/yacc/doc.go | 2 | ||||
-rw-r--r-- | src/cmd/yacc/units.txt | 104 | ||||
-rw-r--r-- | src/cmd/yacc/units.y | 35 | ||||
-rw-r--r-- | src/cmd/yacc/yacc.go | 257 |
4 files changed, 261 insertions, 137 deletions
diff --git a/src/cmd/yacc/doc.go b/src/cmd/yacc/doc.go index 4a2c2a314..792c104e3 100644 --- a/src/cmd/yacc/doc.go +++ b/src/cmd/yacc/doc.go @@ -48,4 +48,4 @@ referenced by yacc's generated code. Setting it to distinct values allows multiple grammars to be placed in a single package. */ -package documentation +package main diff --git a/src/cmd/yacc/units.txt b/src/cmd/yacc/units.txt index ddb2bc294..df8f567d9 100644 --- a/src/cmd/yacc/units.txt +++ b/src/cmd/yacc/units.txt @@ -215,58 +215,58 @@ 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 $ +/ Wed Aug 29, 2012 + +argentinapeso $ 0.2160 +australiadollar $ 1.0372 +boliviaboliviano $ 0.1427 +brazilreal $ 0.4872 +britainpound $ 1.5843 +canadadollar $ 1.0117 +chilepeso $ 1 | 480.6 +chinayuan $ 0.1574 +colombiapeso $ 1 | 1834 +czechkoruna $ 0.0506 +denmarkkrone $ 0.1681 +dominicanpeso $ 0.0256 +egyptpound $ 0.1640 +elsalvadorcolon $ 1 | 8.75 +europeuro $ 1.2528 +guatemalaquetzal $ 0.1290 +honduraslempira $ 0.0511 +hongkongdollar $ 0.1289 +hungaryforint $ 1 | 226.5 +indiarupee $ 0.0180 +indonesiarupiah $ 1 | 9540 +israelshekel $ 0.2479 +japanyen $ 0.0127 +kenyashilling $ 0.0119 +kuwaitdinar $ 3.5456 +lebanonpound $ 1 | 1505.5 +malaysiaringgit $ 0.3204 +mexicopeso $ 0.0754 +newzealanddollar $ 0.8035 +nicaraguacordoba $ 0.0421 +norwaykrone $ 0.1717 +pakistanrupee $ 0.0106 +paraguayguarani $ 1 | 4415 +perunewsol $ 0.3832 +philippinespeso $ 0.0236 +polandzloty $ 0.3001 +russiaruble $ 0.0311 +saudiarabiariyal $ 1 | 3.75 +singaporedollar $ 0.7976 +slovakkoruna 1 | 30.126 europeuro +southafricarand $ 0.1188 +southkoreawon $ 1 | 1135 +swedenkrona $ 0.1502 +switzerlandfranc $ 1.0431 +taiwandollar $ 0.0334 +thailandbaht $ 0.0319 +turkeynewlira $ 0.5504 +uaedirham $ 0.2723 +uruguaynewpeso $ 0.0465 +vietnamdong $ 1 | 20865 / END MONEY diff --git a/src/cmd/yacc/units.y b/src/cmd/yacc/units.y index 7258e3e59..9c1b0b336 100644 --- a/src/cmd/yacc/units.y +++ b/src/cmd/yacc/units.y @@ -11,6 +11,11 @@ %{ +// This tag will end up in the generated y.go, so that forgetting +// 'make clean' does not fail the next build. + +// +build ignore + // units.y // example of a Go yacc program // usage is @@ -26,11 +31,13 @@ package main import ( + "bufio" "flag" "fmt" - "bufio" - "os" "math" + "runtime" + "os" + "path/filepath" "strconv" "unicode/utf8" ) @@ -74,9 +81,9 @@ var vflag bool %type <node> prog expr expr0 expr1 expr2 expr3 expr4 -%token <vval> VAL +%token <vval> VÄL // dieresis to test UTF-8 %token <vvar> VAR -%token <numb> SUP +%token <numb> _SUP // tests leading underscore in token name %% prog: ':' VAR expr @@ -157,7 +164,7 @@ expr3: expr2: expr1 -| expr2 SUP +| expr2 _SUP { xpn(&$$, &$1, $2) } @@ -197,7 +204,7 @@ expr0: $$ = $1.node } } -| VAL +| VÄL { $$ = one $$.vval = $1 @@ -234,13 +241,13 @@ loop: return '/' case '¹', 'ⁱ': yylval.numb = 1 - return SUP + return _SUP case '²', '': yylval.numb = 2 - return SUP + return _SUP case '³', '': yylval.numb = 3 - return SUP + return _SUP } return int(c) @@ -273,7 +280,7 @@ numb: f = 0 } yylval.vval = f - return VAL + return VÄL } func (UnitsLex) Error(s string) { @@ -287,13 +294,11 @@ func main() { flag.Parse() - if dir := os.Getenv("GOROOT"); dir != "" { - file = dir + "/src/cmd/yacc/units.txt" - } + file = filepath.Join(runtime.GOROOT(), "src/cmd/yacc/units.txt") if flag.NArg() > 0 { file = flag.Arg(0) } else if file == "" { - fmt.Fprintf(os.Stderr, "can not find data file units.txt; provide it as argument or set $GOROOT\n") + fmt.Fprintf(os.Stderr, "cannot find data file units.txt; provide it as argument or set $GOROOT\n") os.Exit(1) } @@ -308,7 +313,7 @@ func main() { /* * read the 'units' file to - * develope a database + * develop a database */ lineno = 0 for { diff --git a/src/cmd/yacc/yacc.go b/src/cmd/yacc/yacc.go index e94228152..0c18f93b6 100644 --- a/src/cmd/yacc/yacc.go +++ b/src/cmd/yacc/yacc.go @@ -51,6 +51,8 @@ import ( "fmt" "os" "strings" + "unicode" + "unicode/utf8" ) // the following are adjustable @@ -153,6 +155,8 @@ var ftable *bufio.Writer // y.go file var fcode = &bytes.Buffer{} // saved code var foutput *bufio.Writer // y.output file +var fmtImported bool // output file has recorded an import of "fmt" + 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 @@ -323,7 +327,6 @@ var resrv = []Resrv{ var zznewstate = 0 const EOF = -1 -const UTFmax = 0x3f func main() { @@ -716,8 +719,8 @@ func moreprod() { } // -// define s to be a terminal if t=0 -// or a nonterminal if t=1 +// define s to be a terminal if nt==0 +// or a nonterminal if nt==1 // func defin(nt int, s string) int { val := 0 @@ -750,56 +753,66 @@ func defin(nt int, s string) int { // 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 + if s[0] == ' ' { + s = s[1:] + r, size := utf8.DecodeRuneInString(s) + if r == utf8.RuneError && size == 1 { + errorf("invalid UTF-8 sequence %q", s) + } + val = int(r) + if val == '\\' { // escape sequence + switch { + case len(s) == 2: + // single character escape sequence + switch s[1] { + case '\'': + val = '\'' + case '"': + val = '"' + case '\\': + val = '\\' + case 'a': + val = '\a' + case 'b': + val = '\b' + case 'f': + val = '\f' + case 'n': + val = '\n' + case 'r': + val = '\r' + case 't': + val = '\t' + case 'v': + val = '\v' default: - errorf("illegal \\unnnn construction") + errorf("invalid escape %s", s) } - val = val*16 + c - s = s[1:] - } - if val == 0 { - errorf("'\\u0000' is illegal") + case s[1] == 'u' && len(s) == 2+4, // \unnnn sequence + s[1] == 'U' && len(s) == 2+8: // \Unnnnnnnn sequence + val = 0 + s = s[2:] + 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 \u or \U construction`) + } + val = val*16 + c + s = s[1:] + } + default: + errorf("invalid escape %s", s) } - } else { - errorf("unknown escape") + } + if val == 0 { + errorf("token value 0 is illegal") } } else { val = extval @@ -985,7 +998,7 @@ func gettok() int { func getword(c rune) { tokname = "" - for isword(c) || isdigit(c) || c == '_' || c == '.' || c == '$' { + for isword(c) || isdigit(c) || c == '.' || c == '$' { tokname += string(c) c = getrune(finput) } @@ -1073,6 +1086,7 @@ out: // // saves code between %{ and %} +// adds an import for __fmt__ the first time // func cpycode() { lno := lineno @@ -1085,15 +1099,18 @@ func cpycode() { if !lflag { fmt.Fprintf(ftable, "\n//line %v:%v\n", infile, lineno) } + // accumulate until %} + code := make([]rune, 0, 1024) for c != EOF { if c == '%' { c = getrune(finput) if c == '}' { + emitcode(code, lno+1) return } - ftable.WriteRune('%') + code = append(code, '%') } - ftable.WriteRune(c) + code = append(code, c) if c == '\n' { lineno++ } @@ -1104,6 +1121,107 @@ func cpycode() { } // +// emits code saved up from between %{ and %} +// called by cpycode +// adds an import for __yyfmt__ after the package clause +// +func emitcode(code []rune, lineno int) { + for i, line := range lines(code) { + writecode(line) + if !fmtImported && isPackageClause(line) { + fmt.Fprintln(ftable, `import __yyfmt__ "fmt"`) + fmt.Fprintf(ftable, "//line %v:%v\n\t\t", infile, lineno+i) + fmtImported = true + } + } +} + +// +// does this line look like a package clause? not perfect: might be confused by early comments. +// +func isPackageClause(line []rune) bool { + line = skipspace(line) + + // must be big enough. + if len(line) < len("package X\n") { + return false + } + + // must start with "package" + for i, r := range []rune("package") { + if line[i] != r { + return false + } + } + line = skipspace(line[len("package"):]) + + // must have another identifier. + if len(line) == 0 || (!unicode.IsLetter(line[0]) && line[0] != '_') { + return false + } + for len(line) > 0 { + if !unicode.IsLetter(line[0]) && !unicode.IsDigit(line[0]) && line[0] != '_' { + break + } + line = line[1:] + } + line = skipspace(line) + + // eol, newline, or comment must follow + if len(line) == 0 { + return true + } + if line[0] == '\r' || line[0] == '\n' { + return true + } + if len(line) >= 2 { + return line[0] == '/' && (line[1] == '/' || line[1] == '*') + } + return false +} + +// +// skip initial spaces +// +func skipspace(line []rune) []rune { + for len(line) > 0 { + if line[0] != ' ' && line[0] != '\t' { + break + } + line = line[1:] + } + return line +} + +// +// break code into lines +// +func lines(code []rune) [][]rune { + l := make([][]rune, 0, 100) + for len(code) > 0 { + // one line per loop + var i int + for i = range code { + if code[i] == '\n' { + break + } + } + l = append(l, code[:i+1]) + code = code[i+1:] + } + return l +} + +// +// writes code to ftable +// +func writecode(code []rune) { + for _, r := range code { + ftable.WriteRune(r) + } +} + +// // skip over comments // skipcom is called after reading a '/' // @@ -1230,7 +1348,7 @@ loop: if j >= max { errorf("Illegal use of $%v", j) } - } else if isword(c) || c == '_' || c == '.' { + } else if isword(c) || c == '.' { // look for $name ungetrune(finput, c) if gettok() != IDENTIFIER { @@ -2775,7 +2893,7 @@ func others() { 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.Print("yacc bug -- cannot have 2 different Ts with same value\n") fmt.Printf(" %s and %s\n", tokset[i].name, tokset[temp1[j]].name) nerrors++ } @@ -2799,7 +2917,7 @@ func others() { 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.Print("yacc bug -- cannot have 2 different Ts with same value\n") fmt.Printf(" %s and %s\n", tokset[i].name, tokset[temp1[j]].name) nerrors++ } @@ -2982,7 +3100,7 @@ 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') + return c >= 0xa0 || c == '_' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') } func mktemp(t string) string { return t } @@ -3110,12 +3228,13 @@ type $$Lexer interface { const $$Flag = -1000 func $$Tokname(c int) string { - if c > 0 && c <= len($$Toknames) { - if $$Toknames[c-1] != "" { - return $$Toknames[c-1] + // 4 is TOKSTART above + if c >= 4 && c-4 < len($$Toknames) { + if $$Toknames[c-4] != "" { + return $$Toknames[c-4] } } - return fmt.Sprintf("tok-%v", c) + return __yyfmt__.Sprintf("tok-%v", c) } func $$Statname(s int) string { @@ -3124,7 +3243,7 @@ func $$Statname(s int) string { return $$Statenames[s] } } - return fmt.Sprintf("state-%v", s) + return __yyfmt__.Sprintf("state-%v", s) } func $$lex1(lex $$Lexer, lval *$$SymType) int { @@ -3157,7 +3276,7 @@ out: c = $$Tok2[1] /* unknown char */ } if $$Debug >= 3 { - fmt.Printf("lex %U %s\n", uint(char), $$Tokname(c)) + __yyfmt__.Printf("lex %U %s\n", uint(char), $$Tokname(c)) } return c } @@ -3184,7 +3303,7 @@ ret1: $$stack: /* put a state and value onto the stack */ if $$Debug >= 4 { - fmt.Printf("char %v in %v\n", $$Tokname($$char), $$Statname($$state)) + __yyfmt__.Printf("char %v in %v\n", $$Tokname($$char), $$Statname($$state)) } $$p++ @@ -3253,8 +3372,8 @@ $$default: $$lex.Error("syntax error") Nerrs++ if $$Debug >= 1 { - fmt.Printf("%s", $$Statname($$state)) - fmt.Printf("saw %s\n", $$Tokname($$char)) + __yyfmt__.Printf("%s", $$Statname($$state)) + __yyfmt__.Printf("saw %s\n", $$Tokname($$char)) } fallthrough @@ -3273,7 +3392,7 @@ $$default: /* the current p has no shift on "error", pop stack */ if $$Debug >= 2 { - fmt.Printf("error recovery pops state %d\n", $$S[$$p].yys) + __yyfmt__.Printf("error recovery pops state %d\n", $$S[$$p].yys) } $$p-- } @@ -3282,7 +3401,7 @@ $$default: case 3: /* no shift yet; clobber input char */ if $$Debug >= 2 { - fmt.Printf("error recovery discards %s\n", $$Tokname($$char)) + __yyfmt__.Printf("error recovery discards %s\n", $$Tokname($$char)) } if $$char == $$EofCode { goto ret1 @@ -3294,7 +3413,7 @@ $$default: /* reduction by production $$n */ if $$Debug >= 2 { - fmt.Printf("reduce %v in:\n\t%v\n", $$n, $$Statname($$state)) + __yyfmt__.Printf("reduce %v in:\n\t%v\n", $$n, $$Statname($$state)) } $$nt := $$n |