乐趣区

SharpC-A-C-Interpreter-In-C-0111

表达式,最简单也最困难。各种算术、逻辑、赋值埋同函数调用,想想都头大如斗转星移山填海枯石烂。
废话有云,根据 Yacc 规则,表达式由操作数及操作符构成。操作数有立即数、变量、函数调用及另一个表达式。操作符有一元、二元及三元操作符。惜乎 SharpC 不支持三元表达式。
有两类特殊的操作数:指针及指针指示(Pointer indiction 应该怎么翻译?)。
有一个特殊的操作符:sizeof。说其特殊是因为偶将其归类于一元操作符,且不像其它操作符般需要操作数,sizeof 也可以类型名称作为操作数。
先看看操作符优先级定义:

public enum OperatorPriority
{
    // 赋值操作最低
    Assign,
    Logic,
    Bitwise,
    // 算术运算有两级优先级:+,—是一级,*,/,% 是高一级
    ArthmeticLow,
    ArthmeticHigh,
    // 拔高了移位操作符优先级于算术之上
    Shift,
    Address,
    Unary,
    Parenthese
}

先看看表达式求值过程:

public Operand.Operand Evaluate(Context ctx)
{if (Token is Operand.Operand)
    {if (Token is Operand.ValueOfFunctionCalling)
        {
            Operand.ValueOfFunctionCalling valOfFuncCalling = Token as Operand.ValueOfFunctionCalling;

            return valOfFuncCalling.GetValue(ctx);
        }
        else
            return Token as Operand.Operand;
    }
    else
    {List<Operand.Operand> operands = new List<Operand.Operand>();

        if (LeftNode != null)
            operands.Add(LeftNode.Evaluate(ctx));

        if (RightNode != null)
            operands.Add(RightNode.Evaluate(ctx));

        Operand.Operand res = (Token as Operator.Operator).Evaluate(ctx, operands);

        Debug.WriteLine(string.Format("\tExp: [{0} {1} {2}] Result: [{3}]", 
            operands.First().ToString(),
            Token.ToString(),
            operands.Count > 1 ? operands.Last().ToString() : "", 
            res.ToString()));

        return res;
    }
}

表达式求值过程:

  1. 如果是操作数,则将之作为结果返回。
  2. 如果是操作符,先后对左、右节点求值,再将左、右节点求值的结果作为操作数,调用操作符的求值方法,并将其结果返回。

操作符最终的计算还是基于两种类型:int 和 float。



因为没有严格区分 signed 和 unsigned,涉及到两种计算的求值过程可能会有错误。

因此有以下两个方法:

public class BinaryOperator : Operator
{public BinaryOperator(OperatorPriority prio)
        : base(prio)
    { }

    public Operand.Operand LeftOperand;
    public Operand.Operand RightOperand;

    public virtual int ComputeScalar(int left, int right)
    {throw new NotImplementedException();
    }

    public virtual float ComputeFloat(float left, float right)
    {throw new NotImplementedException();
    }

一元操作符还多了一个 Compute 方法:

public class UnaryOperator : Operator
{public UnaryOperator()
        : base(Operator.OperatorPriority.Unary)
    { }

    public virtual int ComputeScalar(int val)
    {throw new NotImplementedException();
    }

    public virtual float ComputeFloat(float val)
    {throw new NotImplementedException();
    }

