1 // Copyright 2013 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // This is an example of a goyacc program.
7 // goyacc -p "expr" expr.y (produces y.go)
8 // go build -o expr y.go
10 // > <type an expression>
33 %type <num> expr expr1 expr2 expr3
35 %token '+' '-' '*' '/' '(' ')'
45 fmt.Println($1.Num().String())
47 fmt.Println($1.String())
94 // The parser expects the lexer to return 0 on EOF. Give it a name
98 // The parser uses the type <prefix>Lex as a lexer. It must provide
99 // the methods Lex(*<prefix>SymType) int and Error(string).
100 type exprLex struct {
105 // The parser calls this method to get each new token. This
106 // implementation returns operators and NUM.
107 func (x *exprLex) Lex(yylval *exprSymType) int {
113 case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
114 return x.num(c, yylval)
115 case '+', '-', '*', '/', '(', ')':
118 // Recognize Unicode multiplication and division
119 // symbols, returning what the parser expects.
125 case ' ', '\t', '\n', '\r':
127 log.Printf("unrecognized character %q", c)
133 func (x *exprLex) num(c rune, yylval *exprSymType) int {
134 add := func(b *bytes.Buffer, c rune) {
135 if _, err := b.WriteRune(c); err != nil {
136 log.Fatalf("WriteRune: %s", err)
144 case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', 'e', 'E':
153 yylval.num = &big.Rat{}
154 _, ok := yylval.num.SetString(b.String())
156 log.Printf("bad number %q", b.String())
162 // Return the next rune for the lexer.
163 func (x *exprLex) next() rune {
169 if len(x.line) == 0 {
172 c, size := utf8.DecodeRune(x.line)
173 x.line = x.line[size:]
174 if c == utf8.RuneError && size == 1 {
175 log.Print("invalid utf8")
181 // The parser calls this method on a parse error.
182 func (x *exprLex) Error(s string) {
183 log.Printf("parse error: %s", s)
187 in := bufio.NewReader(os.Stdin)
189 if _, err := os.Stdout.WriteString("> "); err != nil {
190 log.Fatalf("WriteString: %s", err)
192 line, err := in.ReadBytes('\n')
197 log.Fatalf("ReadBytes: %s", err)
200 exprParse(&exprLex{line: line})