-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcalculator.py
executable file
·57 lines (45 loc) · 1.83 KB
/
calculator.py
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
#! /usr/bin/env python
from fastidious import Parser
class Calculator(Parser):
# __grammar__ is the PEG definition. Each `rulename <- a rule`
# adds a method `Calculator.rulename()`. This methods tries to
# match the input at current position
__grammar__ = r"""
# the label is ommited. `:expr` is equivalent to `expr:expr`
eval <- :expr EOF {@expr}
# action {on_expr} calls `Calculator.on_expr(self, value, first, rest)`
# on match. `first` and `rest` args are the labeled parts of the rule
term <- first:factor rest:( _ mult_op _ factor )* {on_expr}
# Because the Parser has a method named `on_expr` ("on_" + rulename)
# this method is the implicit action of this rule. We omitted {on_expr}
expr "EXPRESSION" <- _ first:term rest:( _ add_op _ term )* _
# there's no explicit or implicit action. These rules return their exact
# matches. The alias OPERATOR is used in error messages
add_op "OPERATOR" <- '+' / '-'
mult_op "OPERATOR" <- '*' / '/'
# action {@fact} means : return only the match of part labeled `fact`.
factor "EXPRESSION" <- ( '(' fact:expr ')' ) / fact:integer {@fact}
integer "INT"<- '-'? [0-9]+
_ <- [ \n\t\r]*
# this one is tricky. `.` means "any char". At EOF there's no char,
# thus Not any char, thus `!.`
EOF <- !.
"""
def on_expr(self, value, first, rest):
result = first
for r in rest:
op = r[1]
if op == '+':
result += r[3]
elif op == '-':
result -= r[3]
elif op == '*':
result *= r[3]
else:
result /= r[3]
return result
def on_integer(self, value):
return int(self.p_flatten(value))
if __name__ == "__main__":
import sys
print(Calculator.p_parse("".join(sys.argv[1:])))