2012-01-28 115 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

你不能通过神奇/特殊的方式遍历树来解决这个问题。你的解析器不正确!可能它只是配置错误。您绝对需要从中获取正确的树,以便进一步处理它。

也许您在其中有错误的运算符优先规则。至少它看起来像。尝试添加括号以查看它是否修复了树。