-
Notifications
You must be signed in to change notification settings - Fork 0
/
parsercr.cr
132 lines (119 loc) · 3.06 KB
/
parsercr.cr
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
require "./parser.cr"
enum TerminalIds
# in the grammar, whitespace has [skip] so this token will never appear
Whitespace
Number
Add
Minus
Mul
Div
LParen
RParen
end
enum NonTerminalIds
S
Expr
Fact
Atom
end
allowableTerminalIds = [
TerminalIds::Number,
TerminalIds::Add,
TerminalIds::Minus,
TerminalIds::Mul,
TerminalIds::Div,
]
def evaluate(tree, allowableTerminalIds)
case tree
# parse leaves of the tree
when Pegasus::Generated::TerminalTree
tId = TerminalIds.new(Int32.new tree.terminal_id)
if !(allowableTerminalIds.includes? tId)
return Nil
else
if tId == TerminalIds::Number
return Float64.new tree.string
else
return tId
end
end
# parse branches of the tree
when Pegasus::Generated::NonterminalTree
nodeType = NonTerminalIds.new(Int32.new tree.nonterminal_id)
case nodeType
when NonTerminalIds::S
return evaluate(tree.children[0], allowableTerminalIds)
when NonTerminalIds::Atom
# number
if (tree.children.size == 1)
return evaluate(tree.children[0], allowableTerminalIds)
else
# parenthesis
return evaluate(tree.children[1], allowableTerminalIds)
end
when NonTerminalIds::Fact
# atom
if (tree.children.size == 1)
return evaluate(tree.children[0], allowableTerminalIds)
else
# mul or div
lhs = evaluate(tree.children[0], allowableTerminalIds)
sign = evaluate(tree.children[1], allowableTerminalIds)
rhs = evaluate(tree.children[2], allowableTerminalIds)
case lhs
when Float64
case rhs
when Float64
case sign
when TerminalIds::Mul
return lhs * rhs
when TerminalIds::Div
return lhs / rhs
end
end
end
end
when NonTerminalIds::Expr
# atom
if (tree.children.size == 1)
return evaluate(tree.children[0], allowableTerminalIds)
else
# add or sub
lhs = evaluate(tree.children[0], allowableTerminalIds)
sign = evaluate(tree.children[1], allowableTerminalIds)
rhs = evaluate(tree.children[2], allowableTerminalIds)
case lhs
when Float64
case rhs
when Float64
case sign
when TerminalIds::Add
return lhs + rhs
when TerminalIds::Minus
return lhs - rhs
end
end
end
end
end
end
puts "oops, parse_tree() should never reach this statement! something broke!"
end
def print_tree(tree, ident = 0)
ident.times { STDOUT << "| " }
case tree
when Pegasus::Generated::TerminalTree
puts "terminal tree: #{tree.terminal_id}, #{tree.string}"
when Pegasus::Generated::NonterminalTree
puts "non terminal tree: #{tree.name}"
tree.children.each { |it| print_tree(it, ident + 1) }
end
end
raw = gets
case raw
in String
tree = Pegasus::Generated.process(raw)
puts evaluate(tree, allowableTerminalIds)
in Nil
puts "pegasus returned nil wtf"
end