| // 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: |
| // go tool yacc -p "expr" expr.y (produces y.go) |
| // go build -o expr y.go |
| // expr |
| // > <type an expression> |
| |
| %{ |
| |
| // This tag will be copied to the generated file to prevent that file |
| // confusing a future build. |
| |
| // +build ignore |
| |
| package main |
| |
| import ( |
| "bufio" |
| "bytes" |
| "fmt" |
| "io" |
| "log" |
| "math/big" |
| "os" |
| "unicode/utf8" |
| ) |
| |
| %} |
| |
| %union { |
| num *big.Rat |
| } |
| |
| %type <num> expr expr1 expr2 expr3 |
| |
| %token <num> NUM |
| |
| %% |
| |
| top: |
| expr |
| { |
| if $1.IsInt() { |
| fmt.Println($1.Num().String()) |
| } else { |
| fmt.Println($1.String()) |
| } |
| } |
| |
| expr: |
| expr1 |
| | '+' expr |
| { |
| $$ = $2 |
| } |
| | '-' expr |
| { |
| $$.Neg($2) |
| } |
| |
| expr1: |
| expr2 |
| | expr1 '+' expr2 |
| { |
| $$.Add($1, $3) |
| } |
| | expr1 '-' expr2 |
| { |
| $$.Sub($1, $3) |
| } |
| |
| expr2: |
| expr3 |
| | expr2 '*' expr3 |
| { |
| $$.Mul($1, $3) |
| } |
| | expr2 '/' expr3 |
| { |
| $$.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}) |
| } |
| } |