diff options
author | Tianon Gravi <admwiggin@gmail.com> | 2015-01-15 11:54:00 -0700 |
---|---|---|
committer | Tianon Gravi <admwiggin@gmail.com> | 2015-01-15 11:54:00 -0700 |
commit | f154da9e12608589e8d5f0508f908a0c3e88a1bb (patch) | |
tree | f8255d51e10c6f1e0ed69702200b966c9556a431 /src/cmd/yacc/testdata/expr/expr.y | |
parent | 8d8329ed5dfb9622c82a9fbec6fd99a580f9c9f6 (diff) | |
download | golang-upstream/1.4.tar.gz |
Imported Upstream version 1.4upstream/1.4
Diffstat (limited to 'src/cmd/yacc/testdata/expr/expr.y')
-rw-r--r-- | src/cmd/yacc/testdata/expr/expr.y | 202 |
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}) + } +} |