2012-01-28 113 views
2

我正在使用Irony.net生成源代碼之外的解析樹。基本上,我使用ExpressionEvaluatorGrammer就像二進制表達式(算術,關係和邏輯/條件)的語法。我想通過遍歷它將生成的分析樹轉換爲Linq表達式。但是,樹似乎沒有可以直接轉換爲linq條件表達式的格式。這種表達的假設的例子:遍歷具有複雜條件表達式的ast來生成linq表達式

1 == 1 && 4 - 1 == 3 

產生(爲了簡潔僞XML樹):

<binary> 
    <binary> 
    <binary> 
     <literal>1</literal> 
     <op>==</op> 
     <literal>1</literal> 
    </binary> 
    <op>&&</op> 
    <binary> 
     <literal>4</literal> 
     <op>-</op> 
     <literal>1</literal> 
    </binary> 
    </binary> 
    <op>==</op> 
    <literal>3</literal> 
</binary> 

在上面的樹中,算術表達式(4 - 1)成爲合適的表情到& &隨着父節點關閉後的邏輯操作。在理想世界中,它應該是代表「== 3」的節點的左表達式。

你如何遍歷這樣的樹來生成一個合適的和操作?或者,有沒有辦法以我想要的形式生成樹?

編輯:這是語法(部分)的定義。我從Irony.interpreter附帶的ExpressionEvaluatorGrammer中提取了它。

RegisterOperators(15, "&", "&&", "|", "||"); 
RegisterOperators(20, "==", "<", "<=", ">", ">=", "!="); 
RegisterOperators(30, "+", "-"); 
RegisterOperators(40, "*", "/"); 
Expr.Rule = Term 
Term.Rule = number | ParExpr | stringLit | FunctionCall | identifier | MemberAccess | IndexedAccess; 
ParExpr.Rule = "(" + Expr + ")"; 
BinExpr.Rule = Expr + BinOp + Expr; 
BinOp.Rule = ToTerm("+") | "-" | "*" | "/" | "**" | "==" | "<" | "<=" | ">" | ">=" | "!=" | "&&" | "||" | "&" | "|"; 
+1

我不知道Irony.Net但它生成的xml對應於((1 == 1)&&(4 * 1))== 3。無論是&&和==具有相同的優先級,而*具有更高的優先級或它是一個錯誤。您可能會嘗試在解析之前添加paranthesis,或使用其他工具。如果實際的語法不復雜得多,手動編寫解析器(直接生成表達式)應該不會很困難。 – 2012-01-28 16:16:33

+0

你對'RegisterOperators'的看法是什麼樣子?你如何設置關聯性? – user7116 2012-01-28 16:35:25

+0

@sixlettervariables請參閱具有優先級的語法 – 2012-01-28 16:50:32

回答

0

假設運算符優先級是正確的,你應該走的樹遞歸使用訪問者模式,在每個級別返回一個Expression

XName xBinary = "binary"; 
XName xLiteral = "literal"; 
Expression Visit(XElement elt) 
{ 
    if (elt.Name == xBinary) 
    { 
     return VisitBinary(elt); 
    } 
    else if (elt.Name == xLiteral) 
    { 
     return VisitLiteral(elt); 
    } // ... 

    throw new NotSupportedException(); 
} 

現在,你有Visit結構,你簡單地寫每個特定的訪問者使用你的主Visit

Expression VisitLiteral(XElement elt) 
{ 
    Debug.Assert(elt.Name == xLiteral); 
    return Expression.Constant((int)elt); 
} 

Expression VisitBinary(XElement elt) 
{ 
    Debug.Assert(elt.Name == xBinary); 
    Debug.Assert(elt.Elements().Count() >= 3); 

    var lhs = elt.Elements().ElementAt(0); 
    var op = elt.Elements().ElementAt(1); 
    var rhs = elt.Elements().ElementAt(2); 

    switch((string)op) 
    { 
    case "+": 
     // by chaining LHS and RHS to Visit we allow the tree to be constructed 
     // properly as Visit performs the per-element dispatch 
     return Expression.Add(Visit(lhs), Visit(rhs)); 
    case "&&": 
     return Expression.AndAlso(Visit(lhs), Visit(rhs)); 
    default: 
     throw new NotSupportedException(); 
    } 
} 
+0

問題是,由Irony生成的xml「樹」。網絡不正確。 – 2012-01-28 16:24:31

+0

@Ali:剛纔注意到,聽起來像是一個優先問題。一旦優先順序被解決,OP可以使用訪問者模式。 – user7116 2012-01-28 16:31:48

+0

升級解決了這個問題。謝謝! – 2012-02-09 11:23:19

1

你不能通過神奇/特殊的方式遍歷樹來解決這個問題。你的解析器不正確!可能它只是配置錯誤。您絕對需要從中獲取正確的樹,以便進一步處理它。

也許您在其中有錯誤的運算符優先規則。至少它看起來像。嘗試添加括號以查看它是否修復了樹。