[心得]編譯原理知識整理
前言
不學龍書的碼農不是靠譜的碼農。就衝這句話,我真的把編譯原理給速推了一把。
乾貨
分析把源程式分解成多個組成要素,並在這些要素之上加上語法結構。
綜合根據中間表示和符號表中的資訊來構造目標程式。
把宣告如何完成一個計算任務的語言稱為強制式語言。
編譯器最基本的數學模型是有窮狀態機FSM和正則表示式。它們用來描述詞法單位(關鍵字,識別符號)以及被編譯器用來識別這些單位的演算法。此外,上下文無關文法用於描述程式設計語言的語法結構。
識別符號是一個字串。所有的識別符號都是名字,但有些名字也可以是表示式,變數指向儲存中的某個特定位置。
一個函式通常有一個返回值,而一個過程不返回任何值。方法在OO語言中和特定類相關聯。
宣告告訴我們事務的型別,而定義告訴我們它們的值。
語法描述該語言的正確形式。語義定義程式的含義。
詞法單元由各名字和屬性值組成,這些詞法單元也稱為終結符號。
一個文法描述了程式的層次結構。文法的定義使用了稱為終結符號的基本符號和稱為非終結符號的變數符號。這些符號代表了語言的構造。
詞法分析器從輸入中逐個讀取字元,並輸出一個詞法單元的流。
語法分析從一個文法開始符號推匯出一個給定的終結符號串。推導的方法是反覆將某個非終結符替換為它的某個產生式的體。
語法分析的結構是中間程式碼,具體有抽象語法樹AST和三地址程式碼TAC。
詞法分析器掃描源程式並輸出一個由詞法單元組成的序列。
為了判斷下一個詞素何處結束。常常預先掃描輸入字元。
一個詞法分析器的行為經常用一個狀態轉換圖來描述。有窮狀態機是狀態轉換圖的形式化表示。
自底向上語法分析器基於LR(k)語法分析。L表示從左到右的掃描,R表示反向構造出一個最右推導序列,而K表示向前看k個輸入符號。
上下文無關文法,一個文法描述了一個終結符號集合。另一個非終結符號集合和一組產生式。
一顆語法分析樹是一個推導的圖形表示。
如果一個文法的某些終結符號串有兩個或多個最左推導/最右推導,那麼這個文法就稱為二義性文法。
如果對於一個文法,如果只需要檢視下一個輸入符號就可以選擇正確的產生式來擴充套件一個給定的非終結符,那麼這個文法就稱為LL(1)的。
自底向上語法器一般如此:根據下一個符號(向前看符號)和棧中內容,選擇是將下一個輸入移入棧中,還是將棧頂部某些符號進行歸納。
在移入-規約分析過程中,棧中內容總是一個可行字首。
語法制導定義SDD是一個上下文無關文法和屬性以及規則的集合。
語法制導樹簡稱SDT。
一個語法分析樹結點上的繼承屬性只能依賴於它的父結點的繼承屬性,和位於它左邊的兄弟節點的屬性。
有向無環圖簡稱DAG。
中間形式通常是一個圖形表示方法和三地址程式碼的組合。
回填是一種為布林表示式和語句進行一趟式程式碼生成的技術。其基本思想是維護多個由不完整的跳轉指令組成的列表,當跳轉目標已知後,填回該目標。
為了實現語言中的抽象概念,編譯器與作業系統及目標機器協同,建立並管理了一個執行時環境,該環境有一個靜態資料區,用於存放物件程式碼和在編譯時刻建立的靜態資料物件。同時它還有動態的棧區和堆區,用於管理在目的碼執行時建立和銷燬的物件。
過程呼叫和返回通常稱為控制棧的執行時刻棧管理,可以使用棧的原因是過程呼叫在時間上是巢狀的。
區域性變數的儲存空間可以在執行時刻棧中分配。每一個活躍的活動都在控制棧中有一個活動記錄(幀)。
對不支援巢狀函式的語言,一個變數的位置要麼是全域性的,要麼可以在執行時刻棧頂的活動記錄中找到。對於帶巢狀過程的語言而言,可以通過訪問鏈來訪問棧中的非區域性資料。訪問鏈是加在各個活動記錄中的指標。顯示錶是一個和訪問鏈聯合使用的輔助陣列,它不需要使用訪問鏈鏈路的高效捷徑。
堆是用來存放生命週期不確定或到期明確刪除的儲存區域。
best-fit策略(分配能夠滿足空間請求的最小可用“視窗”)可減少碎片。對於空間區域性性而言,通過合併或者說接合相鄰的視窗來減少碎片。
人工回收有2個問題。記憶體洩露或者空指標引用。
有兩種尋找不可達物件的基本方法:要麼截獲一個物件從可達變成不可達的轉換,要麼週期性定位所有可達物件,並推匯出其餘物件是不可達的。
程式碼生成器有3個主要任務:指令選擇、暫存器分配和指派,以及指令排序。
指令選擇是為每個中間表示語句選擇目標語言指令的過程。
暫存器分配是決定哪些IR值將會儲存在暫存器中的過程。
圖著色演算法是一個在編譯器中完成暫存器分配的有效技術。
Ershov數指出瞭如果不把任何臨時值儲存回記憶體中的指令序列。這些指令的目的是在暫存器中騰出空間,以儲存另一個值。
大部分全域性優化是基於資料流分析技術實現的。
全域性公共子表示式:一個重要的優化方法是尋找同一個表示式在兩個不同基本塊中的計算過程。如果一個在另一個前面,可以把第1次計算該表示式的結果存起來,並複用。
複製傳播是替換等價變數。
程式碼移動吧每次迭代取值相同的值移到迴圈之外。
歸納變數在迴圈執行時的不同迭代中的取值是一個線性序列。
一個數據流分析模式在程式的每個點上都定義了一個值。
到達定值的資料流框架的資料流值是程式中的語句集合。
另一個重要的資料流框架計算了在各個程式點上活躍的變數。
可用表示式就是之前已經計算過,且在最後一次計算之後,它的運算分量都沒有被重新定值的表示式。
程式碼移動和全域性公共子表示式消除可以被擴充套件為部分冗餘消除。
如果在一個流圖的入口結點開始對它進行深度優先搜尋,會得到一個深度優先搜尋樹。結點的深度優先排序是這顆樹的後序遍歷的逆序。
在深度優先生成樹上,邊分為前進邊,後退邊和交叉邊。生成樹的一個重要性質是所有的交叉邊都是從樹的右邊到達左邊。另一個重要性質是,如果按照深度優先排序,只有後退邊的頭比它的尾排序更靠前。
回邊就是其頭結點支配尾結點的邊。
如果生成樹的每一個後退邊都是一條回邊,那麼這個流圖就是可以規約的。
一個自然迴圈是一個結點的集合。
不同於迭代方法的另一種資料流分析方法是沿著區域層次結構向上,然後再向下掃描,計算從各個區域的頭到達該區域中各個結點的傳遞函式。
基於區域的分析技術的重要應用之一是尋找歸納變數的資料流框架。該框架試圖找出迴圈區域中每個滿足下面條件變數的公式。這些變數的值可表示為迴圈迭代次數的仿射(線性)函式。
被優化的程式碼排程利用了流水線特性。
通過使用附加位置存放資料,可以消除反依賴和輸出依賴。
真依賴:先寫後讀
反依賴:讀後寫
輸出依賴:先後寫
一個do-all迴圈的迭代之間不存在依賴關係,因而可並行。
一個do-across迴圈存在從每個迭代到後續迭代的依賴關係。
知道了如何優化資料區域性性,也就知道了並行性在哪裡。
並行性覆蓋率的重要性可用amdal定律表示:如果f是被並行化程式碼的比率,且如果並行版本在一個有p個核的機器執行且無任何通訊或者並行化開銷,那麼此時加速比為:1/((1-f)+(f/p))
迴圈是並行化的主要目標,在使用陣列的應用中更是如此。
迴圈中對陣列的各個訪問之間的依賴關係有限且符合一種正則表示式,這兩個因素可獲得較好的資料區域性性。
對陣列的訪問都是假定是仿射的,這些陣列的下標的表示式是迴圈下標的線性函式。
對迭代空間的一個關鍵操作是把定義該空間的各個迴圈重新排列。這就要求把一個多向體迭代空間投影到它的部分維上。
Fourier-Motskin演算法把一個給定變數的上下界替換成為關於這些界限的不等式。
處理迴圈時需解決的一箇中心問題是確定兩個陣列訪問之間是否具有資料依賴關係。如果這些訪問以及迴圈界限都是仿射的,迭代空間就可以被定義為一個多面體。而優化迴圈轉化為一個特定的矩陣向量方程是否具有位於該多面體中的解。
如果該矩陣的秩達到最大值,那麼當著迴圈迭代執行時,資料訪問不會兩次觸及同一個元素。如果陣列是按行(列)存放的,那麼消除最後(最前)一行後得到的矩陣的秩反映這個訪問是否具有良好的區域性性。
為了確定是否存在依賴關係,必須求一個丟番圖方程的整數解。解這個方程的關鍵技術是計算各個變數的係數的最大公約數GCD。
空間分劃約束是說,如果不同迭代中的兩個訪問之間具有資料依賴關係(即他們訪問了同一個元素),那麼它們必須被對映到同一個處理器上。
- 用來並行化具有仿射陣列訪問的程式轉換是7個基本轉換的組合:
- 迴圈融合
迴圈裂變
重新索引(下標加常量)
比例變換(下標乘以常量)
反置(倒轉下標)
交換(交換下標)
傾斜(掃描線不再和座標軸同向)
並行運算同步:在一個程式步驟之間插入同步運算。
流水線化允許處理器共享資料。
時間分劃約束
分塊把一個迴圈巢狀中的每個迴圈都分劃為兩個迴圈。
條狀挖掘和分塊類似。
對跨越過程邊界的資訊進行跟蹤的資料流分析標記為過程間分析。
程式中呼叫其它過程的程式點稱為過程呼叫。
一個程式的呼叫圖是二分圖。
只要一個程式中沒有遞迴,原則上可以把過程呼叫展開,然後進行過程內分析。
如果一個數據流分析得到的事實和程式中的位置相關。那稱它為控制流相關。如果一個數據流分析得到的事實和過程呼叫的歷史相關,那麼它就是上下文相關。
上下文相關分析可以基於過程克隆或者基於摘要。
需要過程間分析技術的一個重要應用是檢測軟體的安全漏洞。
Datalog語言是if-then規則的簡單表示方式。它用於高層次描述資料流分析。
二分決策圖BDD是一種使用帶根的DAG表示布林函式的簡潔方法。