在學到java編譯器的時候,當聽到說javac是由java編寫時其實是感到詫異的。原因很簡單,如果javac本身就是一個java程序,那么一定需要一個編譯器先把它編譯成可執行的文件。可是這款已經編譯好的編譯器又是哪里來的呢?而且,既然我們已經有了一款編譯器,那還要javac做什么呢?
這個問題自然很容易搜索到答案:最初的java編譯器的確不是java寫的,所以這個“雞生蛋還是蛋生雞”的問題自然不必再困惑。而寫出javac作為通用的編譯器則是為了使java滿足一項特性:自舉(Bootstrapping)。自舉的意思是說,一種編程語言的程序可以用這種語言本身編寫的編譯器來編譯。
知乎上的輪子哥是這樣簡要地描述自舉的過程的:
你想創造一門V語言而且用V語言來寫V編譯器的話,你得按照下面的方法做:
1、用C++把那個編譯器(A)寫出來,順便留下很多測試用例。
2、用V語言把那個編譯器寫(B)出來,用A.exe來編譯B,修改直到所有測試用例都通過為止。
3、B.exe來編譯B自己得到B2.exe,修改直到B2.exe所有測試用例都通過為止。這是為了保證,就算B本身有很多bug,至少編譯自己是沒有bug的,從而你就可以走到第四步。
4、當你覺得有信心了,用A.exe把B編譯一遍,就得到了B.exe。然后A的代碼和A.exe都在也不需要存在了,刪掉他們。以后你就不斷的用B.exe來編譯下一個版本的B就好了。就自舉了。
作者:vczh
鏈接:https://www.zhihu.com/question/28513473/answer/41094452
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
不同的編程語言由于其誕生和發展的經歷不盡相同,完成自舉的過程也各自有所差異。一般來說,該語言最開始的編譯器是用其它已經成熟的語言編寫的,比如Pascal最初的編譯器是Fortran寫的;當然比較厲害的人也可以把自己寫的編譯器手動編譯,比如Donald Knuth就自己手動編譯了WEB語言的編譯器。不過,這些繁瑣的過程僅僅需要在該語言剛剛誕生時操作完。一旦自舉完成,最初始的編譯過程就可以掃入歷史的垃圾堆,就好像從未發生過一樣了。
那么為什么一定要完成自舉,而不是使用最初始的編譯器呢?可能當我們自己去設身處地地去想一下初始編譯器的狀態,就可以大致明白了:最初的編譯器往往只在乎能正確工作,而不會考慮最優。舉一個極端的例子,Donald Knuth即便再是大牛,如果要親手編譯每個WEB程序員編寫的每個程序,那也是效率極其低下的。
一般來說,完成自舉有如下的優點:
1. 這是一種對該語言的極好的測試;
2. 編譯器的開發者只需掌握這一門語言即可,不需要再掌握其它語言;
3. 開發編譯器的環境和使用這門語言開發的所有其它程序一致;
4. 對編譯器后端的優化不僅會優化以后所有編譯出來的其它程序的效率,也會優化編譯器本身的效率。