編譯器入門,語義分析
2022-02-02由 閒聊程式碼 發表于 林業
語義型別是什麼
語義分析,是語法分析與中間程式碼生成之間的過渡步驟,是基於抽象語法樹AST的進一步分析,主要是3個方面:
1,型別檢查和自動型別轉換,
對抽象語法樹的每一個節點的輸入進行型別檢查。
在型別不一致時新增自動型別轉換(type cast),必要時給出warnning資訊。
無法自動型別轉換的,給出error資訊。
確定該節點的輸出結果型別,用於父節點的型別分析,依次遞迴。
2,常量表達式的計算,
常量表達式的結果在這裡提前算出來,用一個常數代替,減少後續環節的運算量,提高生成的目的碼的效率。
例如,int sec = 60 * 60,
替換為,int sec = 3600,
這樣在生成機器碼的時候就不需要使用乘法指令,直接一個mov指令把常數3600
賦值給sec就行了。
3,運算子過載和函式過載,
已經完成了型別檢查的情況下,在這裡是可以確定具體選擇哪一個過載函式的,把它轉換為對過載函式的呼叫。
例如有個Mat矩陣類,該類有幾個加法運算的過載函式,那麼在這裡就可以確定輸入引數是不是含有矩陣,是2個矩陣相加還是矩陣加上一個常數,etc。
把這個加法運算子,轉化為對Mat類的對應函式的呼叫。
虛擬函式呼叫是沒法在這裡確定的,因為基類指標的具體子類型別是動態的,只能執行時查詢它的虛擬函式表獲得實際呼叫的函式。
語義分析,是遞迴遍歷AST樹,並對它的節點進行分析。
從語義分析開始,後續的所有分析都是以AST樹的節點為基礎的,不同的階段使用的分析函式不同而已。
所以,我們可以這麼設計AST節點的資料結構:
struct ast_node_s
{
int type; 節點型別
struct ast_node_s* parent; 父節點
struct ast_node_s** childs; 子節點列表
int nb_childs; 子節點個數
uint32_t flags;
各種標示,例如常量、常量字面值等等
} ;
父節點和子節點列表,是構成整個AST樹的基礎。
運算子的優先順序,也是體現在生成語法樹時,誰是子節點,誰是父節點,子節點的優先順序更高。
節點型別,就是節點的語義,標示著該用哪個函式去處理當前節點。
在語義分析階段,和三地址碼生成階段,選擇的處理函式是不同的。
當然,不同型別的節點,選擇的處理函式也是不同。
我們可以根據當前的分析階段和節點型別,去相應的函式表裡查詢對應的函式,並呼叫它。
過了語法分析之後,終於不再有那種互相交織著的遞迴呼叫了,不那麼擰巴了:(
以後都是對語法樹的遍歷,或者三地址序列的遍歷。