語法分析器是整個環節比較主要的一環,大部分的任務都是由其承擔。在前面的基礎知識提到過語法分析的基本方法,由於遞迴子程式手工構造比較簡便,故本設計使用的是遞迴子程式法。由於在實現遞迴時,要考慮是否有遞迴的出口,因此需要提取左公共因子,降低遞迴深度。在語法分析的時候,不僅需要考慮到語法分析程式的高效性和簡潔性,在降低耦合性的同時需要注意函式的之間的聯絡。
語法分析時,可能文法的描述很簡便,但不利於實現,需要對其文法上的等價變換才能更好地編寫。這裡將介紹函式邏輯和文法等價上的變換,介紹的書籍已經有很清楚的介紹,不再進行贅述。下面開始該過程實現之路。
via-c語言由於有很多語句種類,下面介紹幾種常見語句的解析過程。
例如for迴圈語句解析過程如下圖3.1:
3.1 for 迴圈語句的解析過程
從括號解析,進行迴圈變數的初始化,再進行for迴圈的條件的判斷,然後進行for迴圈體的**的執行。
選擇語句,這個都比較熟悉。下圖3.2是語句的解析過程:
3.2 選擇語句的解析過程
雖然跳轉語句有 continue語句等好幾種語句,但是它們解析的過程基本相似。解析過程如圖3.3。
3.3 跳轉語句的解析過程
語句還有其他幾種分類,這裡不再詳細介紹。語句的解析關係著整個語法分析器的邏輯部分,具體可見檔案grammar.c。
解析型別符過程如圖3.4:
3.4 型別解析過程
先經過詞法分析器的解析後,對傳遞進來的識別符號進行識別,上**析了via-c語言的所有的資料型別。
圖3.5是宣告符的解析過程:
3.5 宣告符解析
宣告符主要是解析函式定義和變數的定義,實現詳情見grammar.c檔案。
via-c表示式有好幾類,雖然有在表現形式上有區別,但是表示式在解析過程中基本上是差不多的結構。另外解析表示式時,還需要考慮到運算子的優先順序高低。在前面的**中已經列出了優先順序高低。圖3.6是乘除表示式的解析過程。
3.6 乘除表示式解析過程
在語法的分析中,有些程式沒有進行縮排的處理,可能需要對其縮排,以便讓 語法分析解析後產生的輸出,更加直觀。
以下是對語法狀態的列舉型別定義
enum e_syntaxstate
;
具體的縮排操作函式和縮排動作實現見grammar.c,另外在via-c中採用的縮排是4個空格。
輸入程式(圖3.7)沒有縮排,經過語法分析之後,得到結果(見圖4.13),可以看到程式已經根據了宣告和定義、函式定義等規則進行了縮排,證明了語法分析程式已經成功。
3.7 語法分析的示例程式
可以看到示例程式是雜亂無章的,經過語法分析器分析後輸出整齊一致,如圖3.8。
源**經過上一層次分析後,只能說明**在語法和詞法上符合相關的規則,並不能說**已經是正確。例如在函式內部並沒有迴圈結構,出現了非法的跳轉語句,這是符合語法規則的,然而在邏輯上這並不是正確的。語義分析程式需要抓住這類的漏網之魚。這一階段的工作比較繁雜,需要先做好符號表的準備,再進行語義上的剖析,以便下階段的**生成準備。
符號表主要是儲存符號的相關特徵資訊,其需要在編譯的過程不斷收集資訊的同時不斷更新資訊,通過對屬性資訊的查詢可以進行語義檢查。
符號表主要用棧來實現。由於變數存在作用域的區別,因此需要兩個棧分別進行資訊的收集。分別定義如下:
stack g_sym; //全域性符號棧
stack l_sym; //區域性符號棧
接下來編寫符號表的操作函式,此後就可以在上階段的基礎上進行符號表的構造。
在構造字元表時需要注意的是位元組對齊,尤其在自定義型別的成員上。位元組對齊可以提高訪問速度,但是如果一味地追求位元組上的對齊,會導致許多空間沒有儲存資料,導致效能上的浪費。
前面提到過靜態缺陷和執行異常,語義分析器就是處理靜態語義缺陷。語義分析器主要是限制目標程式和源程式在邏輯結構上完全一致,因此在以前語法分析器的基礎上進行語義上限制。對語義的分析有兩個層次,首先是正確性分析,即需要根據語言的定義規則去判斷**語義的正確性,其次是優化分析,也就是用於分析提高目的**執行的效能。
語義分析器基本是在前面的基礎上實現,實現詳情見grammar.c檔案。
本設計的適用平台為windows,所以可執行檔案的格式為coff,採用的機器語言也是intel x86機器語言。intel x86機器語言有七種指令,跳轉和算術指令等等,以及各種的寄存空間的操作。**生成器需要生成對應的指令和對應的暫存器的操作。具體函式見gencode.c檔案。
5.1 中間**檔案生成
在編寫**的過程中,思維上的遺漏或者是語法上不正確的情形不可避免會出現,因此錯誤控制程式是有必要存在的。一般來說程式出錯的等級有詞法警告、語法錯誤以及執行異常等。
圖5.2是via-c的錯誤控制程式的處理流程,具體實現見error.c。
5.2 錯誤控制程式
首先介紹應用平台的有關知識。windows平台使用的可執行檔案為pe格式,而pe檔案主要由dos部分、nt頭、節點表、節資料等部分構成,dos部首由兩部分組成:dos的mz檔案標誌和dos存根程式,nt頭包含了pe檔案簽名、coff檔案頭、coff可選檔案頭[8,16-19]。
下面開始這階段鏈結器邏輯的編寫,流程順序圖見圖5.3。
5.3 鏈結器的編寫流程圖
中間**的優化,是可以在**生成時採取優化措施直接進行優化,但這樣僅僅是優化了乙個檔案,無法顧及到整個程式的優化。因此一些重要的優化就需要在鏈結器鏈結時才能進行。編譯器有很多的優化方法,淺易如摺疊不變數,高深同重排指令等等。但是有些要緊的優化是超過當今世面上編譯器效能,例如使用高效能的演算法替代低效能的演算法,抑或是優化指令的排列,提高**的執行效能。
5.4鏈結器成果圖
到這裡已經完成了鏈結器的編寫,同時編譯核心的工作基本上完成了。後續將進入周邊功能的實現。
python編譯器原始碼 編譯python原始碼
回望2020,你在技術之路上,有什麼收穫和成長麼?對於未來,你有什麼期待麼?雲 社群年度徵文,各種定製好禮等你!對python原始碼進行編譯1.生成.pyc檔案import py compilepy compile.compile hello.py 2.優化原始碼檔案python o m py co...
C語言規範及編譯器
一 規範 c 的第乙個標準是由ansi發布的。雖然這份文件後來被國際標準化組織 iso 採納並且iso發布的修訂版也被ansi採納了,但名稱ansi c 而不是 iso c 仍被廣泛使用。一些軟體開發者使用iso c,還有一些使用 standard c。c89 1983年,美國國家標準協會 ansi...
C 語言 編譯器
c 語言是高階程式語言,人們在使用 c 語言工作的時候不必用數字碼表示指令,大大簡化了對於計算機底層暫存器的操作,人們可以把工作的重點放在 設計和具體功能的實現,編寫出更易讀易懂的 可是計算機的工作和人類正好相反,c 語言編寫的 對於計算機而言就好比是天書且沒有意義可言,因為計算機是識別機器語言的,...