編譯原理實驗指導書

2022-09-19 04:33:06 字數 4024 閱讀 7644

《編譯原理實踐教程》作為《編譯原理和技術》課程的延伸,其目的是讓大家動手設計和實現某一規模適中的語言的編譯器,該編譯器不僅涉及編譯程式的各個階段,而且也強調了編譯的總體設計、各個階段的介面安排等等。

通過上機實踐,來設計這個相對完整的編譯器,一方面可以使學生增加對編譯程式的整體認識和了解——鞏固《編譯原理和技術》課程所學知識,另一方面,通過上機練習,學生也可以學到很多程式除錯技巧和設計大型程式一般的原則,如模組介面的協調,資料結構的合理選擇等等。

為了使學生能盡早動手實踐,我們建議把實踐分成三部分,首先閱讀本教程第一部分,在這部分就pl/0語言的語法及其編譯程式的各個階段作了簡單介紹,以便對pl/0編譯程式有個初步的印象。其次要認真閱讀理解第三部分所給出的pl/0編譯器源程式,使上一階段的初步印象得以加深、具體化。最後按照第二部分的實驗要求擴充pl/0語言的功能並加以實現。

第一部分 pl/0語言及其編譯器

pl/0程式語言是乙個較簡單的語言,它以賦值語句為基礎,構造概念有順序、條件和重複(迴圈)三種。pl/0有子程式概念,包括過程定義(可以巢狀)與呼叫且有區域性變數說明。pl/0中唯一的資料型別是整型,可以用來說明該型別的常量和變數。

當然pl/0也具有通常的算術運算和關係運算。具體的pl/0語法圖見書。

pl/0的語言的詞法分析器將要完成以下工作:

(1) 跳過分隔符(如空格,回車,製表符);

(2) 識別諸如begin,end,if,while等保留字;

(3) 識別非保留字的一般識別符號,此識別符號值(字串行)賦給全域性量id,而全域性量sym賦值為sym_identifier。

(4) 識別數字序列,當前值賦給全域性量num,sym則置為sym_number;

(5) 識別:=,<=,>=之類的特殊符號,全域性量sym則分別被賦值為sym_becomes,sym_leq,sym_geq等。

相關過程(函式)有getsym(),getch(),其中getch()為獲取單個字元的過程,除此之外,它還完成:

(1) 識別且跳過行結束符;

(2) 將輸入原始檔複寫到輸出檔案;

(3) 產生乙份程式列表,輸出相應行號或指令計數器的值。

我們採用遞迴下降的方法來設計pl/0編譯器。以下我們給出該語言的first和follow集合。

注:表中r代表六個關係運算子。

不難證明,pl/0語言屬於ll(1)文法。(證明從略。)

以下是我們給出如何結合語法圖編寫(遞迴下降)語法分析程式的一般方法。假定圖s所對應的程式段為t(s),則:

(1) 用合適的替換將語法約化成盡可能少的單個圖;

(2) 將每乙個圖按下面的規則(3)-(7)翻譯成乙個過程說明;

(3) 順序圖對應復合語句:

對應:begin t(s1); t(s2); ...; t(sn) end

(4) 選擇:

對應:case語句或者條件語句:

case ch ofif ch in l1 then t(s1) else

