編譯原理 -- 語法制導翻譯

語法制導翻譯

語法制導翻譯是通過向一個文法的產生式附加一些規則或程序片段而得到的。

語法制導翻譯的兩個概念

下面是與語法制導翻譯相關的兩個概念:

  • 屬性(attribute) : 表示與某個程序構造相關的量。這個屬性就是我們平常所理解的 屬性,可以是表達式的數據類型,指定數據類型的字節大小,生成的代碼中的指令數目,等等等。
  • (語法制導的)翻譯方案:翻譯方案是一種將程序片段附加到一個文法的各個產生式上的表示法。這個程序片段就是你用來翻譯這個產生式的翻譯程序。將這些翻譯程序的輸出結果(翻譯結果)按照一定的順序組合起來,就成了最終的翻譯結果。

綜合屬性與繼承屬性

綜合屬性即“自底向上”求值的屬性,綜合屬性的值是由屬性值所在結點及其子結點確定的。對(語法分析樹的)某個結點的綜合屬性的值只需要對(語法分析樹的)該結點做自底向上遍歷就可得到。

相對於“自底向上”求值的綜合屬性,編譯原理裏還有一種重要的“自頂向下”求值的屬性,叫做 繼承屬性 ,繼承屬性的值是由屬性所在結點及其父節點、兄弟結點決定的。

語法制導定義
① 每個文法符號和一個屬性集合相關聯。
② 每個產生式和一組語義規則相關聯。這些規則用於計算該產生式的相關屬性值。

如果將語法分析樹的各個結點的屬性標記在語法分析樹上,那麼這棵語法分析樹我們稱之爲註釋語法樹

我們通過深度優先遍歷整棵註釋語法樹,可以自底向上計算整棵樹所擁有的所有綜合屬性。假設我們對於每一個結點有屬性t,表示該結點的翻譯結果,當我們遍歷完畢整棵樹,每個結點的屬性t都計算完畢,那麼這棵樹就翻譯完成了—我們只需要取得樹的根節點的t屬性即可。

下面是一個例子,該例子演示了將中綴表達式9+5轉換爲後綴表達式95+的過程。
我們假設expr和term有屬性t,表示該產生式對應的翻譯結果:

編號 產生式 語義規則
1 expr -> term + expr1 expr.t = term.t || expr1.t || ‘+’
2 expr -> term expr.t = term.t
3 term -> 0 term.t = ‘0’
4 term -> 1 term.t = ‘1’
12 term -> 9 term.t = ‘9’

(注意上面的||代表字符串連接符)

我們可以得到如下語法分析樹:

5
9
expr
expr
+
term
term

最初的註釋分析樹上屬性都爲空,故上圖沒有畫出屬性部分。
我們開始深度優先遍歷這棵樹。
當我們遍歷到左邊第一顆term結點時,我們發現其下有一個結點9.剛好符合上表中編號爲12的產生式。於是我們根據12號產生式對應的語義規則給左邊的term結點賦予值爲’9’的屬性t。當遍歷到右邊的expr結點時,繼續深度遍歷到右邊的term,根據相應的語義規則賦予完右邊的term、expr之後註釋語法樹如下圖所示:

5
9
expr
expr.t='9'
+
term.t='5'
term.t='9'

當我們遍歷到根結點expr時,發現符合1號產生式。於是我們按照對應的語義規則賦予根節點的屬性expr.t:

5
9
expr.t='95+'
expr.t='9'
+
term.t='5'
term.t='9'

我們可以從根節點的屬性t得到最終的翻譯結果,如此一來,我們就完成了這棵語法樹的翻譯工作。下面,我們來看另一種翻譯方法:

我們可以在文法產生式裏附加上一些程序片斷,用於輸出產生式對應的語法樹的節點的翻譯結果,當我們遍歷這顆語法樹時,就可以逐步輸出整棵語法樹的翻譯結果了。這是不同於註釋語法樹的翻譯方法,我們稱之爲語法制導翻譯方案。用於翻譯的程序片段我們稱之爲語義動作。一個語義動作用花括號括起來,並寫入產生式的體中。如下面所示是一個鑲嵌了語義動作的產生式例子,這個例子同樣是將中綴表達式翻譯成後綴表達式的例子:
rest -> term + term {print ('+')}
term -> 0 {print ('0')} | 1 {print ('1')} | 2 {print ('2')} | ... | 9 {print ('9')}
語句1+2對應的鑲嵌了語義動作的語法分析樹如下所示。

1
2
rest
term
+
term
{print ('+')}
{print ('1')}
{print ('2')}

我們在翻譯時,按深度優先遍歷這棵樹,沒有鑲嵌了語義動作的不予以輸出,只輸出鑲嵌了語義動作的結點的運行結果。當遍歷完成,我們就得到了翻譯結果:12+

發佈了16 篇原創文章 · 獲贊 2 · 訪問量 6986
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章