mirror of
https://github.com/heqin-zhu/algorithm.git
synced 2024-03-22 13:30:46 +08:00
125 lines
3.5 KiB
Python
125 lines
3.5 KiB
Python
import re
|
|
from collections import namedtuple
|
|
left = r'(?P<LEFT>\()'
|
|
right = r'(?P<RIGHT>\))'
|
|
word = r'(?P<WORD>[a-z][a-z0-9]*)'
|
|
num = r'(?P<NUM>(\-)?\d+)'
|
|
blank = r'(?P<BLANK>\s+)'
|
|
pt = re.compile('|'.join([left, right, word, num, blank]))
|
|
|
|
token = namedtuple('token', ['type', 'value'])
|
|
|
|
|
|
def genToken(s):
|
|
scanner = pt.scanner(s)
|
|
for i in iter(scanner.match, None):
|
|
if i.lastgroup != 'BLANK':
|
|
yield token(i.lastgroup, i.group(0))
|
|
|
|
|
|
class parser(object):
|
|
'''grammar:
|
|
S-> '(' expr ')'
|
|
expr -> [mult|add] item item | let {word item } item
|
|
item -> num | word| S
|
|
'''
|
|
|
|
def config(self,s):
|
|
if s:
|
|
self.token = [i for i in genToken(s)]
|
|
self.lookahead = 0
|
|
self.vars = []
|
|
|
|
def parse(self, s):
|
|
self.config(s)
|
|
try:
|
|
return self.S()
|
|
except Exception as e:
|
|
return e
|
|
|
|
def match(self, curType):
|
|
sym = self.token[self.lookahead]
|
|
if sym.type == curType:
|
|
self.lookahead += 1
|
|
return sym.value
|
|
self.errorinfo(f'Expected {curType}, got {sym.value}')
|
|
|
|
def errorinfo(self, s, k=None):
|
|
if k is None:
|
|
k = self.lookahead
|
|
pre = ' '.join([t.value for t in self.token[:k]])
|
|
suf = ' '.join([t.value for t in self.token[k:]])
|
|
print(pre+' '+suf)
|
|
print(' '*(len(pre)+1)+'^'*len(self.token[k].value))
|
|
raise Exception(s)
|
|
|
|
def readVar(self, var):
|
|
for dic in self.vars[::-1]:
|
|
if var in dic:
|
|
return dic[var]
|
|
self.errorinfo(f"Undefined varible '{var}'", self.lookahead-1)
|
|
|
|
def S(self):
|
|
self.vars.append({})
|
|
self.match('LEFT')
|
|
ret = self.expr()
|
|
self.match('RIGHT')
|
|
self.vars.pop()
|
|
return ret
|
|
|
|
def expr(self):
|
|
op = self.match('WORD')
|
|
if op == 'let':
|
|
while self.token[self.lookahead].type != 'RIGHT':
|
|
if self.token[self.lookahead].type == 'WORD':
|
|
var = self.match('WORD')
|
|
if self.token[self.lookahead].type == 'RIGHT':
|
|
return self.readVar(var)
|
|
else:
|
|
self.vars[-1][var] = self.item()
|
|
else:
|
|
return self.item()
|
|
elif op in {'mult', 'add'}:
|
|
a = self.item()
|
|
b = self.item()
|
|
if op == 'mult':
|
|
return a*b
|
|
elif op == 'add':
|
|
return a+b
|
|
else:
|
|
self.errorinfo('Unknown keyword', self.lookahead-1)
|
|
|
|
def item(self):
|
|
if self.token[self.lookahead].type == 'WORD':
|
|
return self.readVar(self.match('WORD'))
|
|
elif self.token[self.lookahead].type == 'NUM':
|
|
return int(self.match('NUM'))
|
|
else:
|
|
return self.S()
|
|
|
|
|
|
class Solution(object):
|
|
def evaluate(self, expression: str) -> int:
|
|
return parser().parse(expression)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sol = Solution()
|
|
|
|
exprs = ['(add -1 2)',
|
|
'(let x -2 y x y)',
|
|
'(mult 3 (add 2 3))',
|
|
'(let x 2 (mult x 5))',
|
|
'(let x 2 (mult x (let x 3 y 4 (add x y))))',
|
|
'(let x 2 x 3 x)',
|
|
'(let x 2 (add (let x 3 (let x 4 x)) x))',
|
|
'(let a1 3 b2 (add a1 1) b2)',
|
|
'add 1 2)', # wrongs
|
|
'(asd 1 2)',
|
|
'(let a 1 b)',
|
|
'(let a 1 b 2)'
|
|
]
|
|
for e in exprs:
|
|
print('>>>', e)
|
|
print(sol.evaluate(e))
|