目录
Python实例题
题目
Python实现Python解释器
实现思路
- 词法分析:将输入的 Python 代码分割成一个个的词法单元(Token),例如数字、运算符、变量名等。
- 语法分析:根据词法单元构建抽象语法树(AST),表示代码的语法结构。
- 语义分析与执行:遍历抽象语法树,根据节点的类型执行相应的操作,例如计算算术表达式、进行变量赋值等。
代码实现
# 定义词法单元类型
TOKEN_NUMBER = 'NUMBER'
TOKEN_PLUS = 'PLUS'
TOKEN_MINUS = 'MINUS'
TOKEN_MULTIPLY = 'MULTIPLY'
TOKEN_DIVIDE = 'DIVIDE'
TOKEN_ASSIGN = 'ASSIGN'
TOKEN_VARIABLE = 'VARIABLE'
TOKEN_EOF = 'EOF'
# 词法分析器
class Lexer:
def __init__(self, text):
self.text = text
self.pos = 0
self.current_char = self.text[self.pos] if self.pos < len(self.text) else None
def error(self):
raise Exception('Invalid character')
def advance(self):
self.pos += 1
if self.pos < len(self.text):
self.current_char = self.text[self.pos]
else:
self.current_char = None
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(TOKEN_NUMBER, self.integer())
if self.current_char == '+':
self.advance()
return Token(TOKEN_PLUS, '+')
if self.current_char == '-':
self.advance()
return Token(TOKEN_MINUS, '-')
if self.current_char == '*':
self.advance()
return Token(TOKEN_MULTIPLY, '*')
if self.current_char == '/':
self.advance()
return Token(TOKEN_DIVIDE, '/')
if self.current_char == '=':
self.advance()
return Token(TOKEN_ASSIGN, '=')
if self.current_char.isalpha():
var_name = ''
while self.current_char is not None and (self.current_char.isalnum() or self.current_char == '_'):
var_name += self.current_char
self.advance()
return Token(TOKEN_VARIABLE, var_name)
self.error()
return Token(TOKEN_EOF, None)
# 词法单元类
class Token:
def __init__(self, type, value):
self.type = type
self.value = value
def __str__(self):
return f'Token({self.type}, {repr(self.value)})'
# 抽象语法树节点类
class AST:
pass
class BinOp(AST):
def __init__(self, left, op, right):
self.left = left
self.op = op
self.right = right
class Num(AST):
def __init__(self, token):
self.token = token
self.value = token.value
class Assign(AST):
def __init__(self, left, op, right):
self.left = left
self.token = self.op = op
self.right = right
class Var(AST):
def __init__(self, token):
self.token = token
self.value = token.value
# 语法分析器
class Parser:
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):
if self.current_token.type == token_type:
self.current_token = self.lexer.get_next_token()
else:
self.error()
def factor(self):
token = self.current_token
if token.type == TOKEN_NUMBER:
self.eat(TOKEN_NUMBER)
return Num(token)
elif token.type == TOKEN_VARIABLE:
self.eat(TOKEN_VARIABLE)
return Var(token)
elif token.type == TOKEN_PLUS:
self.eat(TOKEN_PLUS)
return BinOp(Num(Token(TOKEN_NUMBER, 0)), Token(TOKEN_PLUS, '+'), self.factor())
elif token.type == TOKEN_MINUS:
self.eat(TOKEN_MINUS)
return BinOp(Num(Token(TOKEN_NUMBER, 0)), Token(TOKEN_MINUS, '-'), self.factor())
def term(self):
node = self.factor()
while self.current_token.type in (TOKEN_MULTIPLY, TOKEN_DIVIDE):
token = self.current_token
if token.type == TOKEN_MULTIPLY:
self.eat(TOKEN_MULTIPLY)
elif token.type == TOKEN_DIVIDE:
self.eat(TOKEN_DIVIDE)
node = BinOp(left=node, op=token, right=self.factor())
return node
def expr(self):
node = self.term()
while self.current_token.type in (TOKEN_PLUS, TOKEN_MINUS):
token = self.current_token
if token.type == TOKEN_PLUS:
self.eat(TOKEN_PLUS)
elif token.type == TOKEN_MINUS:
self.eat(TOKEN_MINUS)
node = BinOp(left=node, op=token, right=self.term())
return node
def assignment_statement(self):
left = Var(self.current_token)
self.eat(TOKEN_VARIABLE)
token = self.current_token
self.eat(TOKEN_ASSIGN)
right = self.expr()
node = Assign(left, token, right)
return node
def statement(self):
if self.current_token.type == TOKEN_VARIABLE:
return self.assignment_statement()
else:
return self.expr()
def parse(self):
return self.statement()
# 解释器
class Interpreter:
def __init__(self, parser):
self.parser = parser
self.GLOBAL_SCOPE = {}
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(f'No visit_{type(node).__name__} method')
def visit_BinOp(self, node):
if node.op.type == TOKEN_PLUS:
return self.visit(node.left) + self.visit(node.right)
elif node.op.type == TOKEN_MINUS:
return self.visit(node.left) - self.visit(node.right)
elif node.op.type == TOKEN_MULTIPLY:
return self.visit(node.left) * self.visit(node.right)
elif node.op.type == TOKEN_DIVIDE:
return self.visit(node.left) / self.visit(node.right)
def visit_Num(self, node):
return node.value
def visit_Assign(self, node):
var_name = node.left.value
var_value = self.visit(node.right)
self.GLOBAL_SCOPE[var_name] = var_value
return var_value
def visit_Var(self, node):
var_name = node.value
val = self.GLOBAL_SCOPE.get(var_name)
if val is None:
raise Exception(f'Variable {var_name} is not defined')
else:
return val
def interpret(self):
tree = self.parser.parse()
if tree is None:
return ''
return self.visit(tree)
# 主函数
def main():
while True:
try:
text = input('>> ')
except EOFError:
break
if not text:
continue
lexer = Lexer(text)
parser = Parser(lexer)
interpreter = Interpreter(parser)
result = interpreter.interpret()
print(result)
if __name__ == "__main__":
main()
代码解释
-
词法分析器(Lexer):
Lexer
类将输入的代码字符串分割成一个个的词法单元(Token),根据字符的类型识别出数字、运算符、变量名等。get_next_token
方法根据当前字符的类型返回对应的词法单元。
-
词法单元类(Token):
Token
类表示一个词法单元,包含类型和值两个属性。
-
抽象语法树节点类(AST):
AST
是抽象语法树节点的基类,BinOp
表示二元运算符节点,Num
表示数字节点,Assign
表示赋值语句节点,Var
表示变量节点。
-
语法分析器(Parser):
Parser
类根据词法单元构建抽象语法树,通过递归下降的方法解析代码,处理表达式、赋值语句等。parse
方法返回构建好的抽象语法树。
-
解释器(Interpreter):
Interpreter
类遍历抽象语法树,根据节点的类型执行相应的操作,例如计算算术表达式、进行变量赋值等。visit
方法根据节点类型调用相应的处理方法。
-
主函数(main):
- 循环读取用户输入的代码,调用词法分析器、语法分析器和解释器进行处理,并输出结果。
运行思路
- 保存代码:将上述代码保存为
simple_python_interpreter.py
文件。 - 运行脚本:在终端中运行
python simple_python_interpreter.py
。 - 输入代码:在命令行输入简单的算术表达式或赋值语句,例如
a = 3 + 5
、a + 2
等,解释器会输出计算结果。
注意事项
- 功能局限性:这个解释器仅支持基本的算术表达式和赋值语句,不支持 Python 语言的其他复杂特性,如函数定义、类定义、控制流语句等。
- 错误处理:代码中对一些错误情况进行了简单的处理,但在实际应用中,可能需要更完善的错误处理机制,以提供更友好的错误提示。
- 扩展性:可以通过扩展抽象语法树节点和解释器的处理方法,逐步添加对更多 Python 特性的支持。