《大前端開發(fā)者需要了解的基礎(chǔ)編譯原理和語言知識》讀后感

這幾天看了一篇名為《大前端開發(fā)者需要了解的基礎(chǔ)編譯原理和語言知識》摧冀,讀完之后深感作者知識面之廣,內(nèi)容之豐富梯捕,感謝作者分享如此高質(zhì)量的文章。

同時窝撵,鑒于文章內(nèi)容較多傀顾,自己寫下這篇文章,作為心得和筆記碌奉。

代碼的編譯過程往粗了說分為四個階段:1.預(yù)處理(preprocessing)2.編譯(compliation)3.匯編(assembly)4.鏈接(linking)短曾。

往細(xì)了說分為七個階段:1.預(yù)處理、2.詞法分析赐劣、3.語法分析嫉拐、4.生成中間代碼、5.生成目標(biāo)代碼魁兼、6.匯編婉徘、7.鏈接

這里面的主要區(qū)別就是編譯包括了詞法分析咐汞、語法分析盖呼、生成中間代碼和生成目標(biāo)代碼四個部分。

編譯器負(fù)責(zé)預(yù)處理化撕、詞法分析几晤、語法分析、生成中間代碼和生成目標(biāo)代碼五個步驟植阴,編譯器的輸入是源代碼锌仅,輸出是中間代碼章钾。編譯器以中間代碼為分界又分為編譯器前端編譯器后端墙贱。編譯器前端負(fù)責(zé)語法分析生成抽象語法樹(AST热芹,Abstract Syntax Tree)后端負(fù)責(zé)將抽象語法樹轉(zhuǎn)換為中間代碼惨撇。
ps:中間代碼已經(jīng)非常接近于實(shí)際的匯編代碼伊脓,它幾乎可以直接被轉(zhuǎn)化。主要的工作量在于兼容各種 CPU 以及填寫模板魁衙。此工作由編譯器或匯編器完成报腔。

主流的C/C++的編譯器有GCC,這是GNU發(fā)布的一款極具影響力的編譯器剖淀,已經(jīng)成為LinuxUnix系統(tǒng)的默認(rèn)編譯器纯蛾。從事iOS開發(fā)使用的Xcode目前用的編譯器是clang+LLVM。Xcode4之前纵隔,用的是GCC編譯器翻诉,由于GCC對Objective-C的支持不是很好,于是蘋果采用了“自家”發(fā)起的clang+LLVM作為默認(rèn)編譯器捌刮。

這兩個編譯器的主要區(qū)別是GCC直接負(fù)責(zé)整個編譯過程的五個步驟碰煌,而clang+LLVM將編譯的步驟拆分,clang作為編譯器前端還記得編譯器前端的職責(zé)么绅作?)芦圾,LLVM作為編譯器的后端兩者配合使用。當(dāng)然歷時上也曾經(jīng)出現(xiàn)過俄认,GCC作為編譯器前端个少,LLVM作為編譯器后端的搭配組合。

Xcode 3和Xcode 4時代曾經(jīng)出現(xiàn)的GCC+LLVM搭配

接下來就以細(xì)分的模塊為例眯杏,總結(jié)一下每個模塊由什么負(fù)責(zé)夜焦,分別都做了哪些工作。

1.預(yù)處理(preprocessing) —— 處理宏定義

預(yù)處理主要是處理一些宏定義役拴,比如:#define糊探、#include、**#if **等河闰。預(yù)處理的實(shí)現(xiàn)有很多種科平,有的編譯器會在詞法分析前先進(jìn)行預(yù)處理,替換掉所有 # 開頭的宏姜性,而有的編譯器則是在詞法分析的過程中進(jìn)行預(yù)處理瞪慧。當(dāng)分析到 # 開頭的單詞時才進(jìn)行替換。雖然先預(yù)處理再詞法分析比較符合直覺部念,但在實(shí)際使用中弃酌,GCC 使用的卻是一邊詞法分析氨菇,一邊預(yù)處理的方案。(以上這些內(nèi)容是我從《大前端開發(fā)者需要了解的基礎(chǔ)編譯原理和語言知識》直接粘貼過來的)

2.詞法分析 —— 輸出符號狀態(tài)

