這是之前學習編譯原理過程中做下的筆記。
因能力有限,在很多地方都理解不到位,特別是對於詞法分析與語法分析的過程感覺特別晦澀。
分享這個筆記也是為了自己做個總結,算是一個小的提綱吧,都沒怎么深入解析編譯的過程。
等以后領悟更多了再作補充吧。
希望各路人士能多加指點,謝謝。
詞法分析
作用:將輸入轉換為一個一個的token,而其用一串整數來表示。
協作:只有當解析器需要的時候才會請求詞法分析器,繼續掃描輸入流,在這個過程中將不斷生成符號表。
實現:在通常的編程語言中,相對於不確定的有限自動機(NFA),確定的有限自動機(DFA)中不會有過多的記號使得狀態數達到指數級。所以可以為每個NFA構造等價的DFA,而且最關鍵的是有限自動機的狀態數,而在沒有不確定狀態的情況下,就要求DFA將每個不確定的狀態轉換成從起始到終結狀態間的路徑,而這可能會導致增加DFA的狀態數。而在多數情況下,設計NFA要簡單些,如可通過正則表達式構建,步驟是先分解正則表達式為簡單的子表達式,並構造相應的NFA,再通過正則的運算符組合他們。
語法分析
部分概念解析
移進-歸約(shift-reduce)解析器
其中有包括待解析短語的輸入流+存放終結符以及之前歸約產生的非終結符的堆棧。
移進操作等於將符號從輸入移動到堆棧中;
歸約操作則結合已完成的序列和最后移進的終結符形成堆棧中的非終結符;
算符文法
文法中的任一產生式規則右邊不存在“空”或者兩個連續出現的非終結符;
錯誤恢復
當前棧頂的終結符和輸入的下一個符號之間沒有任何優先關系:只允許移進下一個輸入的字符,提前為優先表中的空白項指定恢復過程。
沒有任何產生式的右句型可以匹配當前的句柄:從合法規則中選擇近似的值,再報告差異錯誤;
LR分析
LR分析器一直追蹤着句柄的活前綴,並使用自動機來識別這些活前綴,其中的一些工作唄goto部分模擬了,所以不需要掃描堆棧中的每個輸入字符來判斷當前的狀態,因為狀態始終都是在棧頂。
類型檢查
類型檢測
包括表達式,語句,函數;
第一次是關於操作數運算符的適用性;
第二次是檢查需要確定使用的變量的定義;
類型等價
名稱等價
結構等價:構造函數
類型轉換
當強制轉換類型時,只是在那個局部轉換,原來的類型保持不變;
符號表
內容:名稱,類型,位置,作用域,其他屬性
嵌套的詞法作用域
每個作用域單獨一張表:堆棧/列表/樹/hash
單個全局表: 使用列表時需要額外的符號位來表示作用域;樹的話新符號都是在葉子端,刪除也要遍歷;hash存根節點;
當存放記錄項(對象)時,要訪問記錄項(對象)的不同字段(屬性),如R.a和R.b可以通過包含a,b定義的符號表來訪問;也可以將其看做R.a和R.b來訪問;
運行時環境管理
活動記錄:參數空間,簿記(bookkeeping)信息包括返回地址,局部變量空間,局部臨時變量空間;
含有局部過程的環境:
訪問變量的定義相對於當前的過程是局部的,所以要查看嵌套過程的活動記錄來決定;
這可以通過訪問鏈來解決;
首先計算出聲明和引用的兩個詞法嵌套層之間的差異d;
再沿着d的訪問鏈到達正確的活動記錄;
通過偏移量來訪問變量。
優化
而在搜索訪問鏈的時候,由於是虛擬的頁面環境,可能會因為頁面交換而變得十分緩慢,為了可以不搜索,可以使用display。
display是活動記錄的全局指針數組,d[i]指向嵌套深度為i的代碼塊中最近的活動;
所以要訪問非局部變量X,只要最靠近X嵌套聲明的深度為i,則d[i]指向包含X的活動記錄,再根據相對地址就可以訪問X了。
中間代碼生成
高級表示
抽象語法樹
有向非循環圖:公共子表達式由單個節點構成
P-代碼:用於基於堆棧的虛擬機
低級表示
三地址代碼
實現:四元組表示法
代碼生成:對於非終結符E,分別用不同屬性保存E的值的名稱,和對應計算的三地址語句序列;
數組:一維:(base-low * w)+i * w;(w是每個元素的寬度);二維:base+((i1 - low1) * n2 + i2 - low2) * w;
布爾類型:為解決兩階段生成代碼問題,引入truelist, falselist和相應creatlist(i), mergelist(list1,list2), backpatch(list,target)函數;
case:當分支數量較少時可使用線性查找/二分查找;多則使用轉移表,若分支值不緊密聚集,空間成本會更高;
函數調用
目標代碼生成
影響因素
輸入的匹配程度,即中間代碼與目標代碼的映射程度;
目標代碼的結構:絕對代碼,可重定位,匯編;
指令集的選擇:CISC, RISC;
寄存器分配:數據+地址;
求值次序:使用寄存器的數目;
基本塊:程序的第一個語句;轉移目標;緊跟在轉移語句之后的語句;
寄存器分配
無向寄存器沖突圖;
圖着色;
k可着色圖:選取邊數少於k的節點t,將t壓棧並從圖中刪除它和它的所有鄰接邊,重復直至所有節點刪除;
k不可着色圖:
必須選擇節點溢出到內存,需要時再載入分配;
如何選取:沖突最大的;定義和使用很少的;盡量不在循環體內的;
使用動態規划生成;
代碼優化
如果你需要轉載,請標注我的名字“AnnsShadoW”和本文地址:http://www.cnblogs.com/annsshadow/p/4986928.html,謝謝~
