C language interpreter-13 expression

Source: Internet
Author: User

Expression, which is the simplest and most difficult. All kinds of arithmetic, logic, and assignment values are buried in the same function call.

According to Yacc rules, expressions are composed of operands and operators. The operands include the immediate number, variable, function call, and another expression. Operators include unary, binary, and ternary operators. Xihu SharpC does not support ternary expressions.

There are two special operands: Pointer and Pointer indication (how to translate Pointer indiction ).

There is a special operator: sizeof. It is special because it is classified as a mona1 operator and does not need an operand like other operators. sizeof can also use a type name as the operand.

First, let's look at the definition of operator priority:

Public enum OperatorPriority {// The lowest Assign, Logic, Bitwise for the value assignment operation. // arithmetic operations have two levels of priority: +,-is a level, *,/, % is a level-one armeticlow, arthur metichigh, // The Shift operator is given priority over arithmetic Shift, Address, Unary, Parenthese}

First, let's look at the expression evaluation process:

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;            }        }

 

Evaluate the expression process:

1. If it is an operand, return it as the result.

2. if it is an operator, evaluate the Left and Right nodes successively, then evaluate the result of the left and right nodes as the operand, call the Evaluate Method of the operator, and return the result.

The final calculation of the operator is based on two types: int and float.

Note: because there is no strict distinction between signed and unsigned, there may be errors in the two calculation evaluation processes.

Therefore, there are two methods:

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();        }

The unary operator has an additional Compute method:

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)        {

The Calculation of binary operators is complex. You need to consider the following situations:

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;            }        }

The unary operator is relatively simple. After all, there is only one operand:

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());        }

Specific to an expression, the implementation of addition is as follows:

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;        }    }

 

The logical operation uses and as an example:

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;        }    }

The unary operator. Take the negative value of a simple vertex as an example:

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;        }    }

Complex points, such as auto-increment and auto-increment in the future, are used as an example:

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()));        }    }

Whether the returned value is a value before or after an operation is considered for auto-increment.

The special address fetch operation is actually relatively simple, because it can only act on variables:

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));            }        }    }

The brackets operator does not belong to the columns of one or two elements. It is a separate class:

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();        }    }

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.