l1: t(s1if ch in l2 then t(s2) else

l2: t(s2); 或

if ch in ln then t(sn) else

ln: t(snerror

其中li∈first(si),ch為當前輸入符號。(下同)

(5) 迴圈

對應:while ch in l do t(s)

(6) 表示另乙個圖a的圖:

對應:過程呼叫a。

(7) 表示終結符的單元圖:

對應:if ch == x then read(ch) else error

相關過程有:

block(), constdeclaration(), vardeclaration(), statement(), condition(), expression(), term(), factor()等。

它們之間依賴關係如圖1-2:

pl/0的語義分析主要進行以下檢查:

(1) 是否存在識別符號先引用未宣告的情況;

(2) 是否存在己宣告的識別符號的錯誤引用;

(3) 是否存在一般識別符號的多重宣告。

pl/0編譯程式不僅完成通常的詞法分析、語法分析,而且還產生中間**和「目標」**。最終我們要「執行」該目標碼。為了使我們的編譯程式保持適當簡單的水平,不致陷入與本課程無關的實際機器的特有性質的考慮中去,我們假想有台適合pl/0程式執行的計算機,我們稱之為pl/0處理機。

pl/0處理機順序解釋生成的目標**,我們稱之為解釋程式。注意:這裡的假設與我們的編譯概念並不矛盾,在本課程中我們寫的只是乙個示範性的編譯程式,它的後端無法完整地實現,因而只能在乙個解釋性的環境下予以模擬。

從另乙個角度上講,把解釋程式就看成是pl/0機硬體,把解釋執行看成是pl/0的硬體執行,那麼我們所做的工作:由pl/0源語言程式到pl/0機器指令的變換,就是乙個完整的編譯程式。

pl/0處理機有兩類存貯,目標**放在乙個固定的存貯陣列code中,而所需資料組織成乙個棧形式存放。

pl/0處理機的指令集根據pl/0語言的要求而設計,它包括以下的指令:

(1)lit將常數置於棧頂 */

(2)lod將變數值置於棧頂 */

(3)sto將棧頂的值賦與某變數 */

(4)cal用於過程呼叫的指令 */

(5)int在資料棧中分配存貯空間 */

(6)jmp, jpc /* 用於if, while語句的條件或無條件控制轉移指令 */

(7)opr一組算術或邏輯運算指令 */

上述指令的格式由三部分組成:

其中,f, l, a的含義見下表:

上表中,層次差為變數名或過程名引用和宣告之間的靜態層次差別,程式位址為目標陣列code的下標,資料位址為變數在區域性存貯中的相對位址。

pl/0的編譯程式為每一條pl/0源程式的可執行語句生成字尾式目標**。這種**生成方式對於表示式、賦值語句、過程呼叫等的翻譯較簡單。

如賦值語句x := y op z(op為某個運算子),將被翻譯成下面的目標**序列:(設指令計數從第100號開始)

而對if和while語句稍繁瑣一點,因為此時要生成一些跳轉指令,而跳轉的目標位址大都是未知的。為解決這一問題,我們在pl/0編譯程式中採用了回填技術,即產生跳轉目標位址不明確的指令時,先保留這些指令的位址(code陣列的下標),等到目標位址明確後再回過來將該跳轉指令的目標位址補上,使其成為完整的指令。下表是if、while語句目標**生成的模式。

(l1,l2是**位址)

相關過程(函式)有:gen(),其任務是把三個引數f、l、a組裝成一條目標指令並存放於code陣列中,增加cx的值,cx表示下一條即將生成的目標指令的位址。

為了簡單起見,我們假設有乙個pl/0處理機,它能夠解釋執行pl/0編譯程式所生成的目標**。這個pl/0處理機有兩類存貯、乙個指令暫存器和三個位址暫存器組成。程式(目標**)存貯稱為code,由編譯程式裝入,在目標**執行過程中保持不變,因此它可被看成是「唯讀」存貯器。

資料存貯s組織成為乙個棧,所有的算術運算均對棧頂元和次棧頂元進行(一元運算僅作用於棧頂元),並用結果值代替原來的運算物件。棧頂元的位址(下標)記在棧頂暫存器t中,指令暫存器i包含著當前正在解釋執行的指令,程式位址暫存器p指向下一條將取出的指令。

pl/0的每乙個過程可能包含著區域性變數,因為這些過程可以被遞迴地呼叫,故在實際呼叫前,無法為這些區域性變數分配存貯位址。各個過程的資料區在存貯棧s內順序疊起來,每個過程,除使用者定義的變數外,還應當有它自己的內部資訊,即呼叫它的程式段位址(返回位址)和它的呼叫者的資料區位址。在過程終止後,為了恢復原來程式的執行,這兩個位址都是必須的。

我們可將這兩個內部值作為位於該過程資料區的內部式隱式區域性變數。我們把它們分別稱為返回位址(return address)ra和動態鏈(dynamic link)dl。動態鏈的頭,即最新分配的資料區的位址,儲存在某位址暫存器b內。

因為實際的存貯分配是執行(解釋)時進行的,編譯程式不能為其生成的**提供絕對位址,它只能確定變數在資料區內的位置,因此它只能提供相對位址。為了正確地訪問資料,解釋程式需將某個修正量加到相應的資料區的基位址上去。若變數是區域性於當前正在解釋的過程,則此基位址由暫存器b給出,否則,就需要順著資料區的鏈逐層上去找。

然而遺憾的是,編譯程式只能知道訪問路線的表的長度,同時動態鏈儲存的則是過程活動的動態歷史,而這兩條訪問路線並不總是一樣。

《編譯原理》實驗指導書

黃營楊躍武編寫 2014.4 前言編譯原理實驗是為電腦科學與技術專業本科 編譯原理 課程配套設定的,是 編譯原理 課程講授中乙個重要的 不可或缺的實踐環節。通過實驗訓練,達到如下目的 使學生進一步了解和掌握編譯原理,提高對實際專案的分析和設計能力,通過實驗課程,熟悉和基本掌握編譯器的詞法分析,語法分...

編譯原理E實驗指導書

實驗1 詞法程式設計 11 實驗2 詞法程式設計 23 實驗3 語法程式設計 14 實驗4 語法程式設計 25 實驗5 語法程式設計 36 實驗6 中間 生成8 實驗1 詞法程式設計 dfa 確定的有窮自動機 的化簡 一 實驗目的與要求 通過設計 編寫和除錯將確定的有窮自動機的狀態數變為最少的c程式...

編譯原理實驗

實驗三中間的 優化 一 實驗目的 掌握區域性優化方法 提高機器的執行速度 二 相關知識 某些編譯程式在中間 或目標 生產之後要對其進行優化,所謂優化就是對 進行等價的變換。而變換後的 執行結果與變換前的 執行結果相同。而執行速度加快或占用記憶體空間減少。中間的 優化就是對中間 進行等價的變換。基本塊...