如何将Python函数调用转为类Lisp风格表达式实现迷你编程语言
实现类Lisp风格的函数调用解析与求值
核心需求是将带/不带逗号的类Lisp括号表达式,转换为可执行的函数调用,本质是实现一个极简的表达式解析器+求值器,分三步完成:
1. 预处理:统一表达式格式
先消除两种写法的差异,把所有逗号替换为空格,同时清理多余空格,确保括号与元素的分隔清晰:
def preprocess(expr): # 去掉所有逗号,替换为空格 expr = expr.replace(',', ' ') # 合并多余空格,保证格式统一 expr = ' '.join(expr.split()) return expr
2. 解析表达式为抽象语法树(AST)
将预处理后的字符串拆分为token(括号、函数名、数字),再递归解析成嵌套列表结构——这就是后续可直接求值的AST。比如(say (div (mul 5 (power 9 5)) 3))会被解析为:['say', ['div', ['mul', 5, ['power', 9, 5]], 3]]
实现代码:
def tokenize(expr): # 给括号添加空格,方便拆分出独立token expr = expr.replace('(', ' ( ').replace(')', ' ) ') return [t for t in expr.split() if t] def parse(tokens): if not tokens: raise SyntaxError("Unexpected end of expression") token = tokens.pop(0) if token == '(': ast = [] while tokens[0] != ')': ast.append(parse(tokens)) tokens.pop(0) # 移除闭合括号 return ast elif token == ')': raise SyntaxError("Unexpected closing parenthesis") else: # 尝试转换为数字,失败则保留为字符串(函数名) try: return int(token) except ValueError: try: return float(token) except ValueError: return token
3. 求值AST,调用对应函数
先定义你的基础函数,再创建函数名与实际函数的映射字典,最后递归遍历AST:遇到列表就取第一个元素作为函数名,递归求值所有参数后调用函数;遇到数字直接返回。
# 定义基础函数 def add(a, b): return a + b def mul(a, b): return a * b def power(a, b): return a ** b def div(a, b): if b == 0: raise ZeroDivisionError("Division by zero") return a / b def say(value): print(value) return value # 函数映射:字符串函数名对应到实际Python函数 function_map = { 'add': add, 'mul': mul, 'power': power, 'div': div, 'say': say } def eval_ast(ast): if isinstance(ast, list): func_name = ast[0] if func_name not in function_map: raise NameError(f"Undefined function: {func_name}") func = function_map[func_name] # 递归求值所有参数 args = [eval_ast(arg) for arg in ast[1:]] return func(*args) else: # 数字直接返回 return ast
完整使用示例
将各模块结合,即可处理两种风格的类Lisp表达式:
# 测试带逗号的表达式 expr1 = "(say, (div, (mul, 5, (power, 9, 5)), 3))" # 测试不带逗号的表达式 expr2 = "(say (div (mul 5 (power 9 5)) 3))" for expr in [expr1, expr2]: processed = preprocess(expr) tokens = tokenize(processed) ast = parse(tokens) result = eval_ast(ast) print(f"输入表达式: {expr}") print(f"求值结果: {result}\n")
运行输出:
输入表达式: (say, (div, (mul, 5, (power, 9, 5)), 3)) 59049.0 求值结果: 19683.0 输入表达式: (say (div (mul 5 (power 9 5)) 3)) 59049.0 求值结果: 19683.0
补充说明
- 新增函数只需在
function_map中添加对应的键值对即可; - 当前实现支持任意层级的嵌套表达式,完全覆盖你的需求;
- 可扩展支持变量、条件表达式等更多语法,当前版本已满足核心功能。
内容的提问来源于stack exchange,提问作者Adras Baros
相关产品推荐
相关产品推荐

