c语言编译器好玩的代码,读懂这4个函数,528行代码,你也可以实现一个C语言编译器...
引言
自從華為方舟編譯器橫空出世,一舉成為全民網紅之后,一下子點燃了大家對編譯器的熱情。不過,對于大多數人來說,編譯器依舊是遙不可及的神秘存在。
今天,介紹一個國外大牛寫的C語言編譯器 - C4,揭開編譯器的神秘面紗。原來實現一個具備基本功能的編譯器,竟是如此簡單!
C4:4個函數實現的C語言編譯器
C4, C in four functions。
它是一個C語言編譯器項目(項目地址在文末),整個實現只有:
一個C語言源碼文件528行C語言代碼4個函數
僅此而已。
讀懂這4個函數,528行代碼,你也可以實現一個C語言編譯器-1.jpg (34.72 KB, 下載次數: 0)
2020-7-17 12:33 上傳
C4代碼倉庫
它簡潔,卻不簡單。
它具備完整的詞法分析、語法分析、簡單的語義檢查、代碼生成、運行時環境(即虛擬機)。
與常見的C編譯器不同的是,它把C語言源程序編譯成字節碼(bytecode),然后在一個精簡的虛擬機中解釋執行。
你以為這樣就完了?不,它令人稱道之處遠不止如此!
C4:可以自舉的C語言編譯器
若只是精簡,或許它還并不那么令人驚奇,畢竟網上有很多類似的編譯器項目,其中不乏一些非常簡單優雅,且非常出色的項目。
然而,C4最驚艷的地方是,它可以自舉。
所謂自舉,簡單來說,就是自己編譯自己。當然,最初始的那個C4編譯器的可執行文件,還是必須要通過GCC、Clang等編譯器進行編譯生成。
我們下面演示一下“Hello, World!”的例子,和C4自舉的例子。
Hello, World示例
先用GCC把C4編譯成可執行文件:
gcc??c4.c??-o??c4
運行“Hello, World!”測試程序hello.c:
讀懂這4個函數,528行代碼,你也可以實現一個C語言編譯器-2.jpg (12.31 KB, 下載次數: 0)
2020-7-17 12:33 上傳
結果如圖:
讀懂這4個函數,528行代碼,你也可以實現一個C語言編譯器-3.jpg (34.83 KB, 下載次數: 0)
2020-7-17 12:33 上傳
其中,“hello, world”是hello.c 輸出的,“exit(0) cycle = 9”是c4編譯器輸出的,表示程序正常運行結束,hello.c一共生成9條指令。
C4的自舉示例
我們用GCC編譯c4.c生成了可執行文件c4,我們稱之為編譯器A,然后用編譯器A來編譯c4的源碼c4.c,則生成一個編譯器B,然后再用編譯器B來編譯執行hello.c。
命令如下:
./c4 c4.c hello.c
結果如圖:
讀懂這4個函數,528行代碼,你也可以實現一個C語言編譯器-4.jpg (38.96 KB, 下載次數: 0)
2020-7-17 12:33 上傳
C4自舉執行
還可以這樣:
./c4??c4.c??c4.c??hello.c
也就是GCC編譯生成的c4是編譯器A,./c4 c4.c生成的是編譯器B, ./c4 c4.c c4.c編譯生成的則是編譯器C,最后用編譯器C來編譯運行hello.c。
讀懂這4個函數,528行代碼,你也可以實現一個C語言編譯器-5.jpg (34.62 KB, 下載次數: 0)
2020-7-17 12:33 上傳
C4遞歸自舉
理論上可以一直遞歸下去。只不過,從圖中可以看出,遞歸的層次越深,生成的字節碼越多,執行所需的時間也越多。
C4實現的C語言子集
C4致力于用最少的代碼,實現一個可以自舉的C編譯器。它的整個實現只有4個函數組成,可想而知,它不可能完整的實現整個C語言的規范,它只實現了C語言的一個子集。
數據類型
char int 指針 枚舉(enum) 數組 字符串
不支持struct、typedef、union等數據類型。
語句結構
if-else控制語句while循環語句return語句函數
不支持do-while、switch-case、for、continue、break、goto等語句結構。
運算符
它支持除+=、%=、<<=、&=等符合運算符之外的幾乎所有運算符。包括:
算術運算符關系運算符邏輯運算符位運算符賦值運算符雜項運算符(如三元運算符?:)
內建庫函數
C4編譯器實現時用到了一些系統庫函數,因此,為了實現自舉,它也內建支持了幾個庫函數。包括:
open、read、close、printf、malloc、free、memset、memcmp、exit
需要注意的是,它不支持以#開頭的預處理命令,如#include、#define、#if等。
代碼注釋只支持“//”開頭的單行注釋,不支持“/* */”標記的多行注釋形式。
與傳統的C語言編譯器相比,C4在實現上有其獨到之處。
下面,先簡單介紹一些傳統編譯器的實現過程。
傳統典型編譯器的實現
典型的編譯器的實現,一般都會有下面幾個過程:
詞法分析語法分析語義分析中間代碼生成代碼優化機器代碼生成
如GCC、Clang、華為方舟編譯器等均是如此。
讀懂這4個函數,528行代碼,你也可以實現一個C語言編譯器-6.jpg (30.59 KB, 下載次數: 0)
2020-7-17 12:33 上傳
這些階段,會對代碼進行多次掃描。這里的代碼,包括文本形式的源代碼、語法樹、中間代碼等表示形式。
典型的實現中,詞法分析和語法分析通常會糅合在一起,在語法分析時,調用詞法分析器逐個取得token。因此,理論上講,詞法分析和語法分析階段,只需要對源碼掃描一遍即可,并生成語法樹,有時也叫抽象語法樹(Abstract Syntax Tree)。
語義分析階段操作的主要對象就是這棵樹,至少要對這棵樹掃描一遍。有些實現中,在進行語義檢查的同時也會直接生成中間代碼。
在代碼優化階段,根據編譯器優化的力度的不同,可能會對中間代碼進行多次掃描。
這里所謂的“掃描一遍”,在編譯器術語中一般稱為pass。對LLVM有了解的朋友應該知道,LLVM中每一種類型的優化都是一個pass,要應用多種優化技術,就需要有多個pass。
C4的獨具特色之處
作為追求極簡主義的C4編譯器來說,它在實現上有很多獨具特色之處。
對C源碼解釋執行
傳統的C語言編譯器,最終都把C語言源碼編譯成可執行文件,也就是二進制的機器碼。
而C4則是把C語言源碼先編譯成其專門設計的字節碼(bytecode),然后直接在虛擬機中解釋執行。
C4設計了39個字節碼指令,其中大部分與匯編語言中的指令有些類似,主要是內存加載指令,算術運算指令等,此外,還包含了為支持內建的庫函數而專門設計的9條特殊的庫函數調用指令。
它的虛擬機是典型的棧式虛擬機(Java虛擬機也是典型的棧式虛擬機,早期的Lua也是棧式虛擬機,但最新的Lua 5.x采用寄存器虛擬機)。
我們可以使用-d命令,把生成的字節碼dump出來。下圖是hello.c的字節碼:
讀懂這4個函數,528行代碼,你也可以實現一個C語言編譯器-7.jpg (35.49 KB, 下載次數: 0)
2020-7-17 12:33 上傳
對源碼只掃描一遍
與傳統的編譯器實現不同,C4它把詞法分析、語法分析、語義分析、代碼生成這幾個步驟巧妙的結合在一起,在把C語言源碼編譯成字節碼的整個過程中,只掃描了一遍源碼。
Lua的解釋器也是采用對源碼掃描一遍的方式,因此,C4和Lua的性能都相當不錯。
C4源碼的可讀性
對于C4的實現,網上也有一些討論。有人認為C4的實現非常簡潔、易讀,也有人認為C4的實現稍顯晦澀。
我個人認為,C4的實現確實非常簡潔,畢竟只有4個函數,500多行代碼。但是要真正完全理解,需要有一定的編譯原理基礎知識。
比如C4的語法分析過程中,就是典型的遞歸下降和算符優先算法相結合的實現方式。只要了解這些編譯器的經典算法原理,C4的實現邏輯理解起來,還是比較輕松的。
讀懂這4個函數,528行代碼,你也可以實現一個C語言編譯器-8.jpg (39.14 KB, 下載次數: 0)
2020-7-17 12:33 上傳
此外,C4為了追求以最少的代碼實現自舉,在實現上采用了一些技巧。
比如,我們前面提到,C4不支持struct類型。這也意味著C4的源碼中不能使用struct類型。為此,它選擇使用數組來模擬struct結構。這樣乍看起來,可能會產生一些困惑。
個人認為,C4的一個槽點,就是它變量的命名上,過于簡潔。比如標記字節碼的位置的變量用e表示,其實如果用emit的話,就會清晰許多,也會更容易理解。
C4的衍生實現
除了C4的原生實現外,網上也有很多基于C4的衍生實現。
比如有人給C4額外增加了80多行代碼,卻給C4添加了JIT功能,使得執行速度得到明顯提升。
也有人對C4做了簡單修改,使得它可以直接產生真實的機器碼,并最終生成ELF可執行文件。
這些都是非常有趣的項目,都很值得研究。
C4的項目地址
在github上,找到用戶名為rswier的大牛,就可以看到C4的項目了。
讀懂這4個函數,528行代碼,你也可以實現一個C語言編譯器-9.jpg (10.81 KB, 下載次數: 0)
2020-7-17 12:33 上傳
結語
現代的編譯器項目,如GCC和Clang/LLVM,它們實現邏輯非常復雜,代碼規模巨大,一個人幾乎不可能完全搞清楚。即便是網上備受推崇的精簡實現TCC和LCC,它們的實現也相對比較復雜的,作為一個新手來說,也很難徹底研究清楚。
而C4的實現,只有四個函數,500多行源碼,個人認為是非常適合新手研究的一個項目。當然了,研究之前,最好具備一些編譯器的基礎知識,那樣理解起來就會比較容易了。
讀懂這4個函數,528行代碼,你也可以實現一個C語言編譯器-10.jpg (50.57 KB, 下載次數: 0)
2020-7-17 12:33 上傳
本文只介紹了C4編譯器項目的一些背景知識,并沒有對C4的實現做過多探討。感興趣的朋友可以到github上面找到它,仔細研究一下,相信你會有不少收獲!
如果對C4的代碼實現感興趣,或者有疑問的話,歡迎留言討論!感興趣的朋友多的話,我可以考慮更新幾篇文章,詳細講解一下C4的代碼實現。
原創不易,覺得有用的話,別忘了點贊!謝謝!
對編譯器、OS內核、性能調優、虛擬化等技術感興趣的童鞋,歡迎右上角關注!
版權聲明:未經允許,禁止轉載。文中部分圖片來源網絡,如有侵權,請通知刪除!
總結
以上是生活随笔為你收集整理的c语言编译器好玩的代码,读懂这4个函数,528行代码,你也可以实现一个C语言编译器...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java面试宝典app_Java面试宝典
- 下一篇: 信息论与编码冯桂周林著答案_信息论与编码