上文中实现了一个可以支持
- 两个整数间的加减法
- 允许空格
的计算器,但这显然太逊了,咱们一步一步来,先把它拓展到支持多个整数相加减
整数计算器 Version 7
先思考一下,如果要支持任意多个整数相加减,这样的输入的元素序列是怎样的?
NUMBER((PLUS|MINUS)NUMBER)*
可以用上述模式表示,其中 |
表示或
,*
表示任意个(0个或多个),可正则表达式类似
搞懂了这一点,就可以修改咱们的解释器了,由于token类型不变,所以只需要修改 Interpreter 类
"""
expr: NUMBER((PLUS|MINUS)NUMBER)*
"""
NUMBER, PLUS, MINUS, EOF = 'NUMBER', 'PLUS', 'MINUS', 'EOF'
class Token:
def __init__(self, token_type, value):
self.type = token_type
self.value = value
def __repr__(self,):
return f'Token({self.type}, {self.value})'
class Lexer:
def __init__(self, text):
self.text = text
self.pos = 0
self.current_char = self.text[self.pos]
def error(self,):
raise Exception('Lexer Error!')
def get_next_token(self, ):
if self.pos >= len(self.text):
return Token(EOF, None)
self.current_char = self.text[self.pos]
if self.current_char == ' ':
while self.current_char == ' ':
self.pos += 1
if self.pos >= len(self.text):
return Token(EOF, None)
self.current_char = self.text[self.pos]
if self.current_char.isdigit():
number = ''
while self.current_char.isdigit():
number += self.current_char
self.pos += 1
if self.pos >= len(self.text):
break
self.current_char = self.text[self.pos]
return Token(NUMBER, int(number))
if self.current_char == '+':
self.pos += 1
return Token(PLUS, '+')
if self.current_char == '-':
self.pos += 1
return Token(MINUS, '-')
self.error()
class Interpreter:
def __init__(self, lexer):
self.lexer = lexer
self.current_token = None
def get_next_token(self,):
self.current_token = self.lexer.get_next_token()
return self.current_token
def error(self, msg = ''):
raise Exception(f'Parse Error! {msg}')
def eat(self, token_type):
if type(token_type) == list and self.current_token.type not in token_type:
self.error(f'current token not in list, expect {token_type}, got {self.current_token}.')
elif type(token_type) == str and self.current_token.type != token_type:
self.error(f'current token not match, expect {token_type}, got {self.current_token}.')
def expr(self,):
result = 0
term = self.get_next_token()
self.eat(NUMBER)
result += term.value
while(self.get_next_token().type != EOF):
op = self.current_token
self.eat([PLUS, MINUS])
term = self.get_next_token()
self.eat(NUMBER)
if op.type == PLUS:
result += term.value
else:
result -= term.value
return result
def main():
while True:
try:
text = input('cal> ')
lexer = Lexer(text)
interpreter = Interpreter(lexer)
print(interpreter.expr())
except Exception as e:
print(e)
break
main()
咱们支持多个整数相加减的计算器就实现了,
代码实现也很简答,while循环很容易就可以实现任意个整数
整数计算器 Version 8
写代码的时候发现 get_next_token, current_token 交替使用有些别扭,于是再把这一块优化一下
"""
expr: NUMBER((PLUS|MINUS)NUMBER)*
"""
class Interpreter:
def __init__(self, lexer):
self.lexer = lexer
self.current_token = self.lexer.get_next_token()
def error(self, msg = ''):
raise Exception(f'Parse Error! {msg}')
def eat(self, token_type):
if type(token_type) == list and self.current_token.type not in token_type:
self.error(f'current token not in list, expect {token_type}, got {self.current_token}.')
elif type(token_type) == str and self.current_token.type != token_type:
self.error(f'current token not match, expect {token_type}, got {self.current_token}.')
else:
self.current_token = self.lexer.get_next_token()
def expr(self,):
result = 0
term = self.current_token
self.eat(NUMBER)
result += term.value
while(self.current_token.type != EOF):
op = self.current_token
self.eat([PLUS, MINUS])
term = self.current_token
self.eat(NUMBER)
if op.type == PLUS:
result += term.value
else:
result -= term.value
return result
def main():
while True:
try:
text = input('cal> ')
lexer = Lexer(text)
interpreter = Interpreter(lexer)
print(interpreter.expr())
except Exception as e:
print(e)
break
main()
将 get_next_token 合并到 eat 函数里,这样每次只要调用 current_token + eat 就可以了,代码上整齐一点!
到目前为止,咱们已经实现了能够支持任意个整数相加减的计算器了
接下来给它增加乘除运算,且看下回分解!