You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 16:24:09