-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy patheg_precedence.py
68 lines (52 loc) · 1.42 KB
/
eg_precedence.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
58
59
60
61
62
63
64
65
66
67
68
"""
Infix parsing with operator precedence (inefficient implementation).
"""
from parson import Grammar, recur, seclude, either, fail
def PrececedenceParser(primary_expr, table):
return foldr(lambda make_expr, subexpr: make_expr(subexpr),
primary_expr,
table)
def LeftAssoc(*pairs):
return lambda subexpr: \
seclude(subexpr + alt([peg + subexpr + oper
for peg, oper in pairs]).star())
def RightAssoc(*pairs):
return lambda subexpr: \
recur(lambda expr:
seclude(subexpr + alt([peg + expr + oper
for peg, oper in pairs]).maybe()))
def alt(pegs):
return foldr(either, fail, pegs)
def foldr(f, z, xs):
for x in reversed(xs):
z = f(x, z)
return z
# eg_calc.py example
from operator import *
from parson import delay
_ = delay(lambda: g.FNORD)
exp3 = delay(lambda: g.exp3)
exp1 = PrececedenceParser(exp3, [
LeftAssoc(('*'+_, mul), ('//'+_, div), ('/'+_, truediv), ('%'+_, mod)),
RightAssoc(('^'+_, pow)),
])
exps = PrececedenceParser(exp1, [
LeftAssoc(('+'+_, add), ('-'+_, sub)),
])
g = Grammar(r"""
:exps :end.
exp3 : '(' :exps ')'
| '-' :exp1 :neg
| /(\d+)/ :int.
FNORD ~= /\s*/.
""")(**globals())
## g('42 *(5-3) + -2^2')
#. (80,)
## g('2^3^2')
#. (512,)
## g('5-3-1')
#. (1,)
## g('3//2')
#. (1,)
## g('3/2')
#. (1.5,)