C语言解释器-13 表达式

来源:互联网 发布:爱美眉美女图片站源码 编辑:程序博客网 时间:2024/05/19 22:55

表达式,最简单也最困难。各种算术、逻辑、赋值埋同函数调用,想想都头大如斗转星移山填海枯石烂。

废话有云,根据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();        }    }


 

原创粉丝点击