2016-08-04 86 views
1

考虑以下语法:如何创建考虑'|'的抽象语法树? (帘布层/ Yacc的)

expr : expr '+' term | expr '-' term | term 
term : term '*' factor | term '/' factor | factor 
factor : '(' expr ')' | identifier | number 

这是我的代码使用厚度:

from ply import lex, yacc 

tokens = [ 
    "identifier", 
    "number", 
    "plus", 
    "minus", 
    "mult", 
    "div" 
] 

t_ignore = r" \t" 
t_identifier = r"^[a-zA-Z]+$" 
t_number = r"[+-]?(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?" 
t_plus = r"\+" 
t_minus = r"-" 
t_mult = r"\*" 
t_div = r"/" 

def p_stmt(p): 
    """stmt : expr""" 
    p[0] = ("stmt", p[1]) 

def p_expr(p): 
    """expr : expr plus term 
      | expr minus term 
      | term""" 
    p[0] = ("expr", p[1], p[2]) # Problem here <<< 

def p_term(p): 
    """term : term mult factor 
      | term div factor 
      | factor""" 

def p_factor(p): 
    """factor : '(' expr ')' 
       | identifier 
       | number""" 


if __name__ == "__main__": 
    lex.lex() 
    yacc.yacc() 
    data = "32 + 10" 
    result = yacc.parse(data) 
    print(result) 

我怎么建立一个AST与表达,如果我不能访问运营商?我可以分开像p_expr_plus这样的函数,但是在这种情况下,我会消除运算符优先级。 docs不是很有帮助,因为我是初学者,不能解决这个问题。我在is this这个主题上找到了最好的素材,但它没有考虑运算符优先级的复杂性。

编辑:我不能访问p 2或p [3],因为我得到一个IndexError(它只与术语匹配)。在我已经链接的PDF中,他们明确地将操作符放在元组中,如:('+',p 1,p 2),因此,考虑到优先级,显示我的问题(我不能分开函数,表达式是表达式,应该有一种方法来考虑管道和访问任何运营商)。

+0

我不明白为什么你觉得你“不能分开的功能”,因为优先。优先顺序没有问题。你真的不使用优先权;语法是明确的,操作符优先级是语法中固有的。在两个不同的动作函数之间划分非终结符不会改变语法,并产生更简单的动作。 – rici

回答

1

据我所见,在p[0] = ("expr", p[1], p[2]),p 1将是左手表达式,p [2]将是运算符,并且p [3](您没有使用)将是右手术语。

只需使用p [2]来确定操作符,然后添加p [3],因为您需要它,并且您应该很好。

此外,您必须验证p有多少项,因为如果最后一条规则| term"""匹配,p将只有两个项目而不是四个。

看看一个片段从GardenSnake example:

def p_comparison(p): 
    """comparison : comparison PLUS comparison 
        | comparison MINUS comparison 
        | comparison MULT comparison 
        | comparison DIV comparison 
        | comparison LT comparison 
        | comparison EQ comparison 
        | comparison GT comparison 
        | PLUS comparison 
        | MINUS comparison 
        | power""" 
    if len(p) == 4: 
     p[0] = binary_ops[p[2]]((p[1], p[3])) 
    elif len(p) == 3: 
     p[0] = unary_ops[p[1]](p[2]) 
    else: 
     p[0] = p[1] 
+0

问题是,当我使用p [3]时,我得到一个超出范围的列表索引。运营商不考虑。在我已经链接的PDF中,他们显式地“保存”操作符:('+',p [1],p [2])。问题在于它可能是任何运营商,我需要考虑优先级。 –

+0

哦,对。它必须是因为最后一行,'|当这个最后的规则匹配时,'p'只会有两个项目,而不是四个。 –

+0

这很奇怪,因为“32 + 10”应该匹配“expr plus term”,因为expr和term最终都会结束是一个数字 –