2016-08-04 34 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最終都會結束是一個數字 –