我们将分步实现一个简化版的Python解释器,这个解释器将支持:

- 基本的算术运算(, , , )
- 变量赋值(如
x = 10) if条件语句while循环print函数
为了简化,我们不会实现函数定义、类、异常处理等复杂特性。
核心思想
我们的解释器将遵循一个基本的工作流程,这被称为读取-求值-打印循环:
- 读取:获取用户输入的一行或多行代码(字符串)。
- 解析:将代码字符串转换成一种更结构化的内部表示,通常是抽象语法树,对于我们的简化版,我们可以直接使用Python的
ast(Abstract Syntax Trees)模块来完成这一步。 - 求值:遍历这个AST,并根据其节点类型执行相应的操作,这是解释器的核心。
- 打印:如果表达式有返回值,则将其打印出来。
第1步:环境 - 存储变量
我们需要一个地方来存储变量名和它们的值,一个简单的字典就非常完美。
class Environment:
def __init__(self, parent=None):
# parent用于实现作用域,全局环境的parent为None
self.parent = parent
self.vars = {}
def get(self, name):
# 首先在当前环境查找
if name in self.vars:
return self.vars[name]
# 如果找不到,则去父环境查找
if self.parent:
return self.parent.get(name)
# 如果都找不到,抛出异常
raise NameError(f"name '{name}' is not defined")
def set(self, name, value):
# 在当前环境设置变量
self.vars[name] = value
def define(self, name, value):
# 用于在当前环境定义新变量(函数参数或全局变量)
self.vars[name] = value
第2步:解释器 - 求值器
这是我们的核心类,它将接收AST节点并递归地求值。

