模型:
参考这里https://ruslanspivak.com/lsbasi-part8/
# 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,LPAR,RPAR, EOF = 'INTEGER','PLUS','MINUS', 'MULT','DIV','LPAR','RPAR','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,'/') if self.current_char=='(': self.advance() return Token(LPAR,'(') if self.current_char==')': self.advance() return Token(RPAR,')') self.error() return Token(EOF,None) class AST(object): pass class BinOp(AST): def __init__(self,left,op,right): self.left=left self.token=self.op=op self.right=right class Num(AST): def __init__(self,token): self.token=token self.value=token.value class UnaryOp(AST): def __init__(self,op,expr): self.token=self.op=op self.expr=expr 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): """factor : (PLUS | MINUS) factor | INTEGER | LPAREN expr RPAREN""" token=self.current_token if token.type==INTEGER: self.eat(INTEGER) return Num(token) elif token.type==LPAR: self.eat(LPAR) result=self.expr() self.eat(RPAR) return result elif token.type == PLUS: self.eat(PLUS) node=UnaryOp(token,self.factor()) return node elif token.type == MINUS: self.eat(MINUS) node=UnaryOp(token,self.factor()) return node else: self.error() #self.eat(INTEGER) #return token.value #return result 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() r=BinOp(r,Token(MULT,'*'),self.factor()) elif self.current_token.type==DIV: self.eat(DIV) #r=r/self.factor() r=BinOp(r,Token(DIV,'/'),self.factor()) else: #????? break #print("term error....."+self.current_token.type) return r def expr(self): t=self.term() #print('expr---->'+str(t)) #print('expr2---->'+self.current_token.type) while self.current_token.type != EOF : #print('expr3---->'+self.current_token.type) if self.current_token.type==PLUS: self.eat(PLUS) #t=t+self.term() t=BinOp(t,Token(PLUS,'+'),self.term()) elif self.current_token.type==MINUS: self.eat(MINUS) #t=t-self.term() t=BinOp(t,Token(MINUS,'-'),self.term()) else: break return t def parse(self): return self.expr() class NodeVisitor(object): def visit(self,node): method_name='visit_'+type(node).__name__ visitor=getattr(self,method_name,self.generic_visit) return visitor(node) def generic_visit(self,node): raise Exception('No visit_{} method'.format(type(node).__name__)) class Interpreter(NodeVisitor): def __init__(self,parser): self.parser=parser def visit_BinOp(self,node): if node.op.type == PLUS: return self.visit(node.left)+self.visit(node.right) elif node.op.type == MINUS: return self.visit(node.left)-self.visit(node.right) elif node.op.type == MULT: return self.visit(node.left)*self.visit(node.right) elif node.op.type == DIV: return self.visit(node.left)/self.visit(node.right) else: pass def visit_Num(self,node): #print(node.value) return node.value def visit_UnaryOp(self,node): op=node.op if op.type == PLUS: return +self.visit(node.expr) elif op.type == MINUS: return -self.visit(node.expr) else: pass def interprete(self): tree=self.parser.parse() return self.visit(tree) def main(): while True: try: try: text = raw_input('spi> ') #python 2 except NameError: text = input('spi>') #python 3 except EOFError: break if not text: continue lexer=Lexer(text) parser = Parser(lexer) interpreter=Interpreter(parser) result=interpreter.interprete() print(result) if __name__ == '__main__': main()