SharpC: A C Interpreter In C# - 0101

出于对指针操作的支持,变量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
}

[Click and drag to move]


对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 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 argEnumerator = ArgumentDefinitions.GetEnumerator();

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

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

public class FunctionArgumentDefine : Variable
{
}

你可能感兴趣的:(c#,c)