第七章:語義分析和中間程式碼的產生
一.語義分析概述
1.語義分析的任務
1)審查每一個語法結構的靜態語義,即驗證語法正確的結構是否有意義。
如:賦值語句:x:=x+y,左邊變數型別與右邊變數型別是否一致。
2)在語義正確的基礎上生成一種中間程式碼或目的碼。
2.語義分析的範圍
1)確定型別:確定識別符號所關聯的資料型別。
2)型別檢查:按語言的型別規則,檢查運算的合法性與運算分量型別的一致性,必要時作型別轉換。
3)識別含義:根據語言的語義定義(形式或非形式),識別程式中各構造成分組合到一起的含義,並作相應的語義處理(生成中間程式碼或目的碼)。
4.控制流檢查:控制流語句必須轉移到合法的地方。如C中,break語句規定跳出最內層的迴圈或switch語句。
5.一致性檢查:在很多場合要求物件只能被說明一次。如:pascal語言規定同一個識別符號在一個分程式中只能被說明一次等。
6.相關名字檢查:如:Ada,迴圈或塊可以有一個名字,它出現在這些結構的開頭或結尾。編譯程式必須檢查這兩個地方用的名字是否相同。
其它:如名字的作用域分析等也是語義分析的工作。
3.語義描述工具和語義分析方法
1)語義描述工具
目前流行:用屬性文法作為描述語義的工具。
2)語義分析方法
根據描述屬性文法的語義規則的方式不同分為:
語法制導定義
翻譯方案
3)自底向上的語法制導翻譯
自頂向下的語法制導翻譯
二.幾種常用的中間語言形式
1.逆波蘭表示法
波蘭表示是一種既不須考慮優先關係、又不用括號的一種表示表示式的方法(字首式)。
現在我們要介紹的剛好是另一種波蘭表示形式,稱為字尾式,即運算子在後。
2.圖表示法
抽象語法樹。
無迴圈有向圖(DAG)
DAG與抽象語法樹基本上一樣,對錶達式中的每個子表示式,DAG中都有一個結點。一個內部結點表示一個操作符,它的孩子表示運算元。
兩者所不同的是,在一個DAG中代表公共子表示式的結點具有多個父結點,而在一棵抽象語法樹中公共子表示式被表示為重複的子樹。
3.三元式
1)三元式由三個部分組成:
算符:OP
第一運算分量:ARG1
第二運算分量:ARG2
4.間接三元式
在三元式的基礎上附加一張指示器表─間接碼錶,按運算的先後順序列出有關三元式在三元式表中的位置。這種表示方法稱為間接三元式。
例: 語句X:=(A+B)*C; Y:=D↑(A+B)的間接三元式
5.四元式
一個四元式是一個帶有四個域的記錄結構:op,arg1,arg2及result。它實際上就是一條三地址的指令。
例:A+B*(C-D)-E/F↑G的四元式為:
OP ARG1 ARG2 RESULT
① - C D T1
② * B T1 T2
③ + A T2 T3
④ ↑ F G T4
⑤ / E T4 T5
⑥ - T3 T5 T6
三.中間程式碼
1.中間語言:語法樹 字尾式 三地址程式碼表示
(1)圖表示法
語法樹,有向非迴圈圖和字尾式表示源程式的自然層次結構
(2)三地址程式碼
一般形式 x:=y op z
(3)三地址語句的種類
1)賦值語句 x:=y op z,op為二目算術算符或邏輯算符;
2)賦值語句 x:=op y ,op為一目算符,如一目減uminus、邏輯非not、移位算符及轉換算符;
3)無條件轉移語句goto L;
4)條件轉移語句 if x relop y goto L,關係運算符號relop(< ,=,>= 等等);
5)複製語句 x:=y;
6)過程呼叫語句 param x 和 call p, n ;
7)索引賦值 x:=y[i] 及 x[i] :=y ;
8)地址和指標賦值 x=&y,x=* y和 * x=y。
(4)語法制導翻譯生成三地址程式碼
1)E.place表示存放E值的名字。
2)E.code表示對E求值的三地址語句序列
3)newtemp是個函式,對它的呼叫將產生 一個新的臨時變數。
(5)三地址程式碼的具體實現
1)四元式 op, arg1, arg2, result
三元式 op, arg1, arg2
四元式需要利用較多的臨時單元,四元式之 間 的聯絡通過臨時變數實現。
中間程式碼優化處理時,四元式比三元式方便的多,間接三元式與四元式同樣方便,兩種實現方式需要的儲存空間大體相同。
四.常用語句的翻譯
1 .說明語句
說明語句的翻譯對應每個區域性的名字,在符號表中建立相應的表項,填寫有關的資訊如型別、巢狀深度、相對地址,內情向量等。2. 賦值語句
賦值語句的翻譯:表示式的成分可以是整型量、實型量、陣列 元素和記錄
1)符號表中的名字
名字可以理解為指向符號表中相應該名字表項的指標
2)簡單算術表示式及賦值語句
3)陣列元素地址分配(複雜賦值語句)
陣列元素地址的計算公式
①一維陣列的陣列元素計算公式:bace-low*w + i*w
②對於一個二維陣列,可以按行或按列存放: base-((low1 *n2)+low2)*w+ ((i1*n2)+i2)* w
③多維陣列A[i1,i2,...,ik] 的地址的計算:a[i1,i2,…in]的地址=base-c+v
c=((...((low1*n2+low2)*n3+low3)...)*nk+lowk) * w
變數部分v= ((...((i1*n2+i2)*n3+i3...)*nk+ik)*w
3. 布林表示式 :用布林運算子號(and,or,not)作用到布林變數或關係表示式上而組成
布林表示式的作用:
1. 用作計算邏輯值
2. 用作控制流語句如if-then,if-then-else和while-do等之中的條件表示式
(1)翻譯布林表示式的方法
1)表示一個布林表示式的值
方法一:用數值表示真和假,從而對布林表示式的求值可以象對算術表示式的求值那樣一步一步地來計算
方法二:另一種方法是根據布林表示式的特點,採用了某種優化措施。
2)數值表示法
用1表示真,0表示假來實現布林表示式的翻譯
3)布林表示式的數值表示法的翻譯模式
emit用於將一個三地址語句輸送到檔案中
Nextquat是一個計數器,指向下一個三地址語句在輸出序列中的索引序號,也就是即將生成的三地址語句序號。
(4)控制流語句中的布林表示式的翻譯
對於出現在條件語句 if E then s1 else s2中的布林表示式E,其作用就是控制對S1和S2的選擇
因此,作為條件的布林表示式,把它設計成兩個出口:E.true 和 E.false
考慮E的上下文,對於IF語句,E.true 指向S1, E.false指向S2;
對於while語句E.true 指向迴圈的開始, E.false指向while 的下一語句
4.過程呼叫
一個過程呼叫的翻譯包括一個呼叫序列,即進入和離開每一個過程所採取的動作序列。
發生一個過程呼叫時:為被呼叫過程傳遞連線資料
①把實在引數的資訊傳遞到被呼叫過程的可取的指定位置;
②建立環境指標以便被呼叫過程能存取非區域性過程的資料;
③保留呼叫過程的執行狀態;
④返回地址應存入指定的單元中;
⑤應生成一條轉移指令轉移到被呼叫過程的程式碼的開始位置。
從過程返回時:
①如果被呼叫過程是一個函式,則需將返回的結果值存放在一個指定的位置 上;
②呼叫過程的活動記錄需要恢復;
③應生成一條轉移指令轉移到呼叫過程的返回地址;
五.知識應用
六.總結
本章理解起來較為簡單。主要是逆波蘭式,三元式,間接三元式,四元式序列,還有語法樹,DAG圖。重點是中間程式碼這部分。其中主要是“翻譯”,通過判斷語句在之後三元式地址碼,最後翻譯出結果。