2

ソースから解析ツリーを生成するために Irony.net を使用しています。基本的に、バイナリ式 (算術式、関係式、および論理/条件式) のグラマーのような ExpressionEvaluatorGrammer を使用しています。結果の解析ツリーをトラバースして Linq 式に変換したい。ただし、ツリーには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("+") | "-" | "*" | "/" | "**" | "==" | "<" | "<=" | ">" | ">=" | "!=" | "&&" | "||" | "&" | "|";
4

2 に答える 2

1

魔法の/特別な方法でツリーをトラバースしても、これを修正することはできません。あなたのパーサーは正しくありません! おそらく、設定が間違っているだけです。さらに処理するには、そこから正しいツリーを取得する必要があります。

おそらく、演算子の優先順位規則が間違っています。少なくともそのように見えます。括弧を追加して、ツリーが修正されるかどうかを確認してください。

于 2012-01-28T16:25:26.503 に答える
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特定の各訪問者を main を使用するように記述するだけです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();
    }
}
于 2012-01-28T16:02:54.660 に答える