// 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> %{ 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}) } }