bst.unparse输出无括号缩进错误,ply.yacc构建AST相关问题求解
问题根因
- 语法规则未区分运算符优先级与结合性:你当前将加减乘除幂五种运算全部定义在同一层级的
term产生式中,且没有通过precedence声明优先级,Ply解析表达式时不会按照数学运算优先级生成嵌套AST节点,所有运算节点都处于平级结构,反解析时自然无法判断哪里需要加括号。 - AST构造函数存在变量名笔误:你定义的
binary_operation函数参数为operator、operand1,但内部写的是op=operator1、left=operand,变量名完全不匹配,会导致AST节点属性赋值错误。 - 嵌套节点错误使用
ast.Expr包装:ast.Expr是表达式语句的顶级包装节点,仅用于表示独立成句的表达式,嵌套的二元运算子节点直接返回ast.BinOp即可。你给所有子运算都套了ast.Expr,会让反解析工具将每个子运算识别为独立语句,最终出现缩进异常、多余换行的问题。
修复方案
- 补充Ply的优先级声明,拆分语法产生式层级:
首先在yacc代码开头声明优先级:
precedence = ( ('left', 'ADD', 'SUB'), ('left', 'MULTI', 'DIV'), ('right', 'POW'), )
拆分产生式区分运算层级:
def p_expression_add_sub(p): '''expression : expression ADD term | expression SUB term''' operator = ast_tree.Binary_operator(p[2]) p[0] = ast_tree.binary_operation(operator, p[1], p[3]) def p_term_mul_div(p): '''term : term MULTI factor | term DIV factor''' operator = ast_tree.Binary_operator(p[2]) p[0] = ast_tree.binary_operation(operator, p[1], p[3]) def p_factor_pow(p): '''factor : factor POW primary''' operator = ast_tree.Binary_operator(p[2]) p[0] = ast_tree.binary_operation(operator, p[1], p[3]) # 补充primary产生式对应数字、括号包裹的表达式等基础节点 def p_factor_primary(p): '''factor : primary''' p[0] = p[1] def p_primary_paren(p): '''primary : LPAREN expression RPAREN''' p[0] = p[2]
- 修复AST构造函数逻辑,移除不必要的
ast.Expr包装:
# 嵌套运算直接返回BinOp节点 def binary_operation(operator, operand1, operand2): return ast.BinOp(op=operator, left=operand1, right=operand2) # 仅在需要生成顶级表达式语句时,在外层单独套ast.Expr def wrap_expr_statement(expr_node): return ast.Expr(value=expr_node)
- 反解析前可以先调用
ast.fix_missing_locations(your_ast_root)补全AST节点的位置信息,避免反解析工具因为缺失位置属性出现格式错误。
内容的提问来源于stack exchange,提问作者beton
相关产品推荐
相关产品推荐

