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