# Token types # EOF (end-of-file) token is used to indicate that # there is no more input left for lexical analysis INTEGER, PLUS, MINUS, EOF = 'INTEGER', 'PLUS', 'MINUS', 'EOF'
classToken(object): def__init__(self, type, value): # token type: INTEGER, PLUS, MINUS, or EOF self.type = type # token value: non-negative integer value, '+', '-', 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): returnself.__str__()
classInterpreter(object): def__init__(self, text): # client string input, e.g. "3 + 5", "12 - 5", etc self.text = text # self.pos is an index into self.text self.pos = 0 # current token instance self.current_token = None self.current_char = self.text[self.pos]
defadvance(self): """Advance the 'pos' pointer and set the 'current_char' variable.""" self.pos += 1 ifself.pos > len(self.text) - 1: self.current_char = None# Indicates end of input else: self.current_char = self.text[self.pos]
definteger(self): """Return a (multidigit) integer consumed from the input.""" result = '' whileself.current_char isnotNoneandself.current_char.isdigit(): result += self.current_char self.advance() returnint(result)
defget_next_token(self): """Lexical analyzer (also known as scanner or tokenizer) This method is responsible for breaking a sentence apart into tokens. """ whileself.current_char isnotNone:
defeat(self, token_type): # compare the current token type with the passed token # type and if they match then "eat" the current token # and assign the next token to the self.current_token, # otherwise raise an exception. ifself.current_token.type == token_type: self.current_token = self.get_next_token() else: self.error()
defexpr(self): """Parser / Interpreter expr -> INTEGER PLUS INTEGER expr -> INTEGER MINUS INTEGER """ # set current token to the first token taken from the input self.current_token = self.get_next_token()
# we expect the current token to be an integer left = self.current_token self.eat(INTEGER)
# we expect the current token to be either a '+' or '-' op = self.current_token if op.type == PLUS: self.eat(PLUS) else: self.eat(MINUS)
# we expect the current token to be an integer right = self.current_token self.eat(INTEGER) # after the above call the self.current_token is set to # EOF token
# at this point either the INTEGER PLUS INTEGER or # the INTEGER MINUS INTEGER sequence of tokens # has been successfully found and the method can just # return the result of adding or subtracting two integers, # thus effectively interpreting client input if op.type == PLUS: result = left.value + right.value else: result = left.value - right.value return result
defmain(): whileTrue: try: # To run under Python3 replace 'raw_input' call # with 'input' text = raw_input('calc> ') except EOFError: break ifnot text: continue interpreter = Interpreter(text) result = interpreter.expr() print(result)
这样,你知道方法expr()在你的解释器中既充当解析器,也充当执行器——该方法首先尝试在Token流中识别(解析)INTEGER -> PLUS -> INTEGER或者INTEGER -> MINUS -> INTEGER,在成功识别(解析)到其中一个“短语”后,该方法就对它解释执行,并把两个整数进行加减运算的结果返回给调用者。