這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
Dog-comp
Abstract
文章介紹一個編譯器的實現流程。源語言選用MiniJava. MiniJava是一個物件導向語言,支援繼承,對象建立等物件導向的特性。具體文法參考Tiger book 附錄。
Dog-comp是一個用golang實現的minijava編譯器,目前可以將minijava翻譯成c。dog-comp包括前端的lexer,parser,type-checking,codegen,後端還有基於minijava-AST的最佳化,基於控制流程圖的最佳化。為了滿足minijava物件導向的特性,Dog-comp還帶有一個runtime,實現了一個垃圾收集器。Dog-comp可以作為學習編譯器和語言最佳化的一個小工具。
lexer
雖然目前已經有了詞法分析器的產生器,但是Dog-comp使用了轉移圖(TDA)演算法手工實現lexer。
parser
Dog-comp的parser使用LL(1)。在Exp與Stm的處理上進行了文法改寫,避免了二義性。
elaborator
編譯器是一個典型的現行結構,類型檢查的輸入就是parser的輸出,也就是源語言的Ast。
codegen
在代碼產生的環節,將源語言的Ast翻譯成了C語言的Ast,時候將C-Ast進行列印,實際上就完成了翻譯。但是,這裡有幾個地方需要注意。將一個物件導向的語言翻譯成C這樣的語言,我們需要在中間做一些變換,這些變換實際上也就是物件導向語言的實現技術。
什麼是對象?
這裡要說對象到底是什麼。對象裡面可以有資料,還可以有函數,所以我們可以說對象是資料和操作這些資料的函數的集合。換到C語言裡面,對象不能僅僅用一個structure表示,這裡也就出現了虛函數表的概念。我們可以將資料和一個函數表組合成一個structure,這個structure其實就是java的對象。
Flattening
所謂的平坦化,就是將java的Class全部消除。顯然,在C裡面,所有的函數都是平坦的。
垃圾收集器
編譯產生的C檔案和runtime.c一起編譯成可執行檔,使得c帶有垃圾收集的功能。為了支援垃圾收集,必須在c的structure裡面在加入一些欄位,用於GC記錄對象的狀態。比如需要記錄這個對象中那些欄位是引用,這個對象是普通對象還是數組對象等等。
最佳化!
Dog-comp在源碼Ast層級上做了4個最佳化。
DeadClass Elimination
如所示,class Fac是一個根本沒有被用到的類,經過死類刪除之後,Fac被幹掉了。
DeadCode Elimination
的程式包含著無作用程式碼。顯然,if的else分支是不可能執行的,最後一個while也沒有執行的可能。所以經過無作用程式碼刪除,這兩段代碼會直接消失。
這裡有一個問題需要注意,while(true){}和while(false){}是否應該同樣對待呢?while(false)顯然是無作用程式碼,但是while(true)是否應該被刪除呢?答案是否定。
AlgSimp
代數化簡主要是針對運算,比如i=ab0*(a+2)/m),右側的運算式可以直接最佳化為0.
ConstFold
常量摺疊是在編譯期把常量上的運算做完。
的代碼中有很多可以最佳化的地方。執行完常量摺疊之後代碼如。
這裡可以觀察到,進行完常量摺疊之後,實際上有產生的無作用程式碼,程式可以繼續最佳化。所以這4個最佳化不停迴圈的作,直到達到不動點為止。
CFG
控制流程圖是一種方便最佳化的中間表示。如就是LinkedList.java中Equal函數的控制流程圖。
可以使用
dog-comp/$ ./dog-comp ../test/LinkedList.java -visualize svg 產生。