摘要:介紹了自製語言的編譯器對符號表的處理。
yf語言中,符號表的基本結構是hash表。每個ast,附帶了3個hash表,變數表,型別表,函式表。例如就是變數表,記錄變數的名稱和值。型別表記錄各種型別,array、class、inte***ce、function、generic。函式表則記錄了函式名和函式體、函式型別的對應關係。
乙個檔案有若干class和inte***ce定義,此外的部分是指令碼,可以定義變數、函式等。同時,class或指令碼都沒有main()函式。指令碼本身就是main()。指令碼內的函式可以訪問指令碼範圍的變數與函式。而型別的作用域都是全域性的(全域性是指本檔案範圍)。檔案頭部import其他檔案之後,可以訪問其class、inte***ce,但不能訪問其指令碼變數和函式。
作用域跟ast的層次有關以及訪問者有關。舉例來說,每個stmt_list都是乙個單獨的作用域。codegenerator保留乙個棧list,訪問ast時,遇到stmt_list,就把這個ast加入棧頂。遇到define variable,就生成乙個新的符號,這個符號加入棧頂ast的符號表中。當後面要查詢variable,就從棧頂開始依次查詢符號表。當訪問者離開這個ast,把棧頂ast退出。這樣,不在作用域內的變數引用就是非法的。而作用域範圍可以巢狀。內層作用域可以訪問外層作用域定義的變數或者函式。
查詢函式的方法,除了函式的名稱,還要有函式的型別簽名,如int(int, int)。這可以用於函式過載。
class內部不允許訪問外部的變數及函式。但是子類可以訪問父類。這裡就有乙個作用域控制問題。class範圍內,每個定義的field和method都記錄入type物件中,同時遞迴地記錄了全部super class以及inte***ce。在class範圍內查詢變數或者函式時,優先在codegenerator的符號表相關ast棧中查詢。ast棧中每個ast,在codegenerator初次訪問時,都打上了乙個標記,標明此處是什麼範圍。比如全域性範圍,標記是0b1,class範圍標記是0b10,區域性變數的標記是0b100,等等。當codegenerator發起乙個查詢時,自身的標記如果不符合,就不被允許查詢。這樣就杜絕了從class內部訪問外部的指令碼的變數。那麼,當class內部查詢不到變數時,就會訪問型別表,查詢當前class的成員記錄。若當前class型別中查詢不到記錄,則繼續向super型別中查詢。直到找到符號或者找不到而throw exception。
值得一提的是this關鍵字。遇到this關鍵字,查詢順序發生變化。省略前面從ast查詢的步驟而是直接通過型別表中找。因為在class範圍內的ast的符號表,無非有兩種情況,class的成員,或者區域性變數。沒有this關鍵字,那麼符號可能是類成員也可能僅僅是區域性變數,有了this關鍵字,符號只能是成員。所以必須從class型別中去找。前面一種情況下區域性變數對型別成員的覆蓋,也是通過ast棧來實現。
自製指令碼語言(7) 指令碼語言的完善 字串 注釋
摘要 前面提到的編譯器直譯器的進一步完善,即加入字串和注釋的處理。字串和注釋不能由正規表示式的方式來處理。注釋的兩種形式是 abc,abc 這就會有巢狀和混用的問題 字串裡面會有轉義符,例如 a b 這樣就不是正則語言了,而是成了上下文無關語言,正規表示式的處理方式無效。所以,我在tokenizer...
12 Python指令碼學習筆記十二作用域與遞迴
12.python指令碼學習筆記十二作用域與遞迴 本篇名言 面對困難,微笑含著勇敢 面對挫折,微笑帶著自信 面對誤解,微笑露出寬容 面對冷漠,微笑洋溢熱情 面對愛情,微笑代表真心。願你微笑面對人生。python 有個內建的vars函式可以返回變數字典。如下 x 1 scope vars scope ...
Linux Shell指令碼語言與數學表示式
當你理解了shell指令碼,每當需要時都能流暢編寫時,那種感覺很爽的。本章中,我們將教你用指令碼語言進行比較複雜的數 算。讓我們從斐波那契數列開始吧。斐波那契數列,又稱 分割數列,指的是這樣乙個數列 0 1 1 2 3 5 8 13 21 它的每一項都是前兩項的和,定義數列的首兩項為0 1。指令碼1...