实现一个简单的解释器,其中只包含整数和加减乘除符号,无括号,并且乘除优先级最高。
参考这里:https://github.com/rspivak/lsbasi
# Token types
#
# EOF (end-of-file) token is used to indicate that
# there is no more input left for lexical analysis
INTEGER, PLUS,MINUS,MULT, DIV, EOF = 'INTEGER','PLUS','MINUS', 'MULT','DIV', 'EOF'
class Token(object):
def __init__(self, type, value):
# token type: INTEGER, PLUS, or EOF
self.type = type
# token value: 0, 1, 2. 3, 4, 5, 6, 7, 8, 9, '+', or None
self.value = value
def __str__(self):
"""String representation of the class instance.
Examples:
Token(INTEGER, 3)
Token(PLUS '+')
"""
return 'Token({type}, {value})'.format(
type=self.type,
value=repr(self.value)
)
def __repr__(self):
return self.__str__()
class Lexer(object):
def __init__(self,text):
self.text=text
self.current_pos=0
self.current_char=self.text[self.current_pos]
def error(self):
raise Exception('Invalid character!')
def advance(self):
self.current_pos+=1
if self.current_pos > len(self.text)-1 :
self.current_char=None
else:
self.current_char=self.text[self.current_pos]
def skip_whitespace(self):
while self.current_char is not None and self.current_char.isspace():
self.advance()
def integer(self):
result=''
while self.current_char is not None and self.current_char.isdigit():
result+=self.current_char
self.advance()
return int(result)
def get_next_token(self):
while self.current_char is not None:
#print('get_next_token---->'+self.current_char)
if self.current_char.isspace():
self.skip_whitespace()
continue
if self.current_char.isdigit():
return Token(INTEGER,self.integer())
if self.current_char=='+':
self.advance()
return Token(PLUS,'+')
if self.current_char=='-':
self.advance()
return Token(MINUS,'-')
if self.current_char=='*':
self.advance()
return Token(MULT,'*')
if self.current_char=='/':
self.advance()
return Token(DIV,'/')
self.error()
return Token(EOF,None)
class Parser(object):
def __init__(self,lexer):
self.lexer=lexer
self.current_token=self.lexer.get_next_token()
def error(self):
raise Exception('Invalid syntax')
def eat(self,token_type):
#print('eat---->'+self.current_token.type)
if self.current_token.type==token_type:
self.current_token=self.lexer.get_next_token()
else:
self.error()
def factor(self):
token=self.current_token
self.eat(INTEGER)
return token.value
def term(self):
r=self.factor()
#print('term---->'+self.current_token.type)
while self.current_token.type != EOF :
if self.current_token.type==MULT:
self.eat(MULT)
r=r*self.factor()
elif self.current_token.type==DIV:
self.eat(DIV)
r=r/self.factor()
else:
break
#print("term error....."+self.current_token.type)
return r
def expr(self):
t=self.term()
#print('expr---->'+str(t))
while self.current_token.type != EOF :
if self.current_token.type==PLUS:
self.eat(PLUS)
t=t+self.term()
elif self.current_token.type==MINUS:
self.eat(MINUS)
t=t-self.term()
else:
#????
pass
return t
def parse(self):
return self.expr()
def main():
while True:
try:
# To run under Python3 replace 'raw_input' call
# with 'input'
text = raw_input('calc> ')
except EOFError:
break
if not text:
continue
parser = Parser(Lexer(text))
result=parser.parse()
print(result)
if __name__ == '__main__':
main()