C语言解释器-8 变量

出于对指针操作的支持,变量Variable需要模拟其在内存空间中的表现。每个变量都有个Address属性。参考Variable.Assign()方法,可知端倪:

public virtual void Assign(Expression.Operand.Value value)
        {
            if (this.TypeInfo.IsPointer)
            {
                Memory.SetInt(Address, value.AsInt);
            }
            else
            switch (TypeInfo.BaseType) // Assign value
            {
                case PrimitiveDataType.CharType:
                    {
                        Memory.SetChar(Address, value.AsChar);
                    }
                    break;
                case PrimitiveDataType.ShortType:
                    {
                        Memory.SetShort(Address, value.AsShort);
                    }
                    break;
                case PrimitiveDataType.IntType:
                    {
                        Memory.SetInt(Address, value.AsInt);
                    }
                    break;
                case PrimitiveDataType.FloatType:
                    {
                        Memory.SetFloat(Address, value.AsFloat);
                    }
                    break;
                default: throw new RuntimeException(string.Format("Uncompatible type between {0} and {1}.", TypeInfo.ToString(), value.GetTypeInfo(this).ToString())); // Uncompatible type
            } // switch
        }


对C的模仿,导致以上行为:赋值对原生类型而言,是将值写入地址空间,而指针则写入一个地址(32位)。

故此,在获取变量值时,值类型和指针类型有不同表现:

public virtual Expression.Operand.Value GetValue()
        {
            if (TypeInfo.IsPointer)
            {
                return new Expression.Operand.Value(PrimitiveDataType.IntType, Address);
            }

            object data;

            switch (TypeInfo.BaseType)
            {
                case PrimitiveDataType.CharType: data = Context.Memory.GetChar(Address); break;
                case PrimitiveDataType.ShortType: data = Context.Memory.GetShort(Address); break;
                case PrimitiveDataType.IntType: data = Context.Memory.GetInt(Address); break;
                case PrimitiveDataType.FloatType: data = Context.Memory.GetFloat(Address); break;
                default: return null;
            }

            return new Expression.Operand.Value(TypeInfo.BaseType, data);
        }


对于常量,SharpC仅将字符串视为常量,其他值则就地产生一个Expression.Operand.Value对象。

字符串常量产生于语法分析器探测到一对“”及其内容时,通过Parser.GetStringValue()方法获得。当得到一个字符串时,就产生一个类型为字符指针的Variable变量,再产生一个ConstantInitialize对象。ConstantInitialize对象包含了前一步所产生的Variable之名字以及初始化数据,在Run()方法被调用时根据这些信息初始化该变量。Variable和ConstantInitialize成对出现。代码片断如下:

// The const variable
            Variable stxConstVar = new Variable()
            {
                TypeInfo = new DataTypeInfo()
                {
                    Type = PrimitiveDataType.CharType | PrimitiveDataType.PointerType,
                    PointerCount = 1
                },
                ReferenceCount = 1
            };

            stxConstVar.Name = Context.GetAnonymousName(stxConstVar.TypeInfo);

            int byteArrayLen = Encoding.ASCII.GetByteCount(strBuilder.ToString()) + 1;

            ConstantInitialize stxConstInit = new ConstantInitialize()
            {
                Name = Context.GetAnonymousName("const_init"),
                VariableName = stxConstVar.Name,
                InitialValue = new byte[byteArrayLen]
            };
            
            char[] charArray = strBuilder.ToString().ToCharArray();

            Encoding.ASCII.GetBytes(charArray, 0, charArray.Length, stxConstInit.InitialValue, 0);

            stxConstInit.InitialValue[byteArrayLen - 1] = 0;
            
            ctx.GlobalContex.AddChildAtFirst(stxConstInit);
            ctx.GlobalContex.AddChildAtFirst(stxConstVar);


对于函数,参数在BeforeRun()方法中初始化一次。变参函数则次次都需要初始化。

private void BeforeRun(Context ctx, List<Expression.Operand.Operand> parameters)
        {
            if (IsFirstRunning)
            {
                ConfigReturnEvent(ctx);

                AllocateFixedArguments(ctx);
                
                IsFirstRunning = false;
            }

            if (IsVariableArgument)
            {
                FreeVariableArgument(ctx);

                AllocateVariableArguments(ctx, parameters);
            }

            SavePreviousParameters(ctx);

            InitArguments(ctx, parameters);

            IteratorCount++;
        }


AllocateFixedArguments方法初始化参数:

private void AllocateFixedArguments(Context ctx)
        {
            // Allocate fixed arguments
            if (!IsVariableArgument)
            {
                IEnumerator<Context> argEnumerator = ArgumentDefinitions.GetEnumerator();

                while (argEnumerator.MoveNext())
                {
                    (argEnumerator.Current as FunctionArgumentDefine).Run(this);
                }
            }
        }


函数参数其实就是Variable的重命名。当然在C#中没有重命名这回事,而是继承:

public class FunctionArgumentDefine : Variable
    {
    }


 

 

 

你可能感兴趣的:(C#,C语言,解释器,形式语言和自动机)