250 likes | 502 Views
編譯器設計. 教師:何慶祥 Email: ch.ho@center.fjtc.edu.tw Room: a309b. 原始程式. 目的程式. 編譯器. 錯誤信息. 編譯器. Analysis-Synthesis Model 分析 Analysis: 原始程式轉換成階層結構稱為樹 (tree) ,語法樹 (syntax tree) 合成 Synthesis: 產生目標碼. 分析. 編譯器的分析過程可分為三階段 線性 (linear) 分析:將原始程式以字元為單位,由左至右群組出標識 (token) 串列,每一個標識都是一個有意義的字串。
E N D
編譯器設計 教師:何慶祥 Email: ch.ho@center.fjtc.edu.tw Room: a309b
原始程式 目的程式 編譯器 錯誤信息 編譯器 • Analysis-Synthesis Model • 分析Analysis: 原始程式轉換成階層結構稱為樹(tree),語法樹(syntax tree) • 合成Synthesis: 產生目標碼
分析 • 編譯器的分析過程可分為三階段 • 線性(linear)分析:將原始程式以字元為單位,由左至右群組出標識(token)串列,每一個標識都是一個有意義的字串。 • 階層(hierarchical)分析:標識串列會被以階層的方式群組出巢狀結構。 • 語意(semantic)分析:確認程式的每個單元都具有意義。
語句(Lexical)分析 • 又稱為線性分析或掃描(scanning) • 舉例來說 • position = initial + rate * 60 ; • 會被群組成下列標識(token) • 1. 識別字 position 2. 指定符號 = 3. 識別字 initial 4. 加號 + 5. 識別字 rate 6.加號 * 7. 數值 60 8. 指令結束符號 ; • 空白會被忽略不記。
習題一 • 撰寫一個scanner分析四則運算指令(僅變數與整數)。其中 • = 為指定運算元, + - * / 為四則運算元。 • 識別字第一個字元必須是字母,其餘字元可以是字母或數字。 • 建立一個符號表(可用陣列)。 • 識別字與數值長度最長為5個字元。 • 測試檔案名稱 statement.txt • 由螢幕列印出所有標識(tokens) • 若標識有不符規則,列出錯誤訊息。
習題一 • 若指令檔statement.txt的內容為 position = initial + rate * 60 ; • 則螢幕輸出標識為 position = initial + rate * 60 ;
語法(Syntax)分析 • 又稱為階層(hierarchical)分析、剖析(parsing)或文法(grammatical)分析。 • 將標識(token)群組成文法片語(grammatical phrases),這些片語會被用來合成輸出碼。 • 通常這些文法片語會被表示為剖析樹
指定指令 = 識別字 position 表示式 + 表示式 識別字 initial 表示式 * 表示式 識別字 rate 表示式 數值 60 語法(Syntax)分析 • 剖析樹 (parse tree)範例 • position = initial + rate * 60 ;
語法(Syntax)分析 • 通常會建立遞迴的(recursive)規則如 • 1. 識別字也是表示式 • 2. 數值也是表示式 • 3. 表示式1與表示式2可形成下列表示式 • 表示式1 + 表示式2 • 表示式1 * 表示式2 • (表示式1)
語法(Syntax)分析 • 式1與式2是非遞迴表示式,式3是一種遞迴表示式 • 許多語言定義指令也是遞迴地使用規則,如 • 1. 若 identifier1是識別字 expression2是表示式則 identifier1 = expression2是指令 • 2. 若 expression1是表示式 statement2是指令 則 while (expression1) statement2以及 if (expression1) statement2式指令
語法(Syntax)分析 • 語句與語法分析的分界在於,前者不用遞迴而後者卻使用遞迴。 • 識別字標識的檢出:識別字標識開始於合法開始字元集合元素 (如字母),結束於非識別字標識之字元集合元素(如字母與數字)的前一個字元。並將之存於符號表(symbol table)。再將處理完的部份除去,準備尋找下一個標識。 • 線性掃描並不適合分析表示式或指令。
= = + position + position initial * initial * rate inttoreal rate 60 60 語法(Syntax)分析 • 語法樹為剖析樹的簡化版,其中運算元是內部節點,而運算子則是該節點的子節點
語意(semantic)分析 • 檢查語意錯誤,並收集型態(type)資訊以備碼的產生(code-generation)。 • 例如:若前例中的變數型態都是實數,而60是整數則在執行乘法運算前,60必需轉為實數。在前頁的圖中加入一個節點給運算元inttoreal,因為運算子是常數,編譯器可直接將整數轉為實數表示。
編譯器可分解成幾個階段 • 組成編譯器的階段,前三階段進行分析 來源程式 語句分析 語法分析 語意分析 符號表管理 錯誤管理 中間碼的產生 碼的最佳化 碼的產生 目的程式
符號表管理 • 記錄識別字及他們的屬性。這些資訊(型態type、範圍scope、所屬程序名稱、號碼及形態、傳遞方法、回傳型態等)關係到資料儲存的方式。 • 符號表的資料結構包括,識別字的紀錄,及記錄屬性的欄位。必須提供快速容易的存取方法。
分析階段 - 語句 • 語句分析階段,讀取原始程式碼的字元,並組合成標識串。 • 標識可能是,識別字、關鍵字、標點、多字元運算元。組成標識的字元串稱為lexeme。 • 當一個識別字輩偵測出來,語法分析器會產生一個標識(id),但lexeme rate會被放入符號表。 • 在此id1, id2, id3, 分別表示position, initial, 及rate。
分析階段 - 語法 • 將階層結構強加於標識串,以語法樹描述。語法樹及其資料結構可參照圖。 • 內部節點中,一個欄位記錄運算元,另兩個欄位記錄左右二個子節點的指標,葉節點記錄標識及其他資訊。
position = initial + rate * 60; Lexical analyzer Lexical analyzer temp1 = inttoreal(60); temp2 = id3 * temp1; temp3 = id2 + temp2; id1 = temp3; id1 = id2 + id3 * 60 syntax analyzer Lexical analyzer temp1 = id3 * 60.0; id1 = id2 + temp1; = id1 + id2 * Lexical analyzer id3 60 semantic analyzer = MOVF id3, R2; MULF #60.0, R2; MOVF id2, R1; ADDF R2, R1 MOVF R1, id1 id1 + id2 * id3 inttoreal 60 翻譯指令
中間碼的產生 • 虛擬機器的程式:容易達成,容易轉成目的程式 • Three-address code:assembly-language-like, memory location like register. • 最多三個運算子(有可能更少)。一個指定運算元外最多一個運算元。 • 編譯器要決定指令中運算元執行的順序,如先乘除後加減。 • 暫時變數儲存運算結果。
碼的最佳化 • 改善中間碼的效能。 • inttoreal可以在編譯階段即完成。 • temp3可以被取代。 • optimizing compilers 主要時間消耗於本階段。
碼的產生 • 目的碼多是機械碼或組合語言。 • 每一個變數對應到記憶體位置。 • 中間運算對應到機器指令。 • 關鍵在於如何將變數對應到暫存器。 • 例子中F表示浮點運算。
= id1 + id2 * id3 60 樹狀圖的資料結構 • 右圖的資料結構可用來實現左圖的樹狀圖 = | | id | 1 + | | * | | id | 2 id | 3 num | 1