編譯器相關

編譯器基本原理

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
複製代碼

1.詞法分析

將源文件的字符串,進行過濾,去除空格,註釋等,而後將其分割成一個個的詞(記號、token) 好比 int a = b + sum(1,2); 會拆分紅12個token後端

int     類型標識符
a       標識符
=       賦值運算符
b       標識符
+       加號
sum     標識符
(       左括號
1       整數
,       逗號
2       整數
)       右括號
;       分號
複製代碼

2.語法分析

詞法分析以後,字符流已經被轉化爲token流了 int<int> ID<a> '=' ID<value> '+' ID<sum> '(' Num<1> ',' Num<2> ')' ';' 上面的int表示一個標識符類型的token。內容爲'int'bash

接下來,解析這個token流,首先這是一個語句,咱們主要有用到4種語句,賦值語句,函數調用語句,if和while語句。很明顯,這是一個賦值語句。架構

語法結構樹.pic.jpg

賦值表達式用變量名、賦值符號= 和表達式構成。編程語言

將語法結構應用到token流上,把等號兩邊的內容放到對應的節點上,生成語法樹以下:

14972724543701.jpg

接下來對expression<b+sum(1,2)>進行解析 表達式有不少種,變量表達式,數字表達式,加減法表達式,通過對比,只有加法表達式結構才能匹配,因而將加法表達式的語法結構應用到其中。如圖

14972725257900.jpg

進一步解析語法樹的<b><sum(1,2)>,發現只有變量表達式和函數調用表示式才能匹配成功,獲得

14972730581069.jpg

接下來進行語法優化,有些節點是多餘的,好比在複製表達式中 '='和';',對語法樹進行濃縮獲得最終的抽象語法樹(AST)

14972734592756.jpg

由此看出,語法分析就是不斷將語法規則用於源程序,將源程序解析成一顆抽象語法樹。以後的語義分析,中間碼生成和代碼優化都是基於對這棵樹進行遍歷,檢查,修改進行的。

3.語義分析

語義分析階段,會對語法進行屢次的遍歷,進行語法檢查,包括類型和聲明的檢查,OClint就是基於語義分析進行靜態代碼分析的。 仍是以上面的賦值語句做爲例子, 須要檢查 1.b, sum是否已經聲明過 2.sum函數的參數數量和類型是否和傳入的參數數量和類型匹配。 3.加法運算的兩個操做數的類型是否匹配,這裏也就是檢查函數的返回值類型了 4.賦值運算的兩個操做數類型是否匹配

通常在遍歷語法樹過程當中,遇到的變量聲明和函數聲明時,會將變量名-類型,函數名-返回類型-參數數量-參數類型保存到符號表裏,當遇到使用變量和函數調用時,根據名稱在符號表猴子那個查找,檢查是否聲明過,類型是否匹配。所以,對於java這種函數聲明能夠放在使用位置後面的語言,至少須要遍歷兩遍語法樹。

語義檢查時,也會對語法樹進行優化,好比將常量的表達式先計算如: a = 1 + 2 * 3; 會被優化成 a = 7;

語義分析完成後,編譯期錯誤被排除,全部使用過的變量名和函數名被綁定到聲明的地址,就能夠進行代碼生成和優化了。

中間碼生成

通常的編譯器都不會直接生成目標代碼,而是先生成中間碼再生成目標代碼。 中間碼的做用: 計算機直接生成的代碼比人手寫的彙編要龐大、重複不少,計算機科學家們對一些具備固定格式的中間代碼(最典型的是三地址中間碼)的進行大量的研究工做,提出了不少普遍應用的、效率很是高的優化算法,能夠對中間代碼進行優化,比直接對目標代碼進行優化的效果要好不少。 經過中間代碼實現先後級分離,在多系統、多語言開發時,可大幅提升總體開發效率,減小開發成本縮短開發週期。 爲了增長編譯器的模塊化和可移植化、可擴展性。中間代碼既獨立於任何高級語言,又獨立於機器架構,所以能夠經過編寫m+n個編譯模塊二得到m *n種編譯器。

相關文章
相關標籤/搜索