Context是构建语法树的基础,程序由一个个Context组成,比如变量(申明),语句,块,函数,控制结构等。
看看Context类的Run方法,很能说明问题:
public virtual void Run(Context ctx)
{
// 正在运行标记
IsRunning = true;
foreach (Context stx in Children)
{
try
{
if (stx is Statement || stx is Block)
{
stx.Run(this);
}
else
if (stx is Variable)
{
//局部变量,需要登记,以便将来释放
LocalVariables.Add(stx.Name);
stx.Run(this);
}
else
if (stx is ConstantInitialize)
{
//常量,出现在全局Context中,需要记录。在运行到最后的时候释放
m_constantVariableDict.Add((stx as ConstantInitialize).VariableName, stx);
stx.Run(this);
}
else
if (stx is Function.FunctionDefine)
{
// 仅运行main函数,其他函数在调用时运行
if (stx.Name == MainFunctionName)
{
m_mainFunction = stx as Function.FunctionDefine;
m_mainFunction.Body.Run(this);
}
}
}
catch (RuntimeException re)
{
if (OnRuntimeError != null)
OnRuntimeError(stx, re.Message);
}
} // foreach
// 释放局部变量
FreeLocalVariables();
IsRunning = false;
}
设定所有的Context都应该有个Parent,如果Parent为null,则表示为全局的Context。也即Yacc脚本中的Program规则。
主要的属性有:
// Public
public Context Parent;
public List Children;
public string Name;
public List LocalVariables;
public bool IsFirstRunning = true;
public LocationInfo Location;
public event EventHandler OnRuntimeError;
一些全局性的东西,申明为静态,主要与语法分析相关。还包括内部定义函数。
// Static
public static string MainFunctionName = "main";
private static int AnonymousVariableCount = 0;
private static string AnonymousVariableNamePrefix = "var";
private static bool ContextIsRunning = false;
public static Dictionary KeywordDict = new Dictionary();
public static Dictionary DataTypeKeywordDict = new Dictionary();
public static Dictionary ControlKeywordDict = new Dictionary();
public static Dictionary TypeCombinationDict = new Dictionary();
public static Dictionary InternalFunctionDict = new Dictionary();
public static Memory Memory = new Memory("");
public static bool IsRunning
{
get { return ContextIsRunning; }
protected set { ContextIsRunning = value; }
}
public static string GetAnonymousName()
{
return string.Format("${0}_{1}$", AnonymousVariableNamePrefix, ++AnonymousVariableCount);
}
public static string GetAnonymousName(string prefix)
{
return string.Format("${0}_{1}$", prefix, ++AnonymousVariableCount);
}
public static string GetAnonymousName(DataTypeInfo dti)
{
return string.Format("${0}_{1}_{2}{3}$",
AnonymousVariableNamePrefix,
DataTypeInfo.StringFromType(dti.BaseType),
dti.PointerCount > 0 ? "ptr_" : "",
++AnonymousVariableCount);
}
public static bool IsKeyword(string str)
{
if (KeywordDict.Count == 0)
{
// primitive type
KeywordDict.Add("void", true);
KeywordDict.Add("char", true);
KeywordDict.Add("short", true);
KeywordDict.Add("int", true);
KeywordDict.Add("float", true);
KeywordDict.Add("signed", true);
KeywordDict.Add("unsigned", true);
// control
KeywordDict.Add("if", true);
KeywordDict.Add("else", true);
KeywordDict.Add("for", true);
KeywordDict.Add("do", true);
KeywordDict.Add("while", true);
KeywordDict.Add("switch", true);
KeywordDict.Add("case", true);
KeywordDict.Add("continue", true);
KeywordDict.Add("break", true);
KeywordDict.Add("return", true);
// misc
KeywordDict.Add("sizeof", true);
}
return KeywordDict.ContainsKey(str);
}
public static bool IsDataType(string str)
{
if (DataTypeKeywordDict.Count == 0)
{
DataTypeKeywordDict.Add("void", PrimitiveDataType.VoidType);
DataTypeKeywordDict.Add("char", PrimitiveDataType.CharType);
DataTypeKeywordDict.Add("short", PrimitiveDataType.ShortType);
DataTypeKeywordDict.Add("int", PrimitiveDataType.IntType);
DataTypeKeywordDict.Add("float", PrimitiveDataType.FloatType);
DataTypeKeywordDict.Add("signed", PrimitiveDataType.SignedType);
DataTypeKeywordDict.Add("unsigned", PrimitiveDataType.UnsignedType);
}
return DataTypeKeywordDict.ContainsKey(str);
}
public static bool IsControlFlow(string str)
{
if (ControlKeywordDict.Count == 0)
{
ControlKeywordDict.Add("if", true);
ControlKeywordDict.Add("else", true);
ControlKeywordDict.Add("for", true);
ControlKeywordDict.Add("do", true);
ControlKeywordDict.Add("while", true);
ControlKeywordDict.Add("switch", true);
ControlKeywordDict.Add("case", true);
ControlKeywordDict.Add("continue", true);
ControlKeywordDict.Add("break", true);
ControlKeywordDict.Add("return", true);
}
return ControlKeywordDict.ContainsKey(str);
}
public static bool IsInternalFunction(string str)
{
return InternalFunctionDict.ContainsKey(str);
}
public static void RegisterInternalFunction(string name)
{
if (!InternalFunctionDict.ContainsKey(name))
InternalFunctionDict.Add(name, true);
}
注意到相当多的静态方法使用字符串字典。
另外一个重要的方法是FindByName(string name),该方法用于查找符合指定名字的已定义的Context,这是检查或查找变量、函数的重要手段。
public virtual Context FindByName(string str)
{
if (m_nameDict.ContainsKey(str))
return m_nameDict[str];
Context stx = this.Parent;
if (stx != null)
return stx.FindByName(str);
return null;
}
一些语法结构,如控制结构、函数,需要知道一些额外信息,因此需要以下辅助方法:
public bool IsInFunction
{
get
{
Context stx = Parent;
while (stx != null)
{
if (stx is Function.FunctionDefine)
return true;
stx = stx.Parent;
}
return false;
}
}
public Function.FunctionDefine ParentFunction
{
get
{
Context stx = Parent;
while (stx != null)
{
if (stx is Function.FunctionDefine)
return stx as Function.FunctionDefine;
stx = stx.Parent;
}
return null;
}
}
public Block ParentBlock
{
get
{
Context stx = Parent;
while (stx != null)
{
if (stx is Block)
return stx as Block;
stx = stx.Parent;
}
return null;
}
}
public bool IsInLoop
{
get
{
Context stx = Parent;
while (stx != null)
{
if (stx is ControlFlow.ForLoop || stx is ControlFlow.DoWhileLoop || stx is ControlFlow.WhileLoop)
return true;
stx = stx.Parent;
}
return false;
}
}
public bool IsInSwitch
{
get
{
Context stx = this;
while (stx != null)
{
if (stx is ControlFlow.Switch)
return true;
stx = stx.Parent;
}
return false;
}
}
public Context GlobalContex
{
get
{
if (this.Parent == null)
return this;
else
return this.Parent.GlobalContex;
}
}
常量应该在最后一刻释放。相同的还有函数的参数定义。SharpC将函数的参数视为特殊的局部变量:在函数第一次运行时分配空间,而在解释器运行到最后时才释放。也算是一种简单的优化。
~Context()
{
FreeConstantVariables();
if (Parent == null)
{
if (m_mainFunction != null)
FreeFunctionArguments(m_mainFunction);
FreeAllFunctionArguments(this);
}
}