Python 表达式计算-递归下降的解析器
- #表达式计算-递归下降的解析器
import re
import collections
#Token specification
NUM = r’(?P\d+)’
PLUS = r’(?P+)’
MINUS = r’(?P-)’
TIMES = r’(?P*)’
DIVIDE = r’(?P/)’
LPAREN = r’(?P()’
RPAREN = r’(?P))’
WS = r’(?P\s+)’
master_pat = re.compile(’|’.join([NUM,PLUS,MINUS,TIMES,DIVIDE,LPAREN,RPAREN,WS]))
#Tokenizer
Token = collections.namedtuple(‘Token’, [‘type’,‘value’])
def generate_tokens(text):
scanner = master_pat.scanner(text)
for m in iter(scanner.match, None):
tok = Token(m.lastgroup,m.group())
if tok.type != ‘WS’:
yield tok
#Parser
class ExpressionEvaluator:
‘’’
Implementation of a recursive desent parser. Each method implements a single
grammar rule.Use the ._accept() method to test and accept the current lookahead
token.Use the ._expect() method to exactly match and discard the next token
on on the input (or raise a SyntaxError if it doesn’t match).
‘’’
def parse(self,text):
self.tokens = generate_tokens(text)
self.tok = None
self.nexttok = None
self._advance()
return self.expr()
def _advance(self):
'Advance one token ahead'
self.tok,self.nexttok = self.nexttok, next(self.tokens,None)
def _accept(self,toktype):
'Test and consume the next token if it matches toktype'
if self.nexttok and self.nexttok.type == toktype:
self._advance()
return True
else:
return False
def _expect(self,toktype):
'Consume next token if it matches toktype or raise SyntaxError'
if not self._accept(toktype):
raise SyntaxError('Expected ' + toktype)
#Grammar rules follow
def expr(self):
"expression ::= term { ('+'|'-') term }*"
exprval = self.term()
while self._accept('PLUS') or self._accept('MINUS'):
op = self.tok.type
right = self.term()
if op == 'PLUS':
#exprval += right
exprval = ('+', exprval, right)
elif op == 'MINUS':
#exprval -= right
exprval = ('-', exprval,right)
return exprval
def term(self):
"term ::= factor {('*'|'/') factor }*"
termval = self.factor()
while self._accept('TIMES') or