OLD | NEW |
(Empty) | |
| 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. |
| 4 |
| 5 // This is an example of a goyacc program. |
| 6 // To build it: |
| 7 // go tool yacc -p "expr" expr.y (produces y.go) |
| 8 // go build -o expr y.go |
| 9 // expr |
| 10 // > <type an expression> |
| 11 |
| 12 %{ |
| 13 |
| 14 package main |
| 15 |
| 16 import ( |
| 17 "bufio" |
| 18 "bytes" |
| 19 "fmt" |
| 20 "io" |
| 21 "log" |
| 22 "math/big" |
| 23 "os" |
| 24 "unicode/utf8" |
| 25 ) |
| 26 |
| 27 %} |
| 28 |
| 29 %union { |
| 30 num *big.Rat |
| 31 } |
| 32 |
| 33 %type <num> expr expr1 expr2 expr3 |
| 34 |
| 35 %token <num> NUM |
| 36 |
| 37 %% |
| 38 |
| 39 top: |
| 40 expr |
| 41 { |
| 42 if $1.IsInt() { |
| 43 fmt.Println($1.Num().String()) |
| 44 } else { |
| 45 fmt.Println($1.String()) |
| 46 } |
| 47 } |
| 48 |
| 49 expr: |
| 50 expr1 |
| 51 | '+' expr |
| 52 { |
| 53 $$ = $2 |
| 54 } |
| 55 | '-' expr |
| 56 { |
| 57 $$.Neg($2) |
| 58 } |
| 59 |
| 60 expr1: |
| 61 expr2 |
| 62 | expr1 '+' expr2 |
| 63 { |
| 64 $$.Add($1, $3) |
| 65 } |
| 66 | expr1 '-' expr2 |
| 67 { |
| 68 $$.Sub($1, $3) |
| 69 } |
| 70 |
| 71 expr2: |
| 72 expr3 |
| 73 | expr2 '*' expr3 |
| 74 { |
| 75 $$.Mul($1, $3) |
| 76 } |
| 77 | expr2 '/' expr3 |
| 78 { |
| 79 $$.Quo($1, $3) |
| 80 } |
| 81 |
| 82 expr3: |
| 83 NUM |
| 84 | '(' expr ')' |
| 85 { |
| 86 $$ = $2 |
| 87 } |
| 88 |
| 89 |
| 90 %% |
| 91 |
| 92 // The parser expects the lexer to return 0 on EOF. Give it a name |
| 93 // for clarity. |
| 94 const eof = 0 |
| 95 |
| 96 // The parser uses the type <prefix>Lex as a lexer. It must provide |
| 97 // the methods Lex(*<prefix>SymType) int and Error(string). |
| 98 type exprLex struct { |
| 99 line []byte |
| 100 peek rune |
| 101 } |
| 102 |
| 103 // The parser calls this method to get each new token. This |
| 104 // implementation returns operators and NUM. |
| 105 func (x *exprLex) Lex(yylval *exprSymType) int { |
| 106 for { |
| 107 c := x.next() |
| 108 switch c { |
| 109 case eof: |
| 110 return eof |
| 111 case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': |
| 112 return x.num(c, yylval) |
| 113 case '+', '-', '*', '/', '(', ')': |
| 114 return int(c) |
| 115 |
| 116 // Recognize Unicode multiplication and division |
| 117 // symbols, returning what the parser expects. |
| 118 case '×': |
| 119 return '*' |
| 120 case '÷': |
| 121 return '/' |
| 122 |
| 123 case ' ', '\t', '\n', '\r': |
| 124 default: |
| 125 log.Printf("unrecognized character %q", c) |
| 126 } |
| 127 } |
| 128 } |
| 129 |
| 130 // Lex a number. |
| 131 func (x *exprLex) num(c rune, yylval *exprSymType) int { |
| 132 add := func(b *bytes.Buffer, c rune) { |
| 133 if _, err := b.WriteRune(c); err != nil { |
| 134 log.Fatalf("WriteRune: %s", err) |
| 135 } |
| 136 } |
| 137 var b bytes.Buffer |
| 138 add(&b, c) |
| 139 L: for { |
| 140 c = x.next() |
| 141 switch c { |
| 142 case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', 'e',
'E': |
| 143 add(&b, c) |
| 144 default: |
| 145 break L |
| 146 } |
| 147 } |
| 148 if c != eof { |
| 149 x.peek = c |
| 150 } |
| 151 yylval.num = &big.Rat{} |
| 152 _, ok := yylval.num.SetString(b.String()) |
| 153 if !ok { |
| 154 log.Printf("bad number %q", b.String()) |
| 155 return eof |
| 156 } |
| 157 return NUM |
| 158 } |
| 159 |
| 160 // Return the next rune for the lexer. |
| 161 func (x *exprLex) next() rune { |
| 162 if x.peek != eof { |
| 163 r := x.peek |
| 164 x.peek = eof |
| 165 return r |
| 166 } |
| 167 if len(x.line) == 0 { |
| 168 return eof |
| 169 } |
| 170 c, size := utf8.DecodeRune(x.line) |
| 171 x.line = x.line[size:] |
| 172 if c == utf8.RuneError && size == 1 { |
| 173 log.Print("invalid utf8") |
| 174 return x.next() |
| 175 } |
| 176 return c |
| 177 } |
| 178 |
| 179 // The parser calls this method on a parse error. |
| 180 func (x *exprLex) Error(s string) { |
| 181 log.Printf("parse error: %s", s) |
| 182 } |
| 183 |
| 184 func main() { |
| 185 in := bufio.NewReader(os.Stdin) |
| 186 for { |
| 187 if _, err := os.Stdout.WriteString("> "); err != nil { |
| 188 log.Fatalf("WriteString: %s", err) |
| 189 } |
| 190 line, err := in.ReadBytes('\n') |
| 191 if err == io.EOF { |
| 192 return |
| 193 } |
| 194 if err != nil { |
| 195 log.Fatalf("ReadBytes: %s", err) |
| 196 } |
| 197 |
| 198 exprParse(&exprLex{line: line}) |
| 199 } |
| 200 } |
OLD | NEW |