Atitti. 語法樹AST、后綴表達式、DAG、三地址代碼
抽象語法樹的觀點認為任何復雜的語句嵌套情況都可以借助於樹的形式加以描述。確實,不得不承認應用抽象語法樹可以使語句翻譯變得相對容易,它很好地描述了語句、表達式之間的聯系。不過,由於Neo Pascal並不會顯式構造抽象語法樹,所以不得不借助於其他數據結構實現。根據先前的經驗,棧結構就是不二之選。
DAG(有向無環圖)
后綴表達式:也稱為逆波蘭表達式,這種形式簡單明晰,便於存儲。在處理表達式翻譯時,后綴表達式有着其他形式無法比擬的優勢。不過,由於后綴表達式的應用領域比較單一,所以很少獨立作為一個實際編譯器的IR存在。
1. 后綴表達式
不包含括號,運算符放在兩個運算對象的后面,所有的計算按運算符出現的順序,嚴格從左向右進行(不再考慮運算符的優先規則,如:(2 + 1) * 3 , 即2 1 + 3 *
作者:: ★(attilax)>>> 綽號:老哇的爪子 ( 全名::Attilax Akbar Al Rapanui 阿提拉克斯 阿克巴 阿爾 拉帕努伊 ) 漢字名:艾龍, EMAIL:1466519819@qq.com
轉載請注明來源: http://www.cnblogs.com/attilax/
1.1. 前綴記法、中綴記法和后綴記法
它們都是對表達式的記法,因此也被稱為前綴記法、中綴記法和后綴記法。它們之間的區別在於運算符相對與操作數的位置不同:前綴表達式的運算符位於與其相關的操作數之前;中綴和后綴同理。
舉例:
(3 + 4) × 5 - 6 就是中綴表達式
- × + 3 4 5 6 前綴表達式
3 4 + 5 × 6 - 后綴表達式
中綴表達式(中綴記法)
中綴表達式是一種通用的算術或邏輯公式表示方法,操作符以中綴形式處於操作數的中間。中綴表達式是人們常用的算術表示方法。
雖然人的大腦很容易理解與分析中綴表達式,但對計算機來說中綴表達式卻是很復雜的,因此計算表達式的值時,通常需要先將中綴表達式轉換為前綴或后綴表達式,然后再進行求值。對計算機來說,計算前綴或后綴表達式的值非常簡單。
三地址代碼:也稱為"四元組",即操作符和三個操作數地址。這是一種最為常見的IR。甚至有些書籍認為IR就是中間代碼(即三地址代碼
所謂的三地址,指的就是每一行代碼通常包含三個地址信息,即操作數1、操作數2、結果操作數。例如,(ADD A,1,C )這行三地址代碼的含義就是A+1→C。這種形式初看與匯編語言有點類似
當然,三地址代碼也不是完美的,由於它是相對離散的,在分析源程序結構方面,它就不及語法樹便捷
三地址代碼的理由如下:三地址代碼是一種線性IR。由於輸入源程序及輸出目標程序都是線性的,因此,線性IR有着其他形式無法比擬的優勢。另外,相對於其他表示形式而言,程序員對於線性表示形式通常會有一種莫名的親切感,編譯器設計者當然也不例外。早期編譯器設計者往往都是匯編語言程序設計的高手,可以非常自然、流暢地閱讀線性的三地址代碼形式。同時,線性表示形式也會降低輸入輸出的實現難度。隨着編譯器"端"、"遍"等概念的出現,IR已經不僅僅是一種存儲在內存中的數據結構。有時它也需要以文件形式轉存輸出,作為接口供其他系統讀取使用。
為什么將其設計為"三地址"的形式呢?實際上,這是計算機科學家經過多年實踐探索后才得到共識的。三地址代碼並不是唯一的線性IR,只能說是最為常見的而已。在編譯技術領域,二地址代碼、單地址代碼(即棧式機代碼)都曾出現過,也曾在某些應用領域盛行一時,尤其是單地址代碼。
然而,單地址代碼的情況則截然不同了,在現代編譯器設計中,單地址代碼也是應用比較廣泛的一種IR。尤其是近年隨着混合語言的日漸壯大,單地址代碼也重新進入了人們的視野。由於執行單地址代碼程序的棧式機架構相對比較簡單,可以非常方便地構造相關的解釋器或虛擬機,所以單地址代碼深受混合語言設計者的歡迎。讀者熟悉的Java字節碼、.NET的IL都是單地址代碼
三地址代碼是在二地址代碼的基礎上發展而來的。二地址代碼的不足之處在於它通常會給其中一個源操作分量帶來一定副作用。當然,這種設計的靈感最初是來源於x86指令系統的,但是卻忘了一個重要的區別:x86指令中往往都是以寄存器作為暫存空間的。而暫存空間對於二地址代碼卻是一個棘手的問題。為了解決二地址代碼的不足,人們提出了一個對源操作分量不產生任何副作用的形式,那就是三地址代碼。也就是說,在一行三地址代碼中,任何運算都不會改變兩個源操作分量。這是三地址代碼與二地址代碼的主要區別。這個特性是非常重要的,它將使得編譯器更自由地復用名字與值,不必考慮代碼帶來的副作用。
最后,再來談談IR的級別,即IR依賴於目標機的程度。按級別分類,可將IR分成三類:高級形式(HIR)、中級形式(MIR)、低級形式(LIR),也可稱為高級中間語言、中級中間語言、低級中間語言。
高級形式(HIR)是一種盡可能保持了源語言程序結構的IR,這種形式能較好地保留源程序的原始語義信息。由於高級形式太接近源語言程序結構,所以很少有編譯器將其獨立作為IR傳遞給后端。
中級形式(MIR)既要以一種與語言無關的方式在一定程度上反映源語言的特性,又要能夠適應多種體系結構的IR。中級形式是一種比較常用的IR,它兼顧了源語言、目標機的特性,又能適用於大多數優化算法。當一個編譯器僅設計一種IR時,中級形式是較理想的選擇。
低級形式(LIR)就是在一定程度上包含某些目標機特性的IR,比目標語言稍高級,常作為一些機器相關的優化算法的輸入。不過,實際上,除了一些較大型的編譯器需要使用低級形式之外,低級形式並不是很常見。因為更多編譯器設計者更願意直接基於目標語言作優化。
表5-6 if語句的翻譯方案
if語句 |
翻 譯 方 案 |
if <表達式> then <語句1> else <語句2> |
<表達式翻譯> (JNT , <表達式結果> , null , __L1 ) <語句1> (JMP , __L2 , null , null ) (LABEL , __L1 , null , null ) <語句2> (LABEL , __L2 , null , null ) |
如果省略了else部分,那么只需將翻譯方案中第4~6行語句省略,並將第7行的"__L2"替換為"__L1"即可。semantic068、semantic069、semantic070主要的功能就是根據翻譯方案翻譯輸入的if語句。也就是說,試圖依靠這三個語義子程序,完成翻譯方案中黑體語句的生成。在上述翻譯方案中,可以暫且將"__L1"稱為"假分支標號",而將"__L2"稱為"出口標號"。另外,需注意一點,當輸入語句是if-then結構時,第7行語句的標號不應該取出口標號,而應該取假分支標號,因為此時並不存在真正意義的假分支,因此,可以將假分支標號當作出口標號使用。
while語句的翻譯方案
while語句 |
翻譯方案 |
while <表達式> do <語句> |
(LABEL ,__L1,null,null) <表達式翻譯> (JNT ,<表達式結果>,null,__L0) <語句> (JMP ,__L1,null,null) (LABEL ,__L0,null,null) |
5.1.2 IR設計及其級別 - 51CTO.COM.html