为二进制表达式创建AST

时间:2013-10-22 12:02:22

标签: python parsing context-free-grammar abstract-syntax-tree ply

我继承了一个ANTLR语法,现在用Python Lex Yacc实现它而不做任何改动。我的问题是,ANTLR通常使用非常高级别的EBNF来定义语法,而Yacc使用简单的上下文无关语法。

我对二进制表达式的AST定义感到困惑。根据ANTLR,他们看起来像

disjunction
: conjunction ('||' conjunction)*

此定义存在优先原因,不要怀疑名称。

在我的CFG中,它看起来像

def p_sum(self, p):
""" sum : product product_list """
???

def p_product_list(self, p):
""" product_list : PLUS product product_list
| MINUS product product_list
| epsilon
"""
???

其他一些表达式看起来像

def p_disjunction_1(self, p):
""" disjunction : conjunction """
    p[0] = p[1]

def p_disjunction_2(self, p):
""" disjunction : conjunction OR disjunction """
    p[0] = BinaryOp(p[2], p[1], p[3], p[1].coord)

我想要的是我的AST仅由BinaryExpression节点组成,如第二个例子中所示:

BinaryExpression('+',lhs,rhs)

但是这个语法给了我一系列因素。有什么方法可以按我的方式写出来吗? ???是我需要的地方,但是建立我的AST的表达,但我想不出一个很好的方法来做到这一点。我看到的是定义一个带有一元表达式列表的节点,但这对我来说很难看。或者还有另一种写语法的方法吗?我不敢触摸它,因为我担心我会以解析不同东西的方式改变它。

1 个答案:

答案 0 :(得分:1)

disjunction产生的“原始”形式(在它左移之前被删除以使其适合LL解析)是

disjunction: conjunction
           | disjunction '|' conjunction
           ;

那将是左联合离解;如果你想要权利关联 - 例如对于赋值运算符 - 使用右递归:

assignment: expression
          | expression '=' assignment
          ;

(这可能不是你想要的赋值运算符的左侧,但它显示了右关联规则的一般模式。)

类似地:

sum: product
   | sum '+' product
   | sum '-' product
   ;

对应于合理解析树的语法重建应该是相当机械的,但是您可能应该编写足够的测试用例,用两种语法解析它们,以确保自己正确解析它。