-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathparser04.py
More file actions
92 lines (74 loc) · 2.83 KB
/
parser04.py
File metadata and controls
92 lines (74 loc) · 2.83 KB
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
class Token(object):
def __init__(self,atype,avalue):
self.type = atype
self.value = avalue
def __eq__(self,other):
if isinstance(other,Token):
return self.type==other.type and self.value==other.value
return self.type==other
def __repr__(self):
return f"({self.type} {self.value})"
def tokenizer(xs):
tokens=[]
symbols = {"(":"lparen",")":"rparen","=":"equal", ";":"semi", "+":"op","-":"op","*":"op","/":"op" }
for x in xs:
if x.isalpha():
tokens.append( Token("name",x) )
elif x.isdigit():
tokens.append( Token("number", int(x)) )
elif x in symbols.keys():
tokens.append( Token(symbols[x],x) )
return tokens
class Parser:
def __init__(self,code):
self.code = code
self.i=0
self.current = self.code[0]
def next(self):
self.i+=1
alist = self.code[self.i:self.i+1] or [Token("eof",object())]
self.current = alist[0]
def matching(self,*args):
for i,arg in enumerate(args):
if arg==None or arg==self.code[self.i+i]:
continue
if isinstance(arg,list):
if self.code[self.i+i] in arg:
continue
return False
return True
def match(self, a):
if self.current==a or (isinstance(a,list) and self.current in a):
result=self.current.value
self.next()
return result
raise Exception(f"match error: {a}")
def parse_expression(self,left=False,op=False):
precedence ={"+":0,"-":0,"*":2,"/":1}
if self.matching("lparen"):
self.match("lparen")
result = self.parse_expression()
self.match("rparen")
if left:
result = [op,left,result]
if self.matching("op"):
op2 = self.match("op")
return self.parse_expression(result,op2)
return result
if self.matching(["name","number"],["semi","rparen"]):
name_or_number = self.match(["name","number"])
if left:
return [op,left,name_or_number]
return name_or_number
if self.matching(["name","number"],"op") and left:
name_or_number = self.match(["name","number"])
op2 = self.match("op")
if precedence[op]>precedence[op2]:
return self.parse_expression([op,left,name_or_number],op2)
return [op,left,self.parse_expression(name_or_number,op2)]
if self.matching(["name","number"],"op"):
name_or_number = self.match(["name","number"])
op = self.match("op")
return self.parse_expression(name_or_number,op)
p=Parser(tokenizer("(1+2)+(3+4);"))
print(p.parse_expression());