github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/cmd/goyacc/testdata/expr/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 // goyacc -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 '+' '-' '*' '/' '(' ')' 36 37 %token <num> NUM 38 39 %% 40 41 top: 42 expr 43 { 44 if $1.IsInt() { 45 fmt.Println($1.Num().String()) 46 } else { 47 fmt.Println($1.String()) 48 } 49 } 50 51 expr: 52 expr1 53 | '+' expr 54 { 55 $$ = $2 56 } 57 | '-' expr 58 { 59 $$ = $2.Neg($2) 60 } 61 62 expr1: 63 expr2 64 | expr1 '+' expr2 65 { 66 $$ = $1.Add($1, $3) 67 } 68 | expr1 '-' expr2 69 { 70 $$ = $1.Sub($1, $3) 71 } 72 73 expr2: 74 expr3 75 | expr2 '*' expr3 76 { 77 $$ = $1.Mul($1, $3) 78 } 79 | expr2 '/' expr3 80 { 81 $$ = $1.Quo($1, $3) 82 } 83 84 expr3: 85 NUM 86 | '(' expr ')' 87 { 88 $$ = $2 89 } 90 91 92 %% 93 94 // The parser expects the lexer to return 0 on EOF. Give it a name 95 // for clarity. 96 const eof = 0 97 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 103 } 104 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) 117 118 // Recognize Unicode multiplication and division 119 // symbols, returning what the parser expects. 120 case '×': 121 return '*' 122 case '÷': 123 return '/' 124 125 case ' ', '\t', '\n', '\r': 126 default: 127 log.Printf("unrecognized character %q", c) 128 } 129 } 130 } 131 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) 137 } 138 } 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 148 } 149 } 150 if c != eof { 151 x.peek = c 152 } 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 158 } 159 return NUM 160 } 161 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 168 } 169 if len(x.line) == 0 { 170 return eof 171 } 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() 177 } 178 return c 179 } 180 181 // The parser calls this method on a parse error. 182 func (x *exprLex) Error(s string) { 183 log.Printf("parse error: %s", s) 184 } 185 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) 191 } 192 line, err := in.ReadBytes('\n') 193 if err == io.EOF { 194 return 195 } 196 if err != nil { 197 log.Fatalf("ReadBytes: %s", err) 198 } 199 200 exprParse(&exprLex{line: line}) 201 } 202 }