整数计算器 Version 4
上一篇文章中,实现了一个能够支持任意位数的整数加法的计算器,下面来把它拓展减法
具体修改之处:
- get_next_token 函数增加减号的识别
- expr 函数增加减法运算
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 Interpreter:
def __init__(self, text):
self.text = text
self.pos = 0
self.current = None
def error(self,):
raise Exception('Parse Error!')
def get_next_token(self, ):
if self.pos >= len(self.text):
return Token(EOF, None)
self.current = self.text[self.pos]
if self.current == ' ':
while self.current == ' ':
self.pos += 1
if self.pos >= len(self.text):
return Token(EOF, None)
self.current = self.text[self.pos]
if self.current.isdigit():
number = ''
while self.current.isdigit():
number += self.current
self.pos += 1
if self.pos >= len(self.text):
break
self.current = self.text[self.pos]
return Token(NUMBER, int(number))
if self.current == '+':
self.pos += 1
return Token(PLUS, '+')
if self.current == '-':
self.pos += 1
return Token(MINUS, '+')
self.error()
def expr(self,):
a = self.get_next_token()
op = self.get_next_token()
b = self.get_next_token()
if op.type == PLUS:
result = a.value + b.value
else:
result = a.value - b.value
return result
def main():
while True:
try:
text = input('cal> ')
interpreter = Interpreter(text)
print(interpreter.expr())
except Exception as e:
print(e)
break
main()
可以看到两个整数之间的加减法都已经可以支持了!
但是,超过两个数的时候还是不行,咱们后续再改进。
现在可以先把当前代码重构一下,因为注意到元素的识别和运算可以拆分成两个独立的功能,所以接下来,分离出一个类来执行词法分析的功能,称为 Lexer。
整数计算器 Version 5
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.get_next_token = self.lexer.get_next_token
def expr(self,):
a = self.get_next_token()
op = self.get_next_token()
b = self.get_next_token()
if op.type == PLUS:
result = a.value + b.value
else:
result = a.value - b.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()
上述代码中,Lexer用于从输入的字符中识别出元素类型:多位整数、加号、减号,Interpreter则只做运算
从这版代码中,有个明显的缺陷是 Interpreter 没有进行错误处理,所以下面给它加上运算时的错误处理
整数计算器 Version 6
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,):
a = self.get_next_token()
self.eat(NUMBER)
op = self.get_next_token()
self.eat([PLUS, MINUS])
b = self.get_next_token()
self.eat(NUMBER)
if op.type == PLUS:
result = a.value + b.value
else:
result = a.value - b.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()
新增了一个eat函数,用来校验当前的token是不是期望的类型,如果不是则报错!
接下来,咱们来把它拓展成支持任意多个整数相加减的计算器,且看下回分解!