purescript
[tastes.git] / goyacc / expr / expr.y
blobba4a1b231678b498e93adc35c2d0e66678cd54dd
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.
6 // To build it:
7 // goyacc -p "expr" expr.y (produces y.go)
8 // go build -o expr y.go
9 // expr
10 // > <type an expression>
14 package main
16 import (
17 "bufio"
18 "bytes"
19 "fmt"
20 "io"
21 "log"
22 "math/big"
23 "os"
24 "unicode/utf8"
29 %union {
30 num *big.Rat
33 %type <num> expr expr1 expr2 expr3
35 %token '+' '-' '*' '/' '(' ')'
37 %token <num> NUM
41 top:
42 expr
44 if $1.IsInt() {
45 fmt.Println($1.Num().String())
46 } else {
47 fmt.Println($1.String())
51 expr:
52 expr1
53 | '+' expr
55 $$ = $2
57 | '-' expr
59 $$ = $2.Neg($2)
62 expr1:
63 expr2
64 | expr1 '+' expr2
66 $$ = $1.Add($1, $3)
68 | expr1 '-' expr2
70 $$ = $1.Sub($1, $3)
73 expr2:
74 expr3
75 | expr2 '*' expr3
77 $$ = $1.Mul($1, $3)
79 | expr2 '/' expr3
81 $$ = $1.Quo($1, $3)
84 expr3:
85 NUM
86 | '(' expr ')'
88 $$ = $2
94 // The parser expects the lexer to return 0 on EOF. Give it a name
95 // for clarity.
96 const eof = 0
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 {
101 line []byte
102 peek rune
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 {
108 for {
109 c := x.next()
110 switch c {
111 case eof:
112 return eof
113 case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
114 return x.num(c, yylval)
115 case '+', '-', '*', '/', '(', ')':
116 return int(c)
118 // Recognize Unicode multiplication and division
119 // symbols, returning what the parser expects.
120 case '×':
121 return '*'
122 case '÷':
123 return '/'
125 case ' ', '\t', '\n', '\r':
126 default:
127 log.Printf("unrecognized character %q", c)
132 // Lex a number.
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)
139 var b bytes.Buffer
140 add(&b, c)
141 L: for {
142 c = x.next()
143 switch c {
144 case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', 'e', 'E':
145 add(&b, c)
146 default:
147 break L
150 if c != eof {
151 x.peek = c
153 yylval.num = &big.Rat{}
154 _, ok := yylval.num.SetString(b.String())
155 if !ok {
156 log.Printf("bad number %q", b.String())
157 return eof
159 return NUM
162 // Return the next rune for the lexer.
163 func (x *exprLex) next() rune {
164 if x.peek != eof {
165 r := x.peek
166 x.peek = eof
167 return r
169 if len(x.line) == 0 {
170 return eof
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")
176 return x.next()
178 return c
181 // The parser calls this method on a parse error.
182 func (x *exprLex) Error(s string) {
183 log.Printf("parse error: %s", s)
186 func main() {
187 in := bufio.NewReader(os.Stdin)
188 for {
189 if _, err := os.Stdout.WriteString("> "); err != nil {
190 log.Fatalf("WriteString: %s", err)
192 line, err := in.ReadBytes('\n')
193 if err == io.EOF {
194 return
196 if err != nil {
197 log.Fatalf("ReadBytes: %s", err)
200 exprParse(&exprLex{line: line})