|
【 聲明:版權(quán)所有,歡迎轉(zhuǎn)載,請勿用于商業(yè)用途。 聯(lián)系信箱:feixiaoxing @163.com】
編譯器一直是我比較喜歡的話題。編譯器是個比較神奇的工具,它可以把原來毫無意義的字符數(shù)據(jù)轉(zhuǎn)變成一行一行可以執(zhí)行的代碼。作為每一個科班出身的同學(xué)來說,編譯原理都是專業(yè)學(xué)習(xí)中必須經(jīng)歷的一個部分。只是在后來的工作中,真正從事編譯器開發(fā)的同學(xué)少之又少,但是如果你懂得了編譯原理的相關(guān)機理,會給你的工作帶來很大的幫助。關(guān)于編譯原理的書很多,網(wǎng)上可以搜一下有阿霍版本的《編譯原理》,有陳火旺院士的《編譯原理》,張素琴版本的《編譯原理》,三本書我都覺得不錯。另外,現(xiàn)在關(guān)于編譯原理也有很多的開發(fā)工具,比如說lex&yacc,只要你會編寫基本的語法范式,設(shè)計自己的編譯器也不是什么難事。
其實,現(xiàn)在的編譯器早已經(jīng)突破了原來的概念。比如說,編譯器最終的代碼不一定在實際機器上運行,可能是虛擬機;編譯器編譯語言時不一定需要生成可執(zhí)行文件,能解釋就行;編譯器最好并行編譯;編譯器不一定很大,可能十幾個文件就可以,比如說lua等等。不過,我們今天說的編譯器還是比較傳統(tǒng)的c編譯器,有興趣的同學(xué)可以看看編譯器是怎么幫助我們生成可執(zhí)行文件的。我們按照詞法、語法、語義、優(yōu)化的順序逐一展開?,F(xiàn)在假設(shè)有這樣一段代碼,
(1)詞法分析
詞法分析是整個文件編譯最基本的環(huán)節(jié)。上面的文件中就存在很多的字符,那我們就需要分別對它們進行處理。比如說,通常的分類很可能是這樣的, a)字符是否是數(shù)字,例如7,1,4 b)字符是否是string類型,例如“p = %d” c)字符是否是關(guān)鍵字,例如define d)字符是否是變量,例如value,argc, argv, p e)字符是否是運算符, 例如 + f)字符是否是圓括號、方括號、花括號等等
(2)語法分析
語法分析的目的就是構(gòu)建一個語法樹,分析當(dāng)前的文件是否符合編程語言的文法結(jié)構(gòu),比如說, a)整個字符串是否符合表達式要求 b)字符串是否符合判斷語句要求 c)字符串是否符合循環(huán)語句要求 d)字符串是否符合函數(shù)要求 e)字符串是否符合include語法要求 f) 有沒有沒有未聲明就是用的變量等等;
(3)語義分析
語義分析有的時候和語法分析是聯(lián)系在一起的。但是,這里我們把它拆開來單獨成了一部分。所謂的語義分析,其實就是把前面生成的語法樹拆解下來,生成原子語句操作的過程。比如說,上面的文件很可能是這樣的形式,
a)SET值為函數(shù)參數(shù) b)call為函數(shù)調(diào)用 c)pop為堆棧平衡使用 d)數(shù)據(jù)[inner],表示當(dāng)前變量是函數(shù)中的臨時變量 e)數(shù)據(jù)[param],表示當(dāng)前變量是入?yún)?shù) f)temp表示編譯器為了自身計算方便,臨時添加的局部變量 g)result表示返回值
(4)代碼優(yōu)化
代碼優(yōu)化是編譯器處理的一個重要環(huán)節(jié),代碼優(yōu)化的目的主要是減少不必要的計算和處理,比如 a)計算沒有使用價值的臨時變量 b)除去沒有判斷價值的if語句 c)對于某些const變量,編譯器提前計算,這里就可以對temp1提前計算 d)其他優(yōu)化措施等等
(5)生成匯編代碼
在(3)中生成的代碼只是中間代碼,并不是完全意義上的匯編語言。所以,編譯器還需要把它翻譯成對應(yīng)的二進制代碼,比如說arm語言、x86語言或者是powerpc語言等等。當(dāng)然這中間還是存在一些技巧的,比如 a)對于多參數(shù)的函數(shù),某些cpu可以用寄存器代替,有些cpu用堆棧表示 b)某些cpu需要對字節(jié)對齊,某些cpu則不需要 c)某些cpu有字節(jié)序的要求,某些cpu則無所謂,而有的cpu則可選 d)對于臨時變量,有的cpu可以寄存器表示,而有的cpu只能自己生成一個temp變量等等,
說到這里,我們也可以自己小試一下身手,看看代碼怎么生成,熟悉x86代碼的同學(xué)也可以自己試試,
(6)匯編級代碼優(yōu)化
這里的優(yōu)化其實還挺多的,但是功能基本有限,無外乎就是, a)乘法轉(zhuǎn)變成移位 b)除法轉(zhuǎn)變成移位 c)寄存器優(yōu)化使用 d)刪除寄存器的重復(fù)操作過程 e)部分函數(shù)參數(shù)用寄存器代替等等
(7)鏈接和生成可執(zhí)行文件
在編譯過程中,我們常??吹接行┐a編譯通過了,但是鏈接失敗了。這是很正常的事情,因為在最后生成的文件當(dāng)中,每一個變量和函數(shù)都應(yīng)該有出處,否則就會鏈接失敗。不管是什么系統(tǒng)平臺,鏈接都是個大學(xué)問。這個時候,做的事情其實還是比較多的,比如 a)生成執(zhí)行文件,確定是否帶調(diào)試信息 b)鏈接所有的變量和代碼 c)生成map文件 d)確定函數(shù)和變量的出處,一旦查找失敗,結(jié)束 e)調(diào)整變量和函數(shù)代碼的位置,填寫文件結(jié)構(gòu),生成最終可執(zhí)行文件 |
|
|