-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathshunting_yard.go
134 lines (121 loc) · 1.91 KB
/
shunting_yard.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
130
131
132
133
134
package main
import (
"bufio"
"fmt"
"os"
)
type prop struct {
prec int
assoc string
}
var props = map[byte]prop{
'+': prop{1, "left"},
'-': prop{1, "left"},
'*': prop{2, "left"},
'/': prop{2, "left"},
}
type token struct {
c byte
val int
}
var tok token
var out []token
var stack []token
var reader *bufio.Reader
func push(t token) {
stack = append(stack, t)
}
func pop() token {
t := stack[len(stack)-1]
stack = stack[:len(stack)-1]
return t
}
func peek() token {
return stack[len(stack)-1]
}
func next() {
c, _ := reader.ReadByte()
if c >= '0' && c <= '9' {
reader.UnreadByte()
fmt.Fscanf(reader, "%d", &tok.val)
tok.c = 0
return
}
tok.c = c
}
func shuntingYard() {
for next(); tok.c != '\n'; next() {
switch tok.c {
case 0:
out = append(out, tok)
case '+', '-', '*', '/':
pr := props[tok.c].prec
as := props[tok.c].assoc
for len(stack) > 0 {
spr := props[peek().c].prec
if pr < spr || (pr == spr && as == "left") {
out = append(out, pop())
} else {
break
}
}
push(tok)
case '(':
push(tok)
case ')':
lparn := false
for len(stack) > 0 {
t := pop()
if t.c == '(' {
lparn = true
break
}
out = append(out, t)
}
if !lparn {
panic("mismatched parentheses")
}
}
}
for len(stack) > 0 {
t := pop()
if t.c == '(' || t.c == ')' {
panic("mismatched parentheses")
}
out = append(out, t)
}
}
func eval() int {
for _, t := range out {
switch t.c {
case '+':
y, x := pop(), pop()
x.val += y.val
push(x)
case '-':
y, x := pop(), pop()
x.val -= y.val
push(x)
case '*':
y, x := pop(), pop()
x.val *= y.val
push(x)
case '/':
y, x := pop(), pop()
x.val /= y.val
push(x)
case 0:
push(t)
}
}
return pop().val
}
func main() {
reader = bufio.NewReader(os.Stdin)
for {
shuntingYard()
fmt.Printf("\t%d\n\n", eval())
out = out[:0]
stack = stack[:0]
}
}