summaryrefslogtreecommitdiff
path: root/src/cmd/yacc/testdata/expr/expr.y
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/yacc/testdata/expr/expr.y')
-rw-r--r--src/cmd/yacc/testdata/expr/expr.y202
1 files changed, 202 insertions, 0 deletions
diff --git a/src/cmd/yacc/testdata/expr/expr.y b/src/cmd/yacc/testdata/expr/expr.y
new file mode 100644
index 000000000..721b1c917
--- /dev/null
+++ b/src/cmd/yacc/testdata/expr/expr.y
@@ -0,0 +1,202 @@
+// 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
+ {
+ $$.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})
+ }
+}