|  | // Copyright 2013 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. | 
|  |  | 
|  | // This is an example of a goyacc program. | 
|  | // To build it: | 
|  | // goyacc -p "expr" expr.y (produces y.go) | 
|  | // go build -o expr y.go | 
|  | // expr | 
|  | // > <type an expression> | 
|  |  | 
|  | %{ | 
|  |  | 
|  | package main | 
|  |  | 
|  | import ( | 
|  | "bufio" | 
|  | "bytes" | 
|  | "fmt" | 
|  | "io" | 
|  | "log" | 
|  | "math/big" | 
|  | "os" | 
|  | "unicode/utf8" | 
|  | ) | 
|  |  | 
|  | %} | 
|  |  | 
|  | %union { | 
|  | num *big.Rat | 
|  | } | 
|  |  | 
|  | %type	<num>	expr expr1 expr2 expr3 | 
|  |  | 
|  | %token '+' '-' '*' '/' '(' ')' | 
|  |  | 
|  | %token	<num>	NUM | 
|  |  | 
|  | %% | 
|  |  | 
|  | top: | 
|  | expr | 
|  | { | 
|  | if $1.IsInt() { | 
|  | fmt.Println($1.Num().String()) | 
|  | } else { | 
|  | fmt.Println($1.String()) | 
|  | } | 
|  | } | 
|  |  | 
|  | expr: | 
|  | expr1 | 
|  | |	'+' expr | 
|  | { | 
|  | $$ = $2 | 
|  | } | 
|  | |	'-' expr | 
|  | { | 
|  | $$ = $2.Neg($2) | 
|  | } | 
|  |  | 
|  | expr1: | 
|  | expr2 | 
|  | |	expr1 '+' expr2 | 
|  | { | 
|  | $$ = $1.Add($1, $3) | 
|  | } | 
|  | |	expr1 '-' expr2 | 
|  | { | 
|  | $$ = $1.Sub($1, $3) | 
|  | } | 
|  |  | 
|  | expr2: | 
|  | expr3 | 
|  | |	expr2 '*' expr3 | 
|  | { | 
|  | $$ = $1.Mul($1, $3) | 
|  | } | 
|  | |	expr2 '/' expr3 | 
|  | { | 
|  | $$ = $1.Quo($1, $3) | 
|  | } | 
|  |  | 
|  | expr3: | 
|  | NUM | 
|  | |	'(' expr ')' | 
|  | { | 
|  | $$ = $2 | 
|  | } | 
|  |  | 
|  |  | 
|  | %% | 
|  |  | 
|  | // The parser expects the lexer to return 0 on EOF.  Give it a name | 
|  | // for clarity. | 
|  | const eof = 0 | 
|  |  | 
|  | // The parser uses the type <prefix>Lex as a lexer. It must provide | 
|  | // the methods Lex(*<prefix>SymType) int and Error(string). | 
|  | type exprLex struct { | 
|  | line []byte | 
|  | peek rune | 
|  | } | 
|  |  | 
|  | // The parser calls this method to get each new token. This | 
|  | // implementation returns operators and NUM. | 
|  | func (x *exprLex) Lex(yylval *exprSymType) int { | 
|  | for { | 
|  | c := x.next() | 
|  | switch c { | 
|  | case eof: | 
|  | return eof | 
|  | case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': | 
|  | return x.num(c, yylval) | 
|  | case '+', '-', '*', '/', '(', ')': | 
|  | return int(c) | 
|  |  | 
|  | // Recognize Unicode multiplication and division | 
|  | // symbols, returning what the parser expects. | 
|  | case '×': | 
|  | return '*' | 
|  | case '÷': | 
|  | return '/' | 
|  |  | 
|  | case ' ', '\t', '\n', '\r': | 
|  | default: | 
|  | log.Printf("unrecognized character %q", c) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // Lex a number. | 
|  | func (x *exprLex) num(c rune, yylval *exprSymType) int { | 
|  | add := func(b *bytes.Buffer, c rune) { | 
|  | if _, err := b.WriteRune(c); err != nil { | 
|  | log.Fatalf("WriteRune: %s", err) | 
|  | } | 
|  | } | 
|  | var b bytes.Buffer | 
|  | add(&b, c) | 
|  | L: for { | 
|  | c = x.next() | 
|  | switch c { | 
|  | case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', 'e', 'E': | 
|  | add(&b, c) | 
|  | default: | 
|  | break L | 
|  | } | 
|  | } | 
|  | if c != eof { | 
|  | x.peek = c | 
|  | } | 
|  | yylval.num = &big.Rat{} | 
|  | _, ok := yylval.num.SetString(b.String()) | 
|  | if !ok { | 
|  | log.Printf("bad number %q", b.String()) | 
|  | return eof | 
|  | } | 
|  | return NUM | 
|  | } | 
|  |  | 
|  | // Return the next rune for the lexer. | 
|  | func (x *exprLex) next() rune { | 
|  | if x.peek != eof { | 
|  | r := x.peek | 
|  | x.peek = eof | 
|  | return r | 
|  | } | 
|  | if len(x.line) == 0 { | 
|  | return eof | 
|  | } | 
|  | c, size := utf8.DecodeRune(x.line) | 
|  | x.line = x.line[size:] | 
|  | if c == utf8.RuneError && size == 1 { | 
|  | log.Print("invalid utf8") | 
|  | return x.next() | 
|  | } | 
|  | return c | 
|  | } | 
|  |  | 
|  | // The parser calls this method on a parse error. | 
|  | func (x *exprLex) Error(s string) { | 
|  | log.Printf("parse error: %s", s) | 
|  | } | 
|  |  | 
|  | func main() { | 
|  | in := bufio.NewReader(os.Stdin) | 
|  | for { | 
|  | if _, err := os.Stdout.WriteString("> "); err != nil { | 
|  | log.Fatalf("WriteString: %s", err) | 
|  | } | 
|  | line, err := in.ReadBytes('\n') | 
|  | if err == io.EOF { | 
|  | return | 
|  | } | 
|  | if err != nil { | 
|  | log.Fatalf("ReadBytes: %s", err) | 
|  | } | 
|  |  | 
|  | exprParse(&exprLex{line: line}) | 
|  | } | 
|  | } |