出于对指针操作的支持,变量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<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
{
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。