import ast
class Interpreter:
def __init__(self):
# 创建一个全局环境
self.global_env = Environment()
# 初始化一些内置函数
self.global_env.define("print", self.builtin_print)
def builtin_print(self, *args):
# 实现print函数
print(" ".join([str(arg) for arg in args]))
def eval(self, node, env=None):
if env is None:
env = self.global_env
# 根据节点类型分发到不同的处理方法
if isinstance(node, ast.Expression):
return self.eval(node.body, env)
elif isinstance(node, ast.Num): # 数字
return node.n
elif isinstance(node, ast.Str): # 字符串
return node.s
elif isinstance(node, ast.Name): # 变量名
return env.get(node.id)
elif isinstance(node, ast.BinOp): # 二元操作,如 a + b
left = self.eval(node.left, env)
right = self.eval(node.right, env)
op = node.op
if isinstance(op, ast.Add):
return left + right
elif isinstance(op, ast.Sub):
return left - right
elif isinstance(op, ast.Mult):
return left * right
elif isinstance(op, ast.Div):
return left / right
# ... 可以添加更多操作符
elif isinstance(node, ast.Assign): # 赋值,如 x = 10
value = self.eval(node.value, env)
for target in node.targets:
if isinstance(target, ast.Name):
env.set(target.id, value)
# 赋值语句本身没有返回值
return None
elif isinstance(node, ast.If): # if语句
test_val = self.eval(node.test, env)
if test_val:
for stmt in node.body:
self.eval(stmt, env)
else:
for stmt in node.orelse:
self.eval(stmt, env)
return None
elif isinstance(node, ast.While): # while循环
while self.eval(node.test, env):
for stmt in node.body:
self.eval(stmt, env)
return None
elif isinstance(node, ast.Call): # 函数调用,如 print(x)
func = self.eval(node.func, env)
args = [self.eval(arg, env) for arg in node.args]
return func(*args)
# ... 可以添加更多AST节点类型
else:
raise NotImplementedError(f"AST node type {type(node).__name__} not implemented")
def run(self, code):
try:
# 使用ast.parse将代码字符串解析成AST
# mode='single'允许执行单个语句或表达式
node = ast.parse(code, mode='single')
# 求值AST
result = self.eval(node)
# 如果结果不是None,则打印它
if result is not None:
print(result)
except SyntaxError as e:
print(f"Syntax Error: {e}")
except NameError as e:
print(f"Name Error: {e}")
except Exception as e:
print(f"Error: {e}")
第3步:主循环
我们创建一个REPL来让用户可以与我们的解释器交互。
def repl(interpreter):
print("Welcome to the Simple Python Interpreter!")
print("Type 'exit' or 'quit' to leave.")
while True:
try:
code = input(">>> ")
if code.lower() in ('exit', 'quit'):
break
if not code.strip():
continue
interpreter.run(code)
except KeyboardInterrupt:
print("\nExiting...")
break
except EOFError:
print("\nExiting...")
break
if __name__ == "__main__":
interpreter = Interpreter()
repl(interpreter)
完整代码
将以上所有部分组合在一起,就是我们的完整解释器。
import ast
# ==============================================================================
# 1. 环境
# ==============================================================================
class Environment:
def __init__(self, parent=None):
self.parent = parent
self.vars = {}
def get(self, name):
if name in self.vars:
return self.vars[name]
if self.parent:
return self.parent.get(name)
raise NameError(f"name '{name}' is not defined")
def set(self, name, value):
self.vars[name] = value
def define(self, name, value):
self.vars[name] = value
# ==============================================================================
# 2. 解释器
# ==============================================================================
class Interpreter:
def __init__(self):
self.global_env = Environment()
self.global_env.define("print", self.builtin_print)
def builtin_print(self, *args):
print(" ".join([str(arg) for arg in args]))
def eval(self, node, env=None):
if env is None:
env = self.global_env
if isinstance(node, ast.Expression):
return self.eval(node.body, env)
elif isinstance(node, ast.Num):
return node.n
elif isinstance(node, ast.Str):
return node.s
elif isinstance(node, ast.Name):
return env.get(node.id)
elif isinstance(node, ast.BinOp):
left = self.eval(node.left, env)
right = self.eval(node.right, env)
op = node.op
if isinstance(op, ast.Add):
return left + right
elif isinstance(op, ast.Sub):
return left - right
elif isinstance(op, ast.Mult):
return left * right
elif isinstance(op, ast.Div):
return left / right
elif isinstance(op, ast.Pow):
return left ** right
elif isinstance(node, ast.Assign):
value = self.eval(node.value, env)
for target in node.targets:
if isinstance(target, ast.Name):
env.set(target.id, value)
return None
elif isinstance(node, ast.If):
test_val = self.eval(node.test, env)
if test_val:
for stmt in node.body:
self.eval(stmt, env)
else:
for stmt in node.orelse:
self.eval(stmt, env)
return None
elif isinstance(node, ast.While):
while self.eval(node.test, env):
for stmt in node.body:
self.eval(stmt, env)
return None
elif isinstance(node, ast.Call):
func = self.eval(node.func, env)
args = [self.eval(arg, env) for arg in node.args]
return func(*args)
elif isinstance(node, ast.Compare): # 处理比较操作,如 a < b
left = self.eval(node.left, env)
for op, right_node in zip(node.ops, node.comparators):
right = self.eval(right_node, env)
if isinstance(op, ast.Lt):
if not left < right:
return False
elif isinstance(op, ast.LtE):
if not left <= right:
return False
elif isinstance(op, ast.Gt):
if not left > right:
return False
elif isinstance(op, ast.GtE):
if not left >= right:
return False
elif isinstance(op, ast.Eq):
if not left == right:
return False
# ... 其他比较操作
left = right # 为下一次比较准备
return True # 如果所有比较都成功
else:
raise NotImplementedError(f"AST node type {type(node).__name__} not implemented")
def run(self, code):
try:
node = ast.parse(code, mode='single')
result = self.eval(node)
if result is not None:
print(result)
except (SyntaxError, NameError, ZeroDivisionError) as e:
print(f"Error: {e}")
except Exception as e:
print(f"An unexpected error occurred: {e}")
# ==============================================================================
# 3. 主循环
# ==============================================================================
def repl(interpreter):
print("Welcome to the Simple Python Interpreter!")
print("Try typing: x = 10; y = 20; print(x + y)")
print("Type 'exit' or 'quit' to leave.")
while True:
try:
code = input(">>> ")
if code.lower() in ('exit', 'quit'):
break
if not code.strip():
continue
interpreter.run(code)
except KeyboardInterrupt:
print("\nExiting...")
break
except EOFError:
print("\nExiting...")
break
if __name__ == "__main__":
interpreter = Interpreter()
repl(interpreter)
如何运行和测试
- 将上面的代码保存为一个文件,
simple_interpreter.py。 - 在终端中运行它:
python simple_interpreter.py。 - 你会看到一个
>>>提示符,现在你可以输入你的简化Python代码了。
测试示例:
>>> x = 10
>>> y = 20
>>> x + y
30
>>> print(x * y)
200
>>> if x < y:
... print("x is less than y")
...
x is less than y
>>> z = 0
>>> while z < 5:
... print(z)
... z = z + 1
...
0
1
2
3
4
>>> exit
进一步的探索方向
这个简化版解释器只是一个起点,如果你想让它变得更强大,可以考虑以下方向:
- 支持更多数据类型:
bool(True,False)、list、dict,这需要为它们实现相应的AST节点处理逻辑。 - 函数定义和调用:这是最大的挑战之一,你需要处理
ast.FunctionDef和ast.Return节点,函数需要有自己的作用域(Environment),并且需要实现一个“闭包”机制,让函数能够访问其定义时的外部环境。 - 作用域和命名空间:我们的
Environment类已经有了parent指针,这为实现作用域打下了基础,你需要确保在函数内部、类内部等不同块中,变量查找是正确的。 - 错误处理:增加更细致的错误处理,比如
TypeError(类型错误)、ZeroDivisionError(除零错误)等。 - 实现自己的AST解析器:目前我们依赖Python内置的
ast模块,一个真正的项目需要自己实现一个词法分析器(将字符流变成“Token”流)和一个语法分析器(将Token流组合成AST),这会是一个巨大的工程,但也是理解编译原理的最好方式。 - 实现
for循环:处理ast.For节点。
通过构建这样一个解释器,你会对Python代码是如何被执行的有一个前所未有的深刻理解。
