承接前四篇,本文深入探討高階語言腳本引擎的核心組件——符號表。符號表連接語法分析與程式碼生成,承載型別資訊、作用域結構、識別子屬性等語義層面資料,是編譯器前後端的關鍵介面。
面對函數型別、結構型別、指標、陣列等複雜型別體系,採用繼承階層雖符合 OOP 直覺,但雙重分派問題棘手(如 Equal(Base1, Base2) 需 dynamic_cast)。本文採用 唯一型別 ID 方案:
GetPointer(baseID)、GetArray(elemID, count)、GetFunction(retID, paramIDs[])不建議將型別、作用域資訊直接存於語法樹節點。因同一程式碼在不同上下文可能有不同語義,若需保留多環境分析結果,語法樹耦合會導致深拷貝困難。改用 map<Expr*, TypeInfo>、map<Stmt*, ScopeInfo> 等關聯容器,以節點指標為鍵外掛語義資訊。
採鏈表串聯巢狀作用域:StmtScope → FuncScope → GlobalScope。查找識別子沿鏈向上搜尋;新增識別子僅檢查當前作用域,自動遮蔽外層同名符號。作用域節點可額外記錄:最近迴圈標籤(break/continue 合法性)、所屬函數(return 型別檢查)等編譯期上下文。
語法樹節點定義虛擬介面:
virtual TypeID GetType(SymbolTable&, Scope*)virtual void Validate(SymbolTable&, Scope*)遞迴遍歷語法樹時,運算式產生型別 ID 註冊至型別表,陳述句建立作用域並驗證合法性。此過程即語義分析,產出完整符號表供下階段程式碼生成使用。
class VL_CMinusTypeTable : public VL_Base {
public:
VInt GetPrimitiveType(VLE_CMinusPrimitiveType Type);
VInt GetPointer(VInt Type);
VInt GetArray(VInt Type, VInt Count);
VInt GetFunction(VInt ReturnType, VL_List& ParameterTypes);
VInt CreateStruct();
VL_CMinusTypeSlot* GetType(VInt Type);
};
下篇將針對繼承、反射、垃圾回收等具體語言特性展開實作討論。