本書面向開設計算機學科的大專院校,提供一門接近實際C/C++語言的C––語言語法,給出了詳細的實驗步驟和指導過程,引導完成一個實際可用的編譯器,并提供了充分的測試樣例來驗證編譯器實現的正確性。本書的實驗設計包括詞法分析與語法分析、語義分析、中間代碼生成以及目標代碼生成四個實驗,貫穿整個編譯器設計的全過程。它具有接近實際、提供指導、幫助驗證和難度可調四個特點,并給出了詳細的使用方式、時間安排和質量控制方案。
前 言本書與機械工業出版社于2009年出版的南京大學趙建華、鄭滔和戴新宇所譯的《編譯原理》課本配合使用。該課本對應的英文版教材是美國哥倫比亞大學、斯坦福大學和Avaya實驗室的Alfred V. Aho、Monica S. Lam、Ravi Sethi和Jeffrey D. Ullman所著的《Compilers: Principles, Techiques and Tools》,由于該書封面配有騎士和恐龍的圖案,也被稱為龍書。在下文中,如無特殊說明,課本均指該書(無論是中文翻譯版還是英文原版)。
需要指出的是,雖然本書配合課本使用,但其內容已經包括所有相關的資料,因而它是內在完整的。這意味著,即使教學時使用其他編譯原理相關的教材,本書仍能作為實踐課程的教材,而不會出現所需資料不完整的情況。
設計思想通常而言,編譯原理實踐課程較難設計,原因是其對應的理論教材以傳授知識為主,離具體實踐有較大的距離。而常規的實踐課程大多會給出一門簡易語言的語法,要求學生實現對應于該語言的編譯器。由于缺乏規范化的指導,時常導致要么降低教學要求,允許學生較為隨意地實現編譯器;要么要求過高,致使學生們無從下手,從而對編譯原理實踐課程產生較大的抵觸心理。針對這些問題,本書面向開設計算機學科的大專院校,提供一門接近實際C/C++的C––語言語法,給出了詳細的實驗步驟和指導過程,引導性地完成一個實際可用的編譯器,并提供了充分的測試樣例來驗證編譯器實現的正確性。
本書共分為四章,分別關注編譯器設計的四個重要階段—詞法分析與語法分析、語義分析、中間代碼生成以及目標代碼生成。每章都給出具體的實驗要求、實驗指導以及測試樣例等,它們共同覆蓋了一個實用編譯器的設計與實現的全過程。
本書的實驗設計具有四個特點:一是接近實際,所采用的語言是C––,接近現實中常用的C/C++,這使得所設計的編譯器非常實用,甚至在特定的領域可以直接或經過少量修改后使用;二是配有指導教程,引導性地完成整個編譯器的設計與實現,不會出現面對實驗要求無從下手或不得不求助第三方資料的情況;三是具備驗證幫助,提供大量的測試樣例來驗證編譯器實現的正確性,而無需自行特別設計測試用例;四是難度可調,提供多種實驗執行方案,既可統一難度要求,也可區分必做內容和選做內容,更可實現分組方案,使得每個組隊實現不同的功能組合,激發學生的思考和鍛煉協作能力。
使用方式本書四章對應四個實驗,前后貫穿,分別為詞法分析與語法分析、語義分析、中間代碼生成以及目標代碼生成,簡稱為實驗一、實驗二、實驗三和實驗四。每個實驗依賴于其前面的實驗,需按順序進行。
在四個實驗中,除了最后的實驗之外,前三個實驗均有必做部分和選做部分,而選做部分又進一步分為幾個不同的要求。具體而言,實驗一的要求包括必做部分和三個選做部分(要求1.1、要求1.2和要求1.3),實驗二的要求包括必做部分和三個選做部分(要求2.1、要求2.2和要求2.3),實驗三的要求包括必做部分和兩個選做部分(要求3.1和要求3.2),最后的實驗四則只有必做部分的要求。
這四個實驗的設計特別考慮了不同院校的不同學生的能力和考核要求上的差異,具備多種使用方式。
1)所有學生相同要求 這是最簡單的使用方式,適用于學習編譯原理的所有學生需要通過相同考核要求的情況。具體而言,可細分為下面三種情況:
所有學生最低要求:完成所有實驗的必做部分即可得滿分。
所有學生最高要求:完成所有實驗的必做部分和選做部分才可得滿分。
所有學生自選要求:完成所有實驗的必做部分即可得滿分;若能完成實驗的選做部分,則視完成情況給予額外獎勵。
2)不同學生不同要求 這種使用方式適用于學習編譯原理的學生需要通過不同考核要求的情況。比如強化班和普通班的學生一起上編譯原理課程,則可要求強化班的學生完成所有實驗的必做部分和選做部分才可得滿分,而普通班的學生完成所有實驗的必做部分即可得滿分,若能完成實驗的選做部分,則可獲得額外獎勵。
3)不同組隊不同要求 這是最復雜的使用方式,適用于允許學生自由組隊以共同完成實驗要求的情況。推薦的組隊規模是1~3人,如兩人組隊則為正常模式可獲得實驗滿分,如三人組隊則為互助模式需減少實驗總分(如變為原來滿分的90%),如單人組隊則為高手模式可提高實驗總分(如變為原來滿分的110%)。在實驗要求方面,仍可考慮不同的考核要求而選擇不同的必做和選做部分,或者完成指定的或隨機選擇的實驗要求。比如一位強化班的學生需要完成所有實驗的必做部分和選做部分才可得滿分,他可以單人組隊進入高手模式以獲得更高的總分,也可以兩人組隊進入正常模式以減少實驗的難度。
4)編譯優化額外獎勵 實驗三的設計特別考慮了編譯優化的程度,即中間代碼的執行效率(具體要求見實驗三的實驗內容部分)。編譯優化屬于額外獎勵部分,如果中間代碼的執行效率位于所有學生實驗的前50%,則可獲得實驗三滿分額外20%的獎勵(即總分變為原來滿分的120%);如果中間代碼的執行效率位于所有學生實驗的前20%,則可獲得實驗三滿分額外50%的獎勵(即總分變為原來滿分的150%)。這部分額外獎勵與前面的三種使用方式既不重疊也不沖突,可根據實際情況考慮是否采用。
時間安排四個實驗的安排依順序進行,每個實驗持續四周,每完成一個實驗即可開始下一個實驗,但實驗一的開始可推遲兩周,以等待對應的課本知識講授。一般而言,如果一個學期時長18周,從第3周開始實驗一,在第6周末結束實驗一并在第7周開始實驗二,在第10周末結束實驗二并在第11周開始實驗三,在第14周末結束實驗三并在第15周開始實驗四,在第18周末結束實驗四以完成整個編譯實踐。如果一個學期時長更短或更長,可做相應調整。比如在更短的情況下,可以適當減少實驗一的推遲時間(由兩周減為一周)或實驗三的時間(由四周減為三周)。
上面的實驗時間安排是根據課本的知識體系而制訂的,如果是其他編譯原理教材,只要有下述的內容,也可模仿進行:
第1~6周:引論、詞法分析、語法分析(實驗一);第7~10周:語法制導的翻譯、中間代碼生成(實驗二);第11~14周:中間代碼生成、運行時刻環境、代碼生成(實驗三);第15~18周:代碼生成、機器無關的優化(實驗四)。
如果由于教學上的特殊安排或別的原因,導致課本理論知識的講解落后于實驗安排,也可以采取推遲部分實驗的結束時間并同時保證后續實驗的開始時間的方法來安排實驗。比如,若語法分析部分的課程講授無法在第6周完成,那么可以允許實驗一推遲一至兩周結束(即在第7周或第8周結束),而實驗二仍保持在第7周開始。這樣既可以幫助部分學生更好地完成實驗一(他們可能因為沒有學習相應的課本知識而無法進行實驗一),也可以允許另外的學生正常地開始實驗二(與實驗相關的內容在本書的實驗指導部分已經提供,課本知識并不是必需的,但能幫助學生更好地理解知識)。
質量控制編譯原理實踐的質量控制是指在完成實驗的過程中,鼓勵學生增強學習興趣,提高所實現編譯器的質量以及抑制不良行為(如作弊)的發生。本書的實驗設計正有這方面的考慮:
1)提高實驗質量 本書從測試用例和編譯優化兩方面來提高實驗質量。
測試用例:本書提供了大量測試樣例來幫助學生自檢編譯器的實現是否符合實驗要求,教學中可引入更多的額外測試用例(可根據實驗要求和書中測試樣例推導出)來進一步測試學生所實現編譯器的質量,這將促使學生們考慮更多的細節來更好地實現編譯器。
編譯優化:實驗三的設計特別考慮了編譯優化的額外獎勵,這將鼓勵學生們努力嘗試以獲得更多的額外獎勵。
2)抑制不良行為 本書從分組實驗和克隆檢測兩方面來抑制不良行為。
分組實驗:本書的實驗設計了必做部分和選做部分,而選做部分又分為不同的要求,它們之間相互獨立。在允許學生自由組隊來協作完成實驗內容的情況下,可進行必做部分和選做部分的隨機組合。比如,根據抽簽隨機決定一組學生必須完成實驗一的必做部分和選做部分的要求1.1,而另一組學生必須完成實驗一的必做部分和選做部分的要求1.2,以此類推,后續的實驗也可隨機組合實驗內容。這樣可以增強不同組隊間需要完成的實驗內容的差異性,增加實驗作弊的難度。也可以進一步要求不允許完成其他組隊的選做實驗(如前一組學生不能完成實驗一選做部分的要求1.2),這樣也可以抑制不同組隊之間的作弊行為(可通過測試用例區別出是否跨組完成了實驗要求)。但要注意這將與第一種使用方式中的“所有學生自選要求”的情況相抵觸,在實驗執行中要注意。
克隆檢測:最后,本書的實驗設計也允許進行實驗代碼間的克隆檢測,特別是在分組實驗的情況下,學生間實驗代碼幾乎無法近似。為避免代碼復制后經過簡單變量名和函數名替換后重新提交為新的實驗代碼,建議采用基于可執行代碼的克隆檢測。采用必要的克隆檢測可以進一步抑制學生實驗作弊的行為。
以上介紹了本書編譯原理實踐的設計思想、使用方式、時間安排和質量控制。在使用過程中如有任何問題,歡迎和我們交流;如有不妥當之處,也敬請指出。
叢書序言
前言
第1章 詞法分析與語法分析 1
1.1 實驗內容 1
1.1.1 實驗要求 1
1.1.2 輸入格式 2
1.1.3 輸出格式 2
1.1.4 測試環境 3
1.1.5 提交要求 3
1.1.6 樣例(必做內容) 4
1.1.7 樣例(選做要求) 7
1.2 實驗指導 11
1.2.1 詞法分析概述 12
1.2.2 GNU Flex介紹 13
1.2.3 Flex:編寫源代碼 14
1.2.4 Flex:書寫正則表達式 17
1.2.5 Flex:高級特性 19
1.2.6 詞法分析提示 21
1.2.7 語法分析概述 22
1.2.8 GNU Bison介紹 24
1.2.9 Bison:編寫源代碼 26
1.2.10 Bison:屬性值的類型 28
1.2.11 Bison:語法單元的位置 30
1.2.12 Bison:二義性與沖突處理 31
1.2.13 Bison:源代碼的調試 33
1.2.14 Bison:錯誤恢復 35
1.2.15 語法分析提示 36
第2章 語義分析 38
2.1 實驗內容 38
2.1.1 實驗要求 38
2.1.2 輸入格式 40
2.1.3 輸出格式 41
2.1.4 測試環境 41
2.1.5 提交要求 41
2.1.6 樣例(必做內容) 42
2.1.7 樣例(選做要求) 48
2.2 實驗指導 51
2.2.1 屬性文法 52
2.2.2 符號表 53
2.2.3 支持多層作用域的符號表 56
2.2.4 類型表示 58
2.2.5 語義分析提示 61
第3章 中間代碼生成 63
3.1 實驗內容 63
3.1.1 實驗要求 63
3.1.2 輸入格式 66
3.1.3 輸出格式 66
3.1.4 測試環境 67
3.1.5 提交要求 67
3.1.6 樣例(必做內容) 67
3.1.7 樣例(選做要求) 70
3.2 實驗指導 73
3.2.1 中間代碼的分類 74
3.2.2 中間代碼的表示(線形) 76
3.2.3 中間代碼的表示(樹形) 77
3.2.4 初探運行時環境 78
3.2.5 翻譯模式(基本表達式) 81
3.2.6 翻譯模式(語句) 83
3.2.7 翻譯模式(函數調用) 84
3.2.8 翻譯模式(數組與結構體) 85
3.2.9 中間代碼生成提示 86
第4章 目標代碼生成 88
4.1 實驗內容 88
4.1.1 實驗要求 88
4.1.2 輸入格式 89
4.1.3 輸出格式 90
4.1.4 測試環境 90
4.1.5 提交要求 90
4.1.6 樣例 91
4.2 實驗指導 95
4.2.1 QtSPIM簡易教程 95
4.2.2 MIPS32匯編代碼書寫 97
4.2.3 指令選擇 100
4.2.4 寄存器分配(樸素寄存器分配算法) 102
4.2.5 寄存器分配(局部寄存器分配算法) 103
4.2.6 寄存器分配(圖染色算法) 104
4.2.7 寄存器分配(活躍變量分析) 106
4.2.8 寄存器分配(MIPS寄存器的使用) 107
4.2.9 棧管理 108
4.2.10 目標代碼生成提示 113
附錄A C––語言文法 115
附錄B 虛擬機小程序使用說明 122
附錄C 資源下載和安裝介紹 125
參考文獻 127