1.是什麼(編譯器是什麼) 2.爲何 (爲何須要編譯器) 3.怎麼作 (編譯器如何工做)前端
在編譯器工做以前須要進行預處理,包括宏的替換,頭文件的導入,以及相似#if的處理 編譯器是一種把源程序語音翻譯成目標程序語言的計算機程序。通常來講,源程序是高級語言好比Java,Objective-C等。 目標程序語言通常就是彙編語言或者二進制碼。java
編譯器通常由前端和後端組成。objective-c
前端主要進行和源語言相關,和目標語言無關的工做,包括詞法分析,語法分析,語義分析,中間碼生成。 後端主要進行和源語言無關,可是和目標語言有關的工做,好比中間碼優化,將中間碼轉化成目標碼,對目標代碼優化生成目標程序。算法
端 | 編譯器階段 | 生成產物 | 功能 | 用途 |
---|---|---|---|---|
前端 | 詞法分析 | 單詞流 | 語法高亮 | 語法高亮 |
前端 | 語法分析 | AST(抽象語法樹) | 語法高亮,代碼格式化,語法檢查 | OCLint |
前端 | 中間碼生成 | 中間碼 |
天然語言最容易表述人們的要求,當用戶用天然語言表述了須要的功能後,編譯器將高級編程語言轉換成彙編、由彙編到機器碼,提升軟件開發的效率express
在命令行輸入clang -ccc-print-phases main.m編程
1: preprocessor, {0}, objective-c-cpp-output
2: compiler, {1}, ir
3: backend, {2}, assembler
4: assembler, {3}, object
5: linker, {4}, image
6: bind-arch, "x86_64", {5}, imag
複製代碼
將源文件的字符串,進行過濾,去除空格,註釋等,而後將其分割成一個個的詞(記號、token) 好比 int a = b + sum(1,2);
會拆分紅12個token後端
int 類型標識符
a 標識符
= 賦值運算符
b 標識符
+ 加號
sum 標識符
( 左括號
1 整數
, 逗號
2 整數
) 右括號
; 分號
複製代碼
詞法分析以後,字符流已經被轉化爲token流了 int<int> ID<a> '=' ID<value> '+' ID<sum> '(' Num<1> ',' Num<2> ')' ';'
上面的int表示一個標識符類型的token。內容爲'int'bash
接下來,解析這個token流,首先這是一個語句,咱們主要有用到4種語句,賦值語句,函數調用語句,if和while語句。很明顯,這是一個賦值語句。架構
賦值表達式用變量名、賦值符號= 和表達式構成。編程語言
將語法結構應用到token流上,把等號兩邊的內容放到對應的節點上,生成語法樹以下:
接下來對expression<b+sum(1,2)>
進行解析 表達式有不少種,變量表達式,數字表達式,加減法表達式,通過對比,只有加法表達式結構才能匹配,因而將加法表達式的語法結構應用到其中。如圖
進一步解析語法樹的<b>
和<sum(1,2)>
,發現只有變量表達式和函數調用表示式才能匹配成功,獲得
接下來進行語法優化,有些節點是多餘的,好比在複製表達式中 '='和';',對語法樹進行濃縮獲得最終的抽象語法樹(AST)
由此看出,語法分析就是不斷將語法規則用於源程序,將源程序解析成一顆抽象語法樹。以後的語義分析,中間碼生成和代碼優化都是基於對這棵樹進行遍歷,檢查,修改進行的。
語義分析階段,會對語法進行屢次的遍歷,進行語法檢查,包括類型和聲明的檢查,OClint就是基於語義分析進行靜態代碼分析的。 仍是以上面的賦值語句做爲例子, 須要檢查 1.b, sum是否已經聲明過 2.sum函數的參數數量和類型是否和傳入的參數數量和類型匹配。 3.加法運算的兩個操做數的類型是否匹配,這裏也就是檢查函數的返回值類型了 4.賦值運算的兩個操做數類型是否匹配
通常在遍歷語法樹過程當中,遇到的變量聲明和函數聲明時,會將變量名-類型,函數名-返回類型-參數數量-參數類型保存到符號表裏,當遇到使用變量和函數調用時,根據名稱在符號表猴子那個查找,檢查是否聲明過,類型是否匹配。所以,對於java這種函數聲明能夠放在使用位置後面的語言,至少須要遍歷兩遍語法樹。
語義檢查時,也會對語法樹進行優化,好比將常量的表達式先計算如: a = 1 + 2 * 3;
會被優化成 a = 7;
語義分析完成後,編譯期錯誤被排除,全部使用過的變量名和函數名被綁定到聲明的地址,就能夠進行代碼生成和優化了。
通常的編譯器都不會直接生成目標代碼,而是先生成中間碼再生成目標代碼。 中間碼的做用: 計算機直接生成的代碼比人手寫的彙編要龐大、重複不少,計算機科學家們對一些具備固定格式的中間代碼(最典型的是三地址中間碼)的進行大量的研究工做,提出了不少普遍應用的、效率很是高的優化算法,能夠對中間代碼進行優化,比直接對目標代碼進行優化的效果要好不少。 經過中間代碼實現先後級分離,在多系統、多語言開發時,可大幅提升總體開發效率,減小開發成本縮短開發週期。 爲了增長編譯器的模塊化和可移植化、可擴展性。中間代碼既獨立於任何高級語言,又獨立於機器架構,所以能夠經過編寫m+n個編譯模塊二得到m *n種編譯器。