表达式,最简单也最困难。各种算术、逻辑、赋值埋同函数调用,想想都头大如斗转星移山填海枯石烂。
废话有云,根据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(); } }