編譯原理—語法分析

PS 多年前寫的了,放在草稿箱裏… 現在發出來了

上週完成了編譯實驗課程的語法分析部分,週末玩去了,今天稍稍整理一下。
首先我們是採用語法制導翻譯來做的編譯,書上對於語法制導翻譯的解釋是,將靜態檢查和中間代碼生成結合到語法分析中進行的技術。大概就是指把詞法分析、語義分析都結合到語法分析中來,一切都圍繞着語法分析展開吧。
所以,完整的語法分析程序,應該是將詞法分析的輸出作爲輸入,在進行每一次歸約時進行語義分析,產生中間代碼。當語法分析結束時,語義分析也結束了。
由於進度等原因,這次寫的語法分析還只是單純的語法分析,沒有加入任何的語義分析成分。
整個代碼的核心部分就是分析表的構建。恩,該語法採用的是LR1分析法,需要構建LR1分析表。
首先需要解決的問題就是符號(包括終結符和非終結符)到數字(對應分析表縱座標,需要從0~符號個數-1)的轉換。這個簡單,做了個hash,難得用了回內散列,因爲數組開的大,應該是沒有什麼衝突。對應的,又建了個從數字到符號的映射,這個就是建了個結構體數組,最開始的時候覺得用處不是那麼大,只是想方便以後根據數字查對應的字符來着,但是後來的時候往結構體里加入了該符號的所有產生式編號,給後面求LR1項目閉包、FIRST集帶來了極大的方便。可謂無心插柳的神來之筆 - - 。
接下來就是對產生式的數字話,這個比較簡單啦。構建了一個結構體數組,利用前面的結果,把字符形式的、複合的(即A->B | C |D 的形式)產生式轉換數字的、單一的結構體項目。

{
 int dotPos ;
 int productionOrder ;
 int expectedSymbol ;
 int exSymNum ; 
} ;

只在裏面記錄產生式的序號,然後可以在根據序號到產生式數組中線性訪問,感覺這麼以來整個程序就關聯起來了,所謂的低耦合?雖然很好,不過老實說,到後期編碼的時候太容易搞混了。。。。
接着就是求閉包了,求閉包之前當然得先得求FIRST集啦,這個用遞歸寫的,老實說,寫得很吃力 - -,感覺是不太會能用棧改寫這個遞歸了。寫這個FIRST集還遇到個問題,就是產生式的左遞歸問題:無窮遞歸。當時測試的時候就是崩潰啊,唉,當時那個難受。後來跟蹤,終於恍然大悟啊。果然求FIRST集不能處理左遞歸的。但是好奇的是《編譯控制檯》這款神奇強大的軟件可以正常處理,着讓我很是驚異,也深感差距。不知到他是用了其他算法,還是限制了遞歸的層次,當發現遞歸數過大時及時跳出。具體原理不知,就只剩下膜拜了。接着搞CLOURE , 總的來說還算順利,基本就是隊列的思想,依次將產生式dotPos處的符號求空閉包,就是當該符號是非終結符時,將該非終結符的每個產生式(這個可以通過查符號列表裏的產生式編號迅速求得)構建成一個LR1項目(包括產生式序號、展望符),加入到cloure中(放入隊位,即數組尾部),然後數組頭指針往後移動一位。加入的時候當然要去重啦。去重效率就相當低了,實在是煩寫hash了,就只能枚舉了 - - 。
求得CLOURE,然後就可以建立起LR1項目集族了。我也是用的一個結構體數組來做 - -。首先求拓展文法的CLOURE,然後就是和求CLOURE一樣的方法,求得CLOURE裏每個LR1項目的後繼項目,然後將該後繼項目構建成LR1項目,求得CLOURE,加入到隊列(數組,當然又得去重),最後項目集族就ok了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章