1.介绍
本系列文章参照该教程学习总结,欢迎查看原文。我个人的学习代码已经放到我的github
词法分析、语法分析、语义分析等定义请参考编译器解释器中的词法分析、语法分析、语义分析
2.概念补充巩固
2.1 语法图
语法图:语法图是指表示一种程序设计语言语法规则的示意图。本质上,一个语法图直观地显示了在你的程序设计语言中,允许使用哪些语句和不允许使用哪些语句。
语法图的两个主要目的:
它们以图表的形式表示一种程序设计语言的规范(语法)。
它们可以帮助你编写解析器,你可以通过遵循简单的规则将一个图表映射成代码。
上图中term指的是输入表达式当中的token,以上的语法图改写成代码为:
def term(self): #匹配期望类型
self.eat(INTEGER) # 注意eat过程后current_token指向下一个token
def expr(self): # 词法分析器的代码段(parsing)
# 当前的token设置成输入的第一个token
self.current_token = self.get_next_token()
self.term() #token被term方法判断是否符号支持的表达式
while self.current_token.type in (PLUS, MINUS): # 在第一个token经过term处理后开始处理符号
token = self.current_token
if token.type == PLUS:
self.eat(PLUS) # 匹配操作符
self.term() # 匹配右值
elif token.type == MINUS:
self.eat(MINUS) # 匹配操作符
self.term() # 匹配右值
以上展现的词法分析器在分析后还没有解释运行,所以修改代码增加一部分代码去调用词法分析器完成结果的计算
def term(self):
"""Return an INTEGER token value"""
token = self.current_token
self.eat(INTEGER)
return token.value
def expr(self):
"""Parser / Interpreter 词法分析器的代码,包括了解释运行 """
# set current token to the first token taken from the input
self.current_token = self.get_next_token()
result = self.term()
while self.current_token.type in (PLUS, MINUS):
token = self.current_token
if token.type == PLUS:
self.eat(PLUS)
result = result + self.term()
elif token.type == MINUS:
self.eat(MINUS)
result = result - self.term()
return result
新版解释器的完整代码如下,通过该代码了解lexer、parsing、tokens等概念.
calc5.py代码如下
'''第三篇中作者给出的代码,用于完成整数的计算,支持长式子'''
INTEGER, PLUS, MINUS, EOF = 'INTEGER', 'PLUS', 'MINUS', 'EOF'
class Token(object):
def __init__(self, type, value):
self.type = type
self.value = value
def __str__(self):
return 'Token({type},{value})'.format(
type=self.type,
value=repr(self.value)
)
def __repr__(self):
return self.__str__()
class Interpreter(object):
def __init__(self, text):
self.text = text
self.pos = 0
self.current_token = None
self.current_char = self.text[self.pos]
##############################################
# 词法分析器部分代码,完成token识别 #
# ############################################
def error(self):
raise Exception('Invalid syntax')
def advance(self):
self.pos += 1
if self.pos > len(self.text) - 1:
self.current_char = None
else:
self.current_char = self.text[self.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:
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, '-')
self.error()
return Token(EOF, None)
############################################
# 语法分析(parsing)和解释运行的代码 #
############################################
def eat(self, token_type):
if self.current_token.type == token_type:
self.current_token = self.get_next_token()
else:
self.error()
def term(self):
token = self.current_token
self.eat(INTEGER)
return token.value
def expr(self):
self.current_token = self.get_next_token()
result = self.term()
while self.current_token.type in (PLUS, MINUS):
token = self.current_token
if token.type == PLUS:
self.eat(PLUS)
result += self.term()
elif token.type == MINUS:
self.eat(MINUS)
result -= self.term()
return result
def main():
while True:
try:
text = input('calc>')
except EOFError:
break
if not text:
continue
interpreter = Interpreter(text)
result = interpreter.expr()
print(result)
if __name__ == '__main__':
main()
3.练习
关于实现乘除和加减法的解释器我们已经在calc.4.py中实现过了,这里不再赘述。语法图把本文中那张图中的加减号换成乘除号就好了。