小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

隨想錄(編譯器是怎么工作的)

 londonKu 2012-05-06

【 聲明:版權(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. #include <stdio.h>  
  2.   
  3. #define MAX_VALUE 7  
  4. int test(int value)  
  5. {  
  6.     return MAX_VALUE + 1 + value * 4;  
  7. }  
  8.   
  9. int main(int argc, char* argv)  
  10. {  
  11.     int p;  
  12.     p = test(3);  
  13.     printf("p = %d", p);  
  14.     return 1;  
  15. }  

   

    (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)系在一起的。但是,這里我們把它拆開來單獨成了一部分。所謂的語義分析,其實就是把前面生成的語法樹拆解下來,生成原子語句操作的過程。比如說,上面的文件很可能是這樣的形式,

  1. SET value  
  2. mov temp1[inner], 7  
  3. add temp1[inner], 1  
  4. mul temp2,value[param], 4  
  5. add temp1, temp2  
  6. mov result, temp1  
  7. pop  
  8.   
  9.   
  10. SET argc[param]  
  11. SET argv[param]  
  12. SET 3  
  13. call test  
  14. pop   
  15. get result  
  16. mov p[inner], result  
  17. SET p  
  18. SET string "p = %d"  
  19. pop  
  20. pop  
  21. mov result, 1  
  22. pop  
  23. pop  
    這里需要解釋一下,語義轉(zhuǎn)換的結(jié)構(gòu)和形式其實是各個編譯器自己定義的,未必有通用的結(jié)構(gòu)。這里的語句只是我自己想出來的,可能和實際的形式有很大的出入,但是基本方法應(yīng)該是一樣的。主要解釋如下,

    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é)也可以自己試試,

  1. push ebp  
  2. mov ebp, esp  
  3. push ebx  
  4. push ecx  
  5. mov ebx, 8  
  6. mov ecx, ebp[8]  
  7. mul ecx, 4  
  8. add ebx, ecx  
  9. mov eax, ebx  
  10. pop ecx  
  11. pop ebx  
  12. mov esp, ebp  
  13. pop ebp  
  14.   
  15.   
  16. push ebp  
  17. mov ebp, esp  
  18. sub esp, 0x4  
  19. push 3  
  20. call test  
  21. add esp 4  
  22. mov ebp[-4], eax  
  23. push ebp[-4]  
  24. push string "p = %d"  
  25. call printf  
  26. add esp, 8  
  27. mov eax, 1  
  28. sub esp, 0x4  
  29. mov esp, ebp  
  30. pop ebp  
     

    (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í)行文件

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多