author: Kevin Lynx email: zmhn320#163.com date: 3.10.2009
符號表
在上一節中,當我們的解釋器解釋執行age=age+1這個語法樹時,會涉及到變量age的值
。實際上我們還需要個保存腳本中相關變量的模塊,當我們的解釋器獲取到一個ID樹節點時
,需要從這個模塊中獲取出該變量的值,并參與運算。
這個我稱之為符號表。我想到這里,我所說的概念很可能和教科書有點不一樣了。
什么是符號表?
符號表(symbol table)就如同其字面意思一樣,是一個表,更寬泛地說是一個保存符號
的容器。
腳本中諸如變量函數之類的東西都算作符號,例如age。符號表就是保存這些符號的容
器。
在kl中,符號表保存著某一個作用域里的變量。其全局符號表還保存著函數符號,對于
函數符號而言,其值為語法樹樹節點的指針值。當調用一個函數時,將該值轉換為樹節點,
然后執行。當然,這應該算做解釋執行一節的細節,不多說。
再明確下符號表的作用,舉例,在上一節中,涉及到這么一個例子函數:
value factor( TreeNode *node )
{
switch( node->type )
{
case ID:
/* 在這里,發現一個樹節點類型為ID,就需要根據ID對應的名字,也就
是age,在符號表中查找age的值 */
return age;
/* ... */
}
}
以上注釋闡述了符號表的作用。
符號表的實現
其實不管符號表如何實現,對于其他模塊而言,對符號表的唯一要求就是提供幾個類似
這樣的接口:
value sym_lookup( const char *name );
void sym_insert( const char *name, value val );
也就是說,提供查找符號值,以及插入新符號的接口。
在kl中,使用了<編譯原理與實踐>中相同的符號表數據結構實現。即使用了hash表,
hash數組中每個元素保存的是一個鏈表頭節點。每一個符號字符串通過散列函數得到hash數
組索引,然后在該索引里進行一次線性查找。很典型的hash結構。
另一方面,因為kl支持全局和函數局部兩個作用域。所以kl中有一個全局符號表,用于
保存全局變量以及所有的函數符號;同時每一次進入一個函數時,就會創建一個臨時的局部
符號表,用于存儲局部變量;后來,為了支持插件,插件函數被特定地保存在另一個全局符
號表里。
代碼導讀
kl中的符號表實現代碼在klsymtab.h/klsymtab.c中,實現比較簡單,無需多言。