詞法分析的主要實(shí)現(xiàn)原理是狀態(tài)機(jī)妓湘,它逐個讀取字符查蓉,然后根據(jù)讀到的字符的特點(diǎn)轉(zhuǎn)換狀態(tài)。計算機(jī)不像人類可以直接識別源代碼的內(nèi)容榜贴,它只能一個一個的識別每個單詞豌研,詞法分析要做的就是把源代碼分割開,形成若干個單詞唬党,并標(biāo)記狀態(tài)為語法分析做準(zhǔn)備鹃共。比如,a=1”“a==1”驶拱,這兩個語句霜浴,計算機(jī)在從左向右識別時,識別到第一個 “=” 時并不能判定該語句是賦值符號還是條件判斷符號蓝纲,必須結(jié)合 “=” 之后的字符才能做出正確的判斷阴孟,若是 “1” 則是賦值符號,若是 “=” 則是條件判斷符號驻龟,根據(jù)識別的不同結(jié)果温眉,進(jìn)行狀態(tài)標(biāo)記。具體的案例在原文中講的很詳細(xì)翁狐,各位讀者可以參考类溢。

詞法分析.png

3.語法分析 —— 輸出抽象語法樹(AST, Abstract Syntax Tree)

詞法分析以后,編譯器已經(jīng)知道了每個單詞的意思露懒,但這些單詞組合起來表示的語法還不清楚闯冷,這時需要編譯器前端(如:GCC或者clang)進(jìn)行語法分析

實(shí)現(xiàn)語法分析的一個簡單的思路是模板匹配懈词,即將編程語言的基本語法規(guī)則抽象成模板進(jìn)行匹配蛇耀,符合相應(yīng)的模板,即對應(yīng)相應(yīng)的意思坎弯,同時生成抽象語法樹(AST, Abstract Syntax Tree)纺涤。

比如有 “int a = 10;” 語句,其實(shí)表示了這么一種通用的語法格式:
類型 變量名 = 常量;”抠忘。

而在成功解析語法以后撩炊,我們會得到抽象語法樹(AST: Abstract Syntax Tree)。

語法分析.png

以這段代碼為例:

int fun(int a, int b) {
int c = 0;
c = a + b;

return c;

}

它的語法樹如下:

抽象語法樹.jpg

語法樹將字符串格式的源代碼轉(zhuǎn)化為樹狀的數(shù)據(jù)結(jié)構(gòu)崎脉,更容易被計算機(jī)理解和處理拧咳。

4.生成中間代碼IR(Intermeidate Representation)

其實(shí)抽象語法樹可以直接轉(zhuǎn)化為目標(biāo)代碼(匯編代碼)。然而囚灼,不同的 CPU 的匯編語法并不一致骆膝,比如《AT&T與Intel匯編風(fēng)格比較》這篇文章所提到的砰嘁,Intel 架構(gòu)AT&T 架構(gòu)的匯編碼中序臂,源操作數(shù)目標(biāo)操作數(shù)位置恰好相反诊县。Intel 架構(gòu)操作數(shù)立即數(shù)沒有前綴但** AT&T 架構(gòu)有密似。因此一種比較高效的做法是先生成語言無關(guān)秀撇,CPU 也無關(guān)的中間代碼(IR)**燕酷,然后再生成對應(yīng)各個 **CPU **的匯編代碼粮揉。

生成中間代碼(IR,Intermediate Representation)是非常重要的一步膊畴,一方面它和語言無關(guān),也和 CPU 與具體實(shí)現(xiàn)無關(guān)锥涕。可以理解為中間代碼是一種非常抽象狭吼,又非常普適的代碼层坠。它客觀中立的描述了代碼要做的事情,如果用中文刁笙、英文來分別表示** C Java 的話破花,中間碼某種意義上可以被理解為世界語**。

另一方面疲吸,中間碼編譯器前端后端的分界線座每。編譯器前端負(fù)責(zé)把源碼轉(zhuǎn)換成中間代碼(IR)編譯器后端負(fù)責(zé)把中間碼轉(zhuǎn)換成目標(biāo)代碼(匯編代碼)摘悴。
抽象語法樹生成中間碼(IR)的過程大體上分為兩步峭梳,第一步是生成中間碼(IR),第二步是將中間碼(IR)最佳化蹂喻。

抽象語法樹轉(zhuǎn)中間碼.png

中間碼最佳化.png

