-
Notifications
You must be signed in to change notification settings - Fork 1
/
main.go
129 lines (107 loc) · 1.85 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package main
import (
"fmt"
"os"
"strconv"
"text/scanner"
)
//go:generate go tool yacc -o silly.go -p "silly" silly.y
type sillyLex struct {
s scanner.Scanner
}
func (x *sillyLex) Lex(yylval *sillySymType) int {
tok := x.s.Scan()
switch {
case tok > 0:
return int(tok)
case tok == scanner.EOF:
return 0
case tok == scanner.Ident:
yylval.ident = x.s.TokenText()
return IDENT
case tok == scanner.Int:
yylval.val, _ = strconv.Atoi(x.s.TokenText())
return VAL
}
panic("unsupported token: " + x.s.TokenText())
}
type function struct{}
type env struct {
bindings map[string]int
functions map[string]*function
next *env
}
func newEnv(next *env) *env {
return &env{make(map[string]int), make(map[string]*function), next}
}
func (x *sillyLex) Error(message string) {
panic(message)
}
type node interface {
eval(e *env) int
}
type intNode struct {
val int
}
func (n *intNode) eval(e *env) int {
return n.val
}
type binopNode struct {
op string
left, right node
}
func (n *binopNode) eval(e *env) int {
ll := n.left.eval(e)
rr := n.right.eval(e)
switch n.op {
case "+":
return ll + rr
case "-":
return ll - rr
case "/":
return ll / rr
case "*":
return ll * rr
}
panic("unsupported op: " + n.op)
}
type assignNode struct {
ident string
right node
}
func (n *assignNode) eval(e *env) int {
v := n.right.eval(e)
e.bindings[n.ident] = v
return v
}
type identNode struct {
ident string
}
func (n *identNode) eval(e *env) int {
for e != nil {
if v, ok := e.bindings[n.ident]; ok {
return v
}
e = e.next
}
return 0
}
type stmtList struct {
c node
next *stmtList
}
func (n *stmtList) eval(e *env) int {
v := 0
for n != nil {
v = n.c.eval(e)
n = n.next
}
return v
}
var r node
func main() {
var s scanner.Scanner
s.Init(os.Stdin)
sillyParse(&sillyLex{s})
fmt.Println(r.eval(newEnv(nil)))
}