GoPLS Viewer

Home|gopls/cmd/goyacc/testdata/expr/expr.y
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
14package main
15
16import (
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
41top:
42    expr
43    {
44        if $1.IsInt() {
45            fmt.Println($1.Num().String())
46        } else {
47            fmt.Println($1.String())
48        }
49    }
50
51expr:
52    expr1
53|    '+' expr
54    {
55        $$ = $2
56    }
57|    '-' expr
58    {
59        $$ = $2.Neg($2)
60    }
61
62expr1:
63    expr2
64|    expr1 '+' expr2
65    {
66        $$ = $1.Add($1, $3)
67    }
68|    expr1 '-' expr2
69    {
70        $$ = $1.Sub($1, $3)
71    }
72
73expr2:
74    expr3
75|    expr2 '*' expr3
76    {
77        $$ = $1.Mul($1, $3)
78    }
79|    expr2 '/' expr3
80    {
81        $$ = $1.Quo($1, $3)
82    }
83
84expr3:
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.
96const 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).
100type 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.
107func (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.
133func (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.
163func (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.
182func (x *exprLex) Error(s string) {
183    log.Printf("parse error: %s", s)
184}
185
186func 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}
203
MembersX
Members
X