以** GCC** 為例葱椭,生成中間代碼可以分為三個步驟:(
1.語法樹轉(zhuǎn)高端 gimple
2.高端 gimple 轉(zhuǎn)低端 gimple
3.低端 gimple 經(jīng)過 cfa 轉(zhuǎn) ssa 再轉(zhuǎn)中間代碼

注:使用Xcode 進(jìn)行iOS 客戶端開發(fā)時,LLVM 負(fù)責(zé)將抽象語法樹轉(zhuǎn)為中間碼(IR)口四。

** Gimple** 是GCC編譯器產(chǎn)生的一種包含最多三個操作數(shù)的中間指令孵运,也就是編譯原理里講的四元碼(三個操作數(shù),一個操作符)蔓彩,基本上也就是 dst = src1 @ src2 的這種形式治笨。由于** Gimple** 最多只能對兩個操作數(shù)進(jìn)行計算,因此一個復(fù)雜的表達(dá)式會展開為一系列的** Gimple** 指令赤嚼,這一過程就是** Gimple** 化旷赖。

4.1 語法樹轉(zhuǎn)高端 Gimple

語法樹轉(zhuǎn)高端 Gimple,主要是處理寄存器探膊,比如:“ c = a + b” 并沒有直接的匯編代碼與之對應(yīng)杠愧,一般來說需要把 a + b 的結(jié)果保存到寄存器中,然后再把寄存器賦值給 c逞壁。另外流济,調(diào)用一個新的函數(shù)時會進(jìn)入到函數(shù)自己的棧锐锣,建棧的操作也需要在 Gimple 中聲明。

4.2 高端 Gimple轉(zhuǎn)低端Gimple

高端 Gimple轉(zhuǎn)低端 Gimple绳瘟,主要是把變量定義雕憔,語句執(zhí)行返回語句區(qū)分存儲,分配椞巧空間斤彼。
比如:

int a = 1;
a++;
int b = 1;

會被處理成:

int a = 1;
int b = 1;
a++;

這樣做的好處是很容易計算一個函數(shù)到底需要多少棧空間蘸泻。

此外琉苇,return 語句會被統(tǒng)一處理,放在函數(shù)的末尾悦施,比如:

if (1 > 0) {
return 1;
}
else {
return 0;

}

會被處理成:

if (1 > 0) {
goto a;
}
else {
goto b;
}
a:
return 1;
b:
return 0;

4.3 低端Gimple轉(zhuǎn)中間代碼

這一步主要是進(jìn)行各種優(yōu)化并扇,添加版本號等。

5.生成目標(biāo)代碼(匯編代碼)

目標(biāo)代碼也可以叫做匯編代碼抡诞。由于中間碼已經(jīng)非常接近于實(shí)際的匯編代碼穷蛹,它幾乎可以直接被轉(zhuǎn)化。主要的工作量在于針對不同的CPU生成不同的匯編代碼昼汗,兼容各種 CPU 以及填寫模板肴熏。在最終生成的匯編代碼中,不僅有匯編命令顷窒,也有一些對文件的說明蛙吏。

生成目標(biāo)代碼.png

6.匯編(assembly)——匯編器生成二進(jìn)制機(jī)器碼

匯編器會接收匯編代碼,將它轉(zhuǎn)換成二進(jìn)制機(jī)器碼蹋肮,生成目標(biāo)文件(后綴是 .o)出刷,機(jī)器碼可以直接被 CPU 識別并執(zhí)行。由于目標(biāo)代碼是分段的坯辩,最終的目標(biāo)文件(機(jī)器碼)也是分段的馁龟。這是因為:

  1. 數(shù)據(jù)和代碼區(qū)分開。其中代碼只讀漆魔,數(shù)據(jù)可寫坷檩,方便權(quán)限管理,避免指令被改寫改抡,提高安全性矢炼。
  2. 現(xiàn)代 CPU 一般有自己的數(shù)據(jù)緩存和指令緩存,區(qū)分存儲有助于提高緩存命中率阿纤。
  3. 當(dāng)多個進(jìn)程同時運(yùn)行時句灌,他們的指令可以被共享,這樣能節(jié)省內(nèi)存。

7.鏈接(linking)

鏈接就是將目標(biāo)文件(.o文件)與其中調(diào)用的外部函數(shù)所在的目標(biāo)文件通過重定位關(guān)聯(lián)起來胰锌。

在一個目標(biāo)文件中骗绕,不可能所有變量函數(shù)都定義在文件內(nèi)部。比如** strlen 函數(shù)就是一個被調(diào)用的外部函數(shù)资昧,此時就需要把 main.o 這個目標(biāo)文件和包含了 strlen 函數(shù)實(shí)現(xiàn)的目標(biāo)文件鏈接起來酬土。我們知道函數(shù)調(diào)用對應(yīng)到匯編其實(shí)是 jump 指令,后面寫上被調(diào)用函數(shù)的地址格带,但在生成 main.o 的過程中撤缴, strlen() 函數(shù)的地址并不知道,所以只能先用 0 來代替叽唱,直到最后鏈接**時屈呕,才會修改成真實(shí)的地址。

鏈接器就是靠著重定位表來知道哪些地方需要被重定位的尔觉。每個可能存在重定位的段都會有對應(yīng)的重定位表凉袱。在鏈接階段鏈接器會根據(jù)重定位表中侦铜,需要重定位的內(nèi)容,去別的目標(biāo)文件中找到地址并進(jìn)行重定位钟鸵。

有時候我們還會聽到動態(tài)鏈接這個名詞钉稍,它表示重定位發(fā)生在運(yùn)行時而非編譯后。動態(tài)鏈接可以節(jié)省內(nèi)存棺耍,但也會帶來加載的性能問題贡未,這里不詳細(xì)解釋,感興趣的讀者可以閱讀《程序員的自我修養(yǎng)》這本書蒙袍。(以上是從《大前端開發(fā)者需要了解的基礎(chǔ)編譯原理和語言知識》直接粘貼過來的)

寫在最后

最后十分感謝《大前端開發(fā)者需要了解的基礎(chǔ)編譯原理和語言知識》的作者能夠貢獻(xiàn)如此高質(zhì)量的一篇文章俊卤,講清楚了整個編譯過程中的細(xì)節(jié)。本文有大量內(nèi)容是直接從該文章中復(fù)制過來害幅,最終的版權(quán)歸原作者所有消恍,本人只是作為一個讀后筆記寫下本文,若有侵權(quán)的地方以现,煩請告知狠怨。
參考文獻(xiàn)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市邑遏,隨后出現(xiàn)的幾起案子佣赖,更是在濱河造成了極大的恐慌,老刑警劉巖记盒,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件憎蛤,死亡現(xiàn)場離奇詭異,居然都是意外死亡纪吮,警方通過查閱死者的電腦和手機(jī)俩檬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門萎胰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人豆胸,你說我怎么就攤上這事奥洼。” “怎么了晚胡?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵灵奖,是天一觀的道長。 經(jīng)常有香客問我估盘,道長瓷患,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任遣妥,我火速辦了婚禮擅编,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘箫踩。我一直安慰自己爱态,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布境钟。 她就那樣靜靜地躺著锦担,像睡著了一般。 火紅的嫁衣襯著肌膚如雪慨削。 梳的紋絲不亂的頭發(fā)上洞渔,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天,我揣著相機(jī)與錄音缚态,去河邊找鬼磁椒。 笑死,一個胖子當(dāng)著我的面吹牛玫芦,可吹牛的內(nèi)容都是我干的浆熔。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼姨俩,長吁一口氣:“原來是場噩夢啊……” “哼蘸拔!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起环葵,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤调窍,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后张遭,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體邓萨,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了缔恳。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宝剖。...
    茶點(diǎn)故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖歉甚,靈堂內(nèi)的尸體忽然破棺而出万细,到底是詐尸還是另有隱情,我是刑警寧澤纸泄,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布赖钞,位于F島的核電站,受9級特大地震影響聘裁,放射性物質(zhì)發(fā)生泄漏雪营。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一衡便、第九天 我趴在偏房一處隱蔽的房頂上張望献起。 院中可真熱鬧,春花似錦镣陕、人聲如沸谴餐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽总寒。三九已至,卻和暖如春理肺,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背善镰。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工妹萨, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人炫欺。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓乎完,卻偏偏與公主長得像,于是被迫代替她去往敵國和親品洛。 傳聞我的和親對象是個殘疾皇子树姨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 一、以 Hello World開篇 Hello World對程序員而言肯定是如雷貫耳桥状。但是簡單的事物背后往往包含這...
    ZhengYaWei閱讀 8,467評論 10 84
  • 前言 2000年帽揪,伊利諾伊大學(xué)厄巴納-香檳分校(University of Illinois at Urbana-...
    星光社的戴銘閱讀 15,861評論 8 180
  • TITLE: 編程語言亂燉 碼農(nóng)最大的煩惱——編程語言太多。不是我不學(xué)習(xí)辅斟,這世界變化快转晰! 有時候還是蠻懷念十幾、二...
    碼園老農(nóng)閱讀 5,295評論 2 35
  • 又是一年 鄉(xiāng)土難離 燈火燭光 鳥兒紛飛 故鄉(xiāng)夢里 推開舊窗 緣來淚水 那些年歲 習(xí)慣城市高墻 紅葉隨風(fēng)流浪 沒有山...
    是為一閱讀 227評論 0 0
  • 姑娘們約酒蔗崎,沒有心情不好,沒有其他意思扰藕,就是想單純聚聚缓苛,這有什么理由讓人拒絕? 我們都是以前的同事邓深,那時候的工作環(huán)...
    蘇穆涼閱讀 201評論 0 0