lambda表达式的解析(四) 运算符表达式

一元、二元、三元运算符的转换大多都非常有规律,先看这个一元树:

主要就是一个运算符跟一个表达式,转换起来很简单:

        private Expression ProcessUnaryExpression(ParseTreeNode expNode)
        {
            string op;
            var first = expNode.FirstChild;
            var second = expNode.LastChild;
            switch (first.GetName())
            {
                case "unary_operator":
                    op = first.FirstChild.GetValue();
                    break;
                case "pre_incr_decr_expression":
                    op = first.GetChild("incr_or_decr").FirstChild.GetValue();
                    second = first.LastChild;
                    break;
                case "post_incr_decr_expression":
                    op = "post" + first.GetChild("incr_or_decr").FirstChild.GetValue();
                    second = first.FirstChild;
                    break;
                default:
                    return ProcessExpression(expNode.FirstChild);
            }
            return Expression.MakeUnary(unaryOps[op], ProcessExpression(second), null);
        }


运算符表:

            #region UnaryOps
            unaryOps["++"] = ExpressionType.PreIncrementAssign;
            unaryOps["--"] = ExpressionType.PreDecrementAssign;
            unaryOps["post++"] = ExpressionType.PostIncrementAssign;
            unaryOps["post--"] = ExpressionType.PostDecrementAssign;
            unaryOps["!"] = ExpressionType.Not;
            unaryOps["~"] = ExpressionType.Not;
            unaryOps["+"] = ExpressionType.Quote;
            unaryOps["-"] = ExpressionType.Negate;
            //ops["as"] = ExpressionType.TypeAs;
            #endregion

如前一篇提到的,要注意的有2点,第一是++,--的节点是独立出来的需要特殊处理,第二就是as在C#里虽然是一元的但我们的grammar视其为二元所以不在这里处理。

还有就是MakeUnary的第三个参数是表达式返回类型,从优化角度考虑这个参数在某些情况下可以直接代替ConvertExpression,从而节省一个节点,目前不考虑优化情况下忽略了这个参数。

二元和三元处理方式都类似,二元的树:

这个图里面也包括了++,--这个特别节点的显示方式,可以清晰的看出前面一元处理方法是怎么处理的。

二元处理方法:

        private Expression ProcessBinaryExpression(ParseTreeNode expNode)
        {
            var left = expNode.ChildNodes[0];
            var right = expNode.ChildNodes[2];
            var op = expNode.ChildNodes[1].FirstChild.GetValue();
            if (op == "as")
            {
                var typeName = right.GetDescendant("Identifier").GetValue();
                return Expression.TypeAs(ProcessExpression(left), GetType(typeName));
            }
            return Expression.MakeBinary(binaryOps[op], ProcessExpression(left), ProcessExpression(right));
        }


二元运算符表:

            #region BinaryOps
            binaryOps["+"] = ExpressionType.Add;
            binaryOps["-"] = ExpressionType.Subtract;
            binaryOps["*"] = ExpressionType.Multiply;
            binaryOps["/"] = ExpressionType.Divide;
            binaryOps["%"] = ExpressionType.Modulo;
            binaryOps["&"] = ExpressionType.And;
            binaryOps["|"] = ExpressionType.Or;
            binaryOps["^"] = ExpressionType.ExclusiveOr;
            binaryOps["??"] = ExpressionType.Coalesce;
            binaryOps["<<"] = ExpressionType.LeftShift;
            binaryOps[">>"] = ExpressionType.RightShift;
            binaryOps["+="] = ExpressionType.AddAssign;
            binaryOps["-="] = ExpressionType.SubtractAssign;
            binaryOps["*="] = ExpressionType.MultiplyAssign;
            binaryOps["/="] = ExpressionType.DivideAssign;
            binaryOps["%="] = ExpressionType.ModuloAssign;
            binaryOps["&="] = ExpressionType.AndAssign;
            binaryOps["|="] = ExpressionType.OrAssign;
            binaryOps["^="] = ExpressionType.ExclusiveOrAssign;
            binaryOps["<<="] = ExpressionType.LeftShiftAssign;
            binaryOps[">>="] = ExpressionType.RightShiftAssign;
            binaryOps["=="] = ExpressionType.Equal;
            binaryOps["!="] = ExpressionType.NotEqual;
            binaryOps["&&"] = ExpressionType.AndAlso;
            binaryOps["||"] = ExpressionType.OrElse;
            binaryOps["is"] = ExpressionType.TypeIs;
            binaryOps["="] = ExpressionType.Equal;
            #endregion


和前面提到的一样,二元处理方法里特别照顾了as操作。

三元条件表达式的图:

处理方法:

        private Expression ProcessConditionalExpression(ParseTreeNode expNode)
        {
            return Expression.Condition(
                ProcessExpression(expNode.FirstChild),
                ProcessExpression(expNode.ChildNodes[2]),
                ProcessExpression(expNode.ChildNodes[3]));
        }


运算符表达式的解析处理都很类似,简单明了的很,所以这里就不再进一步赘述了。

展开阅读全文

没有更多推荐了,返回首页