    public virtual Operand.Value Compute(Context ctx, Operand.Operand operand)
    {

二元操作符的运算比较复杂,需要考虑种种情况:

public override Operand.Operand Evaluate(Context ctx, List<Operand.Operand> operands)
{Debug.Assert(operands.Count() == 2);

    LeftOperand = operands.First();
    RightOperand = operands.Last();

    DataTypeInfo leftDti = LeftOperand.GetTypeInfo(ctx);
    DataTypeInfo rightDti = RightOperand.GetTypeInfo(ctx);

    if (leftDti.IsPointer ||  rightDti.IsPointer)
    {int leftAddr = leftDti.IsPointer ? Context.Memory.GetInt(LeftOperand.GetValue(ctx).AsInt) : LeftOperand.GetValue(ctx).AsInt;
        int rightAddr = rightDti.IsPointer ? Context.Memory.GetInt(RightOperand.GetValue(ctx).AsInt) : RightOperand.GetValue(ctx).AsInt;

        Operand.ValueOfPointer valOfPointer = new Operand.ValueOfPointer() {Address = ComputeScalar(leftAddr, rightAddr)
        };

        if (leftDti.IsPointer)
        {if (rightDti.IsPointer)
                valOfPointer.TypeInfo = leftDti.BaseType > rightDti.BaseType ? leftDti : rightDti;
            else
                valOfPointer.TypeInfo = leftDti;
        }
        else
        {if (rightDti.IsPointer)
                valOfPointer.TypeInfo = rightDti;
            else
                valOfPointer.TypeInfo = leftDti.BaseType > rightDti.BaseType ? leftDti : rightDti;
        }

        return valOfPointer;
    }
    else
    {Operand.Value res = new Operand.Value()
        {DataType = leftDti.BaseType > rightDti.BaseType ? leftDti.BaseType : rightDti.BaseType};

        switch (res.DataType)
        {
            case PrimitiveDataType.CharType:
                {switch (rightDti.BaseType)
                    {case PrimitiveDataType.CharType: res.DataField = (byte)ComputeScalar(LeftOperand.GetValue(ctx).AsChar, RightOperand.GetValue(ctx).AsChar); break;
                        case PrimitiveDataType.ShortType: res.DataField = (byte)ComputeScalar(LeftOperand.GetValue(ctx).AsChar, RightOperand.GetValue(ctx).AsShort); break;
                        case PrimitiveDataType.IntType: res.DataField = (byte)ComputeScalar(LeftOperand.GetValue(ctx).AsChar, RightOperand.GetValue(ctx).AsInt); break;
                        case PrimitiveDataType.FloatType: res.DataField = (byte)ComputeFloat(LeftOperand.GetValue(ctx).AsChar, RightOperand.GetValue(ctx).AsFloat); break;
                        default: throw new RuntimeException(string.Format("Operator \"{0}\"doesn't supported type \"{1}\".", this, DataTypeInfo.StringFromType(rightDti.BaseType)));
                    }
                }
                break;
            case PrimitiveDataType.ShortType:
                {switch (rightDti.BaseType)
                    {case PrimitiveDataType.CharType: res.DataField = (short)ComputeScalar(LeftOperand.GetValue(ctx).AsShort, RightOperand.GetValue(ctx).AsChar); break;
                        case PrimitiveDataType.ShortType: res.DataField = (short)ComputeScalar(LeftOperand.GetValue(ctx).AsShort, RightOperand.GetValue(ctx).AsShort); break;
                        case PrimitiveDataType.IntType: res.DataField = (short)ComputeScalar(LeftOperand.GetValue(ctx).AsShort, RightOperand.GetValue(ctx).AsInt); break;
                        case PrimitiveDataType.FloatType: res.DataField = (short)ComputeFloat(LeftOperand.GetValue(ctx).AsShort, RightOperand.GetValue(ctx).AsFloat); break;
                        default: throw new RuntimeException(string.Format("Operator \"{0}\"doesn't supported type \"{1}\".", this, DataTypeInfo.StringFromType(rightDti.BaseType)));
                    }
                }
                break;
            case PrimitiveDataType.IntType:
                {switch (rightDti.BaseType)
                    {case PrimitiveDataType.CharType: res.DataField = (int)ComputeScalar(LeftOperand.GetValue(ctx).AsInt, RightOperand.GetValue(ctx).AsChar); break;
                        case PrimitiveDataType.ShortType: res.DataField = (int)ComputeScalar(LeftOperand.GetValue(ctx).AsInt, RightOperand.GetValue(ctx).AsShort); break;
                        case PrimitiveDataType.IntType: res.DataField = (int)ComputeScalar(LeftOperand.GetValue(ctx).AsInt, RightOperand.GetValue(ctx).AsInt); break;
                        case PrimitiveDataType.FloatType: res.DataField = (int)ComputeFloat(LeftOperand.GetValue(ctx).AsInt, RightOperand.GetValue(ctx).AsFloat); break;
                        default: throw new RuntimeException(string.Format("Operator \"{0}\"doesn't supported type \"{1}\".", this, DataTypeInfo.StringFromType(rightDti.BaseType)));
                    }
                }
                break;
            case PrimitiveDataType.FloatType:
                {switch (rightDti.BaseType)
                    {case PrimitiveDataType.CharType: res.DataField = (float)ComputeFloat(LeftOperand.GetValue(ctx).AsFloat, RightOperand.GetValue(ctx).AsChar); break;
                        case PrimitiveDataType.ShortType: res.DataField = (float)ComputeFloat(LeftOperand.GetValue(ctx).AsFloat, RightOperand.GetValue(ctx).AsShort); break;
                        case PrimitiveDataType.IntType: res.DataField = (float)ComputeFloat(LeftOperand.GetValue(ctx).AsFloat, RightOperand.GetValue(ctx).AsInt); break;
                        case PrimitiveDataType.FloatType: res.DataField = (float)ComputeFloat(LeftOperand.GetValue(ctx).AsFloat, RightOperand.GetValue(ctx).AsFloat); break;
                        default: throw new RuntimeException(string.Format("Operator \"{0}\"doesn't supported type \"{1}\".", this, DataTypeInfo.StringFromType(rightDti.BaseType)));
                    }
                }
                break;
            default:
                throw new RuntimeException(string.Format("Operator \"{0}\"doesn't supported type \"{1}\".", this, DataTypeInfo.StringFromType(res.DataType)));
        } // switch

        return res;
    }
}

一元操作符就比较简单,毕竟只有一个操作数:

public virtual Operand.Value Compute(Context ctx, Operand.Operand operand)
{DataTypeInfo leftType = operand.GetTypeInfo(ctx);

    if (leftType.IsPointer)
    {return new Operand.Value()
        {
            DataType = PrimitiveDataType.IntType,
            DataField = (int)ComputeScalar(Context.Memory.GetInt(operand.GetValue(ctx).AsInt))
        };
    }
    else
    {Operand.Value res = new Operand.Value()
        {DataType = leftType.BaseType};

        switch (leftType.BaseType)
        {case PrimitiveDataType.CharType: res.DataField = (byte)ComputeScalar(operand.GetValue(ctx).AsChar); break;
            case PrimitiveDataType.ShortType: res.DataField = (short)ComputeScalar(operand.GetValue(ctx).AsShort); break;
            case PrimitiveDataType.IntType: res.DataField = (int)ComputeScalar(operand.GetValue(ctx).AsInt); break;
            case PrimitiveDataType.FloatType: res.DataField = (float)ComputeFloat(operand.GetValue(ctx).AsFloat); break;
            default:
                throw new RuntimeException(string.Format("\"{0}\"doesn't support type \"{1}\".", this, leftType.ToString()));
        } // switch

        return res;
    }
}

public override Operand.Operand Evaluate(Context ctx, List<Operand.Operand> operands)
{Debug.Assert(operands.Count > 0);

    return Compute(ctx, operands.First());
}

具体到某一表达式,以加法为例,其实现如下:

public class Add : LowLevelArithmetic
{public override string ToString()
    {return "+";}

    public override int ComputeScalar(int left, int right)
    {return left + right;}

    public override float ComputeFloat(float left, float right)
    {return left + right;}
}

逻辑运算以 and 为例:

public class And : LogicOperator
{public override string ToString()
    {return "&&";}

    public override int ComputeScalar(int left, int right)
    {return left != 0 && right != 0 ? 1 : 0;}

    public override float ComputeFloat(float left, float right)
    {return left != 0 && right != 0 ? 1 : 0;}
}

一元操作符,以简单点的取负为例:

public class Minus : UnaryOperator
{public override string ToString()
    {return "-";}

    public override int ComputeScalar(int val)
    {return - val;}

    public override float ComputeFloat(float val)
    {return -val;}
}

复杂的点的如自增,以后自增为例:

public class PostfixIncrease : UnaryOperator
{public override string ToString()
    {return "++";}

    public override int ComputeScalar(int val)
    {return val + 1;}

    public override Operand.Operand Evaluate(Context ctx, List<Operand.Operand> operands)
    {Operand.Operand theOperand = operands.First();

        if (theOperand is Operand.Value || theOperand is Operand.ValueOfVariableReference)
        {Operand.Operand res = theOperand.GetValue(ctx);
            Operand.Operand computerRres = base.Evaluate(ctx, operands);

            if (theOperand is Operand.ValueOfVariableReference)
            {(theOperand as Operand.ValueOfVariableReference).GetReferencedVariable(ctx).Assign(computerRres.GetValue(ctx));    
            }

            return res;
        }

        if (theOperand is Operand.ValueOfPointerIndiction)
        {Operand.Value val = theOperand.GetValue(ctx);

            switch (theOperand.GetTypeInfo(ctx).BaseType)
            {case PrimitiveDataType.CharType: (theOperand as Operand.ValueOfPointerIndiction).Address++; break;
                case PrimitiveDataType.ShortType: (theOperand as Operand.ValueOfPointerIndiction).Address += 2; break;
                default: (theOperand as Operand.ValueOfPointerIndiction).Address += 4; break;
            }

            return val;
        }

        throw new RuntimeException(string.Format("\"{0}\"doesn't support type \"{1}\".", this, theOperand.GetTypeInfo(ctx).ToString()));
    }
}

自增需要考虑返回值是运算之前的值还是运算之后。
特殊的取地址操作其实比较简单,因为限制其只能作用于变量:

public class GetAddress : UnaryOperator
{public override string ToString()
    {return "&";}

    public override Operand.Value Compute(Context ctx, Operand.Operand operand)
    {if (operand is Operand.ValueOfVariableReference)
        {return new Operand.Value()
            {
                DataType = PrimitiveDataType.IntType,
                DataField = (operand as Operand.ValueOfVariableReference).GetReferencedVariable(ctx).Address 
            };
        }
        else
        {throw new RuntimeException(string.Format("\"{0}\"only support variable.", this));
        }
    }
}

括号操作符不属于一元、二元之列,单独一类:

public class Parentheses : Operator
{public Parentheses()
        : base(OperatorPriority.Parenthese)
    { }

    public override string ToString()
    {return "(";}

    public override Operand.Operand Evaluate(Context ctx, List<Operand.Operand> operands)
    {return operands.First();
    }
}
退出移动版