共计 5592 个字符,预计需要花费 14 分钟才能阅读完成。
Context 类
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<Context> Children;
public string Name;
public List<string> LocalVariables;
public bool IsFirstRunning = true;
public LocationInfo Location;
public event EventHandler<string> 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<string, bool> KeywordDict = new Dictionary<string, bool>();
public static Dictionary<string, PrimitiveDataType> DataTypeKeywordDict = new Dictionary<string, PrimitiveDataType>();
public static Dictionary<string, bool> ControlKeywordDict = new Dictionary<string, bool>();
public static Dictionary<int, short> TypeCombinationDict = new Dictionary<int, short>();
public static Dictionary<string, bool> InternalFunctionDict = new Dictionary<string, bool>();
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);
}
}
正文完