簡單的編譯流程

簡易編譯器流程圖:

一個典型的編譯器,能夠包含爲一個前端,一個後端。前端接收源程序產生一箇中間表示,後端接收中間表示繼續生成一個目標程序。因此,前端處理的是跟源語言有關的屬性,後端處理跟目標機器有關的屬性。前端

複雜的編譯器:java

詞法分析器:

1.詞法分析器讀入源代碼,而後對字符流(源代碼)作切分紅記號流。舉個例子:程序員

    這是一個程序員看到的字符流(源代碼)後端

2.詞法分析器將字符流讀入,根據關鍵字、標識符、標點、字符串、整形數等進行劃分,造成記號流(單詞):數組

    

 舉個例子: 假如源語句if(x>5),則詞法分析器返回token{k=IF,lexeme=0};token{k=LPAREN,lexeme=0};token{k=ID,lexeme="X"};……數據結構

詞法分析器的任務:字符流到記號流。函數

       字符流:和被編譯語言密切相關(ASCII,Unicode,or……)工具

       記號流:編譯器內部定義的數據結構,編碼所識別出的詞法單元性能

語法分析器:

 語法分析器(Parser)一般是做爲編譯器解釋器的組件出現的,它的做用是進行語法檢查(檢查語法是否符合這個語言的規則)、並構建由輸入的單詞組成的數據結構(通常是語法分析樹抽象語法樹等層次化的數據結構)。語法分析器一般使用一個獨立的詞法分析器從輸入字符流中分離出一個個的「單詞」,並將單詞流做爲其輸入。實際開發中,語法分析器能夠手工編寫,也可使用工具(半)自動生成。優化

抽象語法樹是對程序語法的抽象表示

例如,當在開發語言時,可能在開始的時候,選擇LL(1)文法來描述語言的語法規則,編譯器前端生成LL(1)語法樹,編譯器後端對LL(1)語法樹進行處理,生成字節碼或者是彙編代碼。可是隨着工程的開發,在語言中加入了更多的特性,用LL(1)文法描述時,感受限制很大,而且編寫文法時很吃力,因此這個時候決定採用LR(1)文法來描述語言的語法規則,把編譯器前端改生成LR(1)語法樹,但在這個時候,你會發現很糟糕,由於之前編譯器後端是對LL(1)語樹進行處理,不得不一樣時也修改後端的代碼。

1.抽象語法樹的第一個特色爲:不依賴於具體的文法。不管是LL(1)文法,仍是LR(1),或者仍是其它的方法,都要求在語法分析時候,構造出相同的語法樹,這樣能夠給編譯器後端提供了清晰,統一的接口。即便是前端採用了不一樣的文法,都只須要改變前端代碼,而不用連累到後端。即減小了工做量,也提升的編譯器的可維護性。

2.抽象語法樹的第二個特色爲:不依賴於語言的細節。在編譯器家族中,大名鼎鼎的gcc算得上是一個老大哥了,它能夠編譯多種語言,例如c,c++,java,ADA,Object C, FORTRAN, PASCAL,COBOL等等。在前端gcc對不一樣的語言進行詞法,語法分析和語義分析後,產生抽象語法樹造成中間代碼做爲輸出,供後端處理。要作到這一點,就必須在構造語法樹時,不依賴於語言的細節,例如在不一樣的語言中,相似於if-condition-then這樣的語句有不一樣的表示方法

語義分析器:

對語法樹的合法性進行處理(例如:一個變量在使用以前是否先定義聲明,所調用的函數是否有對應的定義),產生相應的中間代碼或目標代碼.

語義分析編譯過程的一個邏輯階段, 語義分析的任務是對結構上正確的源程序進行上下文有關性質的審查,進行類型審查。語義分析是審查源程序有無語義錯誤,爲代碼生成階段收集類型信息。好比語義分析的一個工做是進行類型審查,審查每一個算符是否具備語言規範容許的運算對象,當不符合語言規範時,編譯程序應報告錯誤。若有的編譯程序要對實數用做數組下標的狀況報告錯誤。又好比某些程序規定運算對象可被強制,那麼當二目運算施於一整型和一實型對象時,編譯程序應將整型轉換爲實型而不能認爲是源程序的錯誤。

通過上面的處理,程序中就沒有在包括語言和語義的錯誤(除非編譯器自己就有bug)

中間代碼

  中間代碼也叫中間語言

(Intermediate code /language)是:源程序的一種內部表示,不依賴目標機的結構,複雜性介於源語言和機器語言之間。

中間代碼的優勢

一、邏輯結構清楚;

二、利於不一樣目標機上實現同一種語言;

三、利於進行與機器無關的優化;

中間代碼能夠生成例如 三地址代碼 SSA 控制流圖 等 (中間碼的生成也是取決於編譯器設計中的考慮,例如需不須要優化,或者追求速度,性能等).

關於語法分析器和中間代碼:

LINKhttps://blog.csdn.net/yongchaocsdn/article/details/79056504

代碼生成:

中間代碼能夠被最終的一個代碼生成的階段處理爲最後的目標代碼(例如機器碼,JVM字節碼)

符號表

符號表是存儲程序編譯過程當中重要信息,能夠給每一個階段提供支持

在計算機科學中,符號表是一種用於語言翻譯器(例如編譯器解釋器)中的數據結構。在符號表中,程序源代碼中的每一個標識符都和它的聲明或使用信息綁定在一塊兒,好比其數據類型、做用域以及內存地址

符號表在編譯程序工做的過程當中須要不斷收集、記錄和使用源程序中一些語法符號的類型和特徵等相關信息。這些信息通常以表格形式存儲於系統中。如常數表、變量名錶、數組名錶、過程名錶、標號表等等,統稱爲符號表。對於符號表組織、構造和管理方法的好壞會直接影響編譯系統的運行效率。

舉個例子:

一個加法表達式(sum)在編譯中的過程:

例如sum的語法規則是:

1.整數數字 n

2.加法表達式式 n1+n2

根據上面的規則

3

1+2

1+2+3  (加法表達式遵循左結合也就是 1+2 的結果 3+3 這也屬於加法表達式的一種)

這上面的三種都遵照了加法表達式的規則  因此都是加法表示式的一種

目標機器: 棧式計算機(stack)

是一個LIFO的一個先入後出存儲器,跟它向對應的是FIFO存儲器先入先出傳統順序

有兩條指令:

1.push n (將指定的參數壓入棧中)

2.add (將棧頂的兩個索引的數據彈出並進行加法運算,再將運算後的結果壓入棧中)

//x和y表示棧頂的數據 pop[]表示彈出棧頂的數據
x = pop[]

y = pop[]

//加法運算
n = x+y

//壓棧
push n

例如1+2+3加法運算通過語法分析器翻譯抽象語法樹(AST):

1+2+3 =語法分析器:      語法樹
                         (+)
                     (+)     (3)
                  (1)   (2)

先從左結合開始:

1+2 = 3

3+3 = 6

生成棧式計算機(stack)的代碼:

代碼生成使用樹的後續遍歷(從樹的左邊子節點開始遍歷,而後遍歷右邊子節點最後遍歷根節點)

代碼生成規則:

1. 遍歷樹中時若是遇到整數 n 生成代碼: push n

2.遍歷樹中時若是遇到 + 生成代碼: add

最後生成的棧式計算機的代碼:

push 1

push 2

add

push 3

add
相關文章
相關標籤/搜索