SharpC-A-C-Interpreter-In-C-0100

22次阅读

共计 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);
    }
}

正文完
 0