源程序的编译过程
內容來自<<程序員的自我修養-鏈接,加載和庫>> 非常好的書.
編譯過程一般分為6個步驟:
掃描:
源代碼程序被輸入到掃描器(Scanner),掃描器的任務很簡單,他只是進行詞法分析,將源碼中的字符序列分割成一系列記號;
詞法分析產生的記號一般可以分為如下幾類: 關鍵字,標識符,字面量(數字字符串等),和特殊符號(如 加號 ,減號等).在掃描器識別記號的同時,也完成了其他的工作.比如將標識符存放在符號表,將數字,字符串常量存放到文字表等,以備后面的步驟使用.(對于一些有預處理的語言,如c語言,它的宏替換和頭文件包含等工作一般不歸如編譯器的范圍,而交給一個獨立的預處理器)
語法分析:
接下來語法分析器(Grammar Parser) 將由掃描器產生的記號進行語法分析,從而產生語法樹(Syntax tree).整個過程采用了上下文無關(context-free Grammar) 的分析手段.由語法分析器產生的語法樹就是以表達式為節點的樹.我們知道C語言的一個語句是一個表達式,而復雜的語句是很多表達式的組合.在語法分析的同時,很多富豪的優先級和含義也被確定下來了.(比如* 好是表示乘法表達式,還是表示對指針內容取值等).如果出現表達式不合法,比如括號不匹配等,編譯器就會報告語法分析階段的錯誤
語法分析也由一個現成的獨立工具叫做yacc.對于不同的編程語言,編譯器的開發者只需改變語法規則,而無需為編譯器編寫一個語法分析器.
語義分析:
接下來是語義分析.有語義分析器(Semantic Analyzer)來完成.與法分析僅僅是完成了對表達式的語法層面的分析,但是它并不了解這個語句是否正真有意義.比如C語言里面兩個指針做乘法運算是沒意義的,但是這個語句在語法上是合法的.
編譯器所能分析的語義是靜態語義(static semantic),所謂靜態語義是指在編譯期可以確定的語義,預支對應的動態語義就是指只有在運行期才能確定的語義.
靜態語義通常包括聲明和類型匹配,類型裝換.比如一個浮點型的表達式復制給一個整形表達式時,其中隱含了一個浮點型到整形的轉換過程,語義分析過程需要完成這個步驟.比如將一個浮點型復制給一個指針的時候,語義分析程序會發現這個類型不匹配,編譯器就會報錯.動態語義一般是指在運行期間出現的語義相關的問題,比如將0作為除數是一個運行期語義錯誤.
經過語義分析后,整個語法書的表達式都背標識餓類型,如果這些類型需要做隱式轉換,語義分析程序會在語法書中插入相應的轉換節點.
源代碼優化:
現代編譯器有著很多層次的優化,往往子啊源代碼級別會有一個優化過程.這里描述的源代碼級優化器在不同的編譯器中可能會有不同的定義域或者有其他的一些差異.列如: 在上面的(2+6)這個表達式可以被優化掉(被優化成8).因為它的值在編譯期就可以被確定.類似的還有很多其他復雜的優化過程.直接在語法樹上做優化比較困難,語義源代碼優化器往往將整個語法書轉換成中間代碼,它是語法書的順序表示,其實它已經非常接近目標代碼了.大師它一般跟目標機器運行和運行是環境是無關的,比如他不包含數據的尺寸,變量的地址和寄存器的名字.
中間代碼使得編譯器可以被分為前端和后端.編譯器前端負責產生機器無關的中間代碼,編譯器后端將中間代碼轉換成目標機器代碼.這樣對于一些可跨平臺的編譯器而言,它們可以正對不同的平臺使用同一個前端,和針對不同的機器平臺的數個后端.
目標代碼生成:
源代碼優化器產生中間代碼標志著下面的過程都屬于編譯器后端.編譯器后端主要包括代碼生成器(Code Generator) 和目標代碼優化器(Target Code Optimizer).
代碼生成器將中間代碼轉換成目標機器代碼,這個過程十分依賴于目標機器,因為不同的機器有著不同的字長,寄存器,整數數據類型和浮點數數據類型.
目標代碼優化: ?
最后目標代碼優化器對目標代碼進行優化,比如選擇合適的尋址方式沒使用位移來替代乘法運算,刪除多余的指令等.
連接:
連接的主要內容就是把各個模塊之間的互相引用的部分處理好,使得各個模塊之間能夠正確的銜接.從原理上來講就是把一些指定對其他符號地址的引用加以修正.連接的過程主要包括了地址分配(Address and storage? Allocate ) ,符號決議(Symbol Resolution) 和重定位(Relocation) 等步驟.?
總結
- 上一篇: 10天学会avr单片机和c语言,郭天祥十
- 下一篇: idea统计代码量