淺聊什麼是語言自舉

語言: CN / TW / HK

高階語言都是需要進行編譯的,編譯就是把高階語言翻譯為機器指令。

就算是Java也需要編譯,這裡指的編譯不是javac,而是jit編譯器,javac負責把java程式碼編譯為JVM位元組碼,jit編譯器負責把位元組碼指令翻譯為機器指令。

我們知道jit編譯器是用c++開發的,那麼我們能不能用Java語言開發一個編譯器,然後通過它能夠把Java程式碼直接編譯成為機器指令呢?

肯定是可以的,就像C語言、Go語言一樣,它們的編譯器都是用自己的語言實現的。

能用本語言實現的編譯器對本語言進行編譯,這就是語言自舉。

編譯就是把一個用高階語言寫的字串,編譯成為機器指令的字串,這個功能基本上任何一個語言都能實現。

在Java中,GraalVM其實就完成了這個功能,GraalVM就是用Java開發的,同時它又能把Java程式碼編譯成為機器指令。

這就有點像是,先有雞還是先有蛋的問題了。

比如GraalVM,它是用Java語言開發的,相當於就是一個Java程式,可是它要執行編譯Java程式碼的的話,不得自己先編譯完才能執行嗎?

也就是,Java編譯器為了能編譯Java程式碼,自己得先編譯。

可是問題就是,這個編譯器自己該怎麼被編譯呢?

這就是語言自舉中要解決的問題。

通常,這個編譯器的第一個版本不會是本語言實現的,而是通過其他語言。

比如我先用C++寫一個Java編譯器,記做CJava編譯器,然後就可以用CJava編譯器編譯Java程式碼了,然後我又用Java程式碼寫一個Java編譯器專案,就可以利用CJava編譯器編譯這個專案,得到另外一個Java編譯器了,而後續我們只需要用這個Java編譯器就可以編譯Java程式碼了。

這樣就完成了語言自舉。

當然,如果Java語言語法上有升級,對應的編譯器也要升級,因為之前老版本的編譯器可能編譯不了新的語法,這個時候可能仍然得藉助外力,也就是用另外一門語言來編譯新的語法得對應的機器指令,比如C++。

知乎上有一個點贊不多,但是我覺得很好的比喻:

你是一個鐵匠,專門給木匠提供生產工具的鐵匠。

有一天你覺得你目前的工具製造工藝精度太低、效率不夠高,於是你決定發明機床替代打鐵和手工製作木製零件。

你手工用木頭和鐵製作了一個簡單粗糙的手動機床。

有了這臺機床之後你給木匠製作工具的效率明顯提高了。但是用了一段時間之後,你發現這臺機床的設計還是有一些不足,於是你決定開發第二版機床。

把設計圖畫好之後你開始動手了。這次你決定不用打鐵削木頭的方式製造第二版機床,而是用已經制作好的第一版機床製作大部分第二版機床的零件,只有小部分用第一代機床製作不出來的零件你手工製作。

第二代機床製作好之後你越用越順手,越來越多的木匠開始用你用機床生產的工具。為了提升效率你決定開發第三代機床。

因為第二代機床的設計比第一代機床更完善,你發現生產第三代機床的所有零件都可以直接用第二代機床製作。於是你用第二代機床生產了第三代機床。

恭喜,你達成了機床自舉。

今天初二,簡單聊聊,要去拜年了,祝大家新年快樂,不想錯過更多幹貨內容,關注公眾號:Hoeller。