三地址碼簡介

三地址碼簡介

三地址碼(Three Address Code)是一種最常用的中間語言,編譯器可以通過它來改進代碼轉換效率。每個三地址碼指令,都可以被分解為一個四元組(4-tuple)的形式:(運算符,操作數1,操作數2,結果)。由于每個陳述都包含了三個變量,即每條指令最多有三個操作數,所以它被稱為三地址碼。

編譯器

編譯器(compiler),是一種計算機程序,它會將用某種編程語言寫成的源代碼(原始語言),轉換成另一種編程語言(目標語言)。

它主要的目的是將便于人編寫、閱讀、維護的高級計算機語言所寫作的源代碼程序,翻譯為計算機能解讀、運行的低階機器語言的程序,也就是可執行文件。編譯器將原始程序(source program)作為輸入,翻譯產生使用目標語言(target language)的等價程序。源代碼一般為高級語言(High-level language),如Pascal、C、C++、C# 、Java等,而目標語言則是匯編語言或目標機器的目標代碼(Object code),有時也稱作機器代碼(Machine code)。

一個現代編譯器的主要工作流程要通常要經過預處理、編譯、匯編、鏈接等步驟。關于編譯器的工作流程的介紹,可參考:從C源代碼到可執行文件的四個過程:預處理、編譯、匯編、鏈接

中間語言

中間語言(Intermediate language),有時也稱為中間表示(Intermediate Rrepresentation,IR)在計算機科學中,是指一種應用于抽象機器(abstract machine)的編程語言,它設計的目的,是用來幫助我們分析計算機程序。這個術語源自于編譯器,在編譯器將源代碼編譯為目的碼的過程中,會先將源代碼轉換為一個或多個的中間表述,以方便編譯器進行最佳化,并最終產生出目的機器的機器語言。通常,中間語言的設計與一般的機器語言有三個不同之處:

  • 每個指令代表僅有一個基本的操作。舉例來說,在微處理器中出現的 shift-add 定址模式在中間語言不會出現。
  • 指令集內可能不會包含控制流程的資訊。
  • 暫存器可用的數量可能會很大,甚至沒有限制。

最常見的中間語言表述形式,是三位址碼(Three address code),常簡稱為 TAC 或 3AC。

這個術語也同時用來代稱一些作為中間層的語言,有些高級語言不會輸出為機器語言,它們僅會輸出這種中間語言,而這些中間語言則會像一般語言一樣,提交給編譯器,編譯為機器語言。這通常被用于讓最佳化的過程更簡單,也用于增進可移植性的能力,改進移植的方式則是利用中間語言的編譯器,可以編譯出許多中央處理器及操作系統可使用的機器碼,例如C語言。中間語言的復雜度,通常介于高階語言及低級語言之間,例如匯編語言。

四元式

四元式主要由四部分組成:OP,arg1,arg2,result,即(操作符,操作數1,操作數2,結果),

其中,OP是運算符,arg1,arg2分別是第一和第二個運算對象,result是編譯程序為存放中間運算結果而引進的變量,常稱為臨時變量。當OP是一目運算時,常常將運算對象定義為arg1。

例如 X = a*b+c/d 的四元式序列:

  1. (*, a, b, T1)
  2. (/, c, d, T2)
  3. (+, T1, T2, T3)
  4. (=, T3, -, X)
  • 四元式出現的順序和語法成份的計值順序相一致。
  • 四元式之間的聯系是通過臨時變量實現的,這樣易于調整和變動四元式。
  • 便于優化處理。

三地址碼

三地址代碼是四元式的另一種表示形式。每個三地址碼指令,都可以被分解為一個四元式(4-tuple)。因為每個陳述都包含了三個變量,所以它被稱為三地址碼。

上面例子 X = a*b+c/d 的三地址序列:

  1. t1=a*b
  2. t2=c/d
  3. t3=t1+t2
  4. X=t3

常用的三地址碼(三地址碼形式和四元組形式)

序號指令類型指令形式備注
1賦值指令x = y op zx = op yop為運算符
2復制指令x = y
3條件跳轉if x relop y goto nrelop為關系運算符
4非條件跳轉goto n跳轉到地址n的指令
5參數傳遞param x將x設置為參數
6過程調用call p,np為過程的名字n為過程的參數的個數
7過程返回return x
8數組引用x=y[i]i為數組的偏移地址,而不是下標
9數組賦值x[i]=y
10地址及指針操作x=&yx=*y *x=y

將上表的三地址指令用四元式表示

x = y op z( op , y , z , x)
x = op y( op , y , _ , x)
x = y( = , y , _ , x)
if x relop y goto n( relop , x , y , n)
goto n( goto , _ , _ , n)
param x( param , _ , _ , x)
call p,n( call , p , n , _)
return x( return , _ , _ , x)
x=y[i]( =[] , y , i , x) ps: y為基地址,i為偏移地址
x[i]=y( []= , y , x , i)
x=&y( & , y , _ , x)
x=*y( =* , y , _ , x)
*x=y( *= , y , _ , x)

每一個指令只有一個操作符,那么只完成一個動作,這樣看來,三地址指令序列唯一確定了運算完成的順序。

中間代碼生成的例子

while a<b doif c<5 thenwhile x>y doz=x+1;else x=y;

100到112為指令的編碼,從100到112順序執行。

100: ( j<, a, b, 102 )如果a<b ,那么跳轉到102指令,否則繼續執行101指令
101: ( j , -, -, 112 )該指令為無條件指令,跳轉到112
102: ( j<, c, 5, 104 )如果c<5 ,那么跳轉到104指令,否則繼續執行103指令
103: ( j , -, - , 110 )該指令為無條件指令,跳轉到110
104: ( j>, x, y, 106 )如果x>y ,那么跳轉到106指令,否則繼續執行105指令
105: ( j , -, - , 100 )該指令為無條件指令,跳轉到100
106: ( + , x, 1 , t1 )x+1的值賦值給t1
107: ( = , t1, - , z )t1的值賦值給z,106和107完成了一條語句
108: ( j , -, - , 104 )該指令為無條件指令,跳轉到104
109: ( j , -, - , 100 )該指令為無條件指令,跳轉到100
110: (= , y, - , x )把y賦值給x,然后執行111指令
111: ( j , -, - , 100 )該指令為無條件指令,跳轉到100
112:結束

中間表示IR的演變歷史

計算機科學家提出三地址代碼的理由如下:三地址代碼是一種線性IR。由于輸入源程序及輸出目標程序都是線性的,因此,線性IR有著其他形式無法比擬的優勢。另外,相對于其他表示形式而言,程序員對于線性表示形式通常會有一種莫名的親切感,編譯器設計者當然也不例外。早期編譯器設計者往往都是匯編語言程序設計的高手,可以非常自然、流暢地閱讀線性的三地址代碼形式。同時,線性表示形式也會降低輸入輸出的實現難度。隨著編譯器"端"、"遍"等概念的出現,IR已經不僅僅是一種存儲在內存中的數據結構。有時它也需要以文件形式轉存輸出,作為接口供其他系統讀取使用。

那么,一定有讀者會心存疑問:為什么將其設計為"三地址"的形式呢?實際上,這是計算機科學家經過多年實踐探索后才得到共識的。三地址代碼并不是唯一的線性IR,只能說是最為常見的而已。在編譯技術領域,二地址代碼、單地址代碼(即棧式機代碼)都曾出現過,也曾在某些應用領域盛行一時,尤其是單地址代碼。

二地址代碼比較簡單,就是選擇其中一個對象同時充當運算分量與目標操作數。在早期,二地址代碼主要就是著眼于x86機器而提出的。不過,實踐證明,這只是人們的一廂情愿而已,即使是針對x86機器,二地址的優勢也并不明顯,它反而可能會給編譯器帶來一定的麻煩,所以這種表示形式已經逐步被淘汰了。

然而,單地址代碼的情況則截然不同了,在現代編譯器設計中,單地址代碼也是應用比較廣泛的一種IR。尤其是近年隨著混合語言的日漸壯大,單地址代碼也重新進入了人們的視野。由于執行單地址代碼程序的棧式機架構相對比較簡單,可以非常方便地構造相關的解釋器或虛擬機,所以單地址代碼深受混合語言設計者的歡迎。讀者熟悉的Java字節碼、.NET的IL都是單地址代碼。棧式機或者單地址代碼與常見的x86體系結構相差甚遠,可能讀者所知不多。不過,單地址代碼還是一種比較有意思的表示形式,因此,筆者想通過一個簡單的實例讓讀者對單地址代碼有所了解。

三地址代碼是在二地址代碼的基礎上發展而來的。二地址代碼的不足之處在于它通常會給其中一個源操作分量帶來一定副作用。當然,這種設計的靈感最初是來源于x86指令系統的,但是卻忘了一個重要的區別:x86指令中往往都是以寄存器作為暫存空間的。而暫存空間對于二地址代碼卻是一個棘手的問題。為了解決二地址代碼的不足,人們提出了一個對源操作分量不產生任何副作用的形式,那就是三地址代碼。也就是說,在一行三地址代碼中,任何運算都不會改變兩個源操作分量。這是三地址代碼與二地址代碼的主要區別。這個特性是非常重要的,它將使得編譯器更自由地復用名字與值,不必考慮代碼帶來的副作用。

一般來說,三地址代碼的大多數操作都是由四項組成,即一個操作碼和三個地址。不過,三地址代碼同樣存在級別差異。隨著語言復雜性的提高,在現代編譯器設計中,三地址代碼的級別概念顯得尤其重要。根據編譯器設計的需要,有些三地址代碼可能近似于源語言,而有些三地址代碼則更接近于目標語言。當然,級別主要就是取決于三地址代碼的操作符及操作分量的復雜性。下面,筆者就操作符及操作分量這兩個話題來討論三地址代碼。

操作符是用于標識三地址代碼操作含義的元素。根據源語言、目標語言的特點,三地址代碼操作符的集合以及抽象程度是各不相同的。其中,抽象程度是三地址代碼設計中的重要因素之一。一般而言,三地址代碼將包含大部分低級操作,即目標機所支持的指令。不過,這并不意味著三地址代碼就是機器指令系統的映射。設計者應該從便于后端處理的角度考慮,盡可能地發揮三地址代碼作為中間語言的作用

Ref:

https://zh.m.wikipedia.org/wiki/%E4%B8%89%E4%BD%8D%E5%9D%80%E7%A2%BC

https://baike.baidu.com/item/%E4%B8%89%E5%9C%B0%E5%9D%80%E7%A0%81/23121007

https://blog.csdn.net/starter_____/article/details/90146048

https://jishuin.proginn.com/p/763bfbd55cbd

https://book.51cto.com/art/201206/340208.htm

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/532651.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/532651.shtml
英文地址,請注明出處:http://en.pswp.cn/news/532651.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

llvm與gcc

llvm與gcc llvm 是一個編譯器&#xff0c;也是一個編譯器架構&#xff0c;是一系列編譯工具&#xff0c;也是一個編譯器工具鏈&#xff0c;開源 C11 實現。 gcc 相對于 clang 的優勢&#xff1a; gcc 支持更過語言前端&#xff0c;如 Java, Ada, FORTRAN, Go等gcc 支持更多地 …

攻防世界web新手區解題 view_source / robots / backup

1**. view_source** 題目描述&#xff1a;X老師讓小寧同學查看一個網頁的源代碼&#xff0c;但小寧同學發現鼠標右鍵好像不管用了。 f12查看源碼即可發現flag 2. robots 題目描述&#xff1a;X老師上課講了Robots協議&#xff0c;小寧同學卻上課打了瞌睡&#xff0c;趕緊來教教…

python參數傳遞*args和**kwargs

python參數傳遞*args和**kwargs 和* 實際上真正的Python參數傳遞語法是 * 和 ** 。*args 和 **kwargs 只是一種約定俗成的編程實踐。我們也可以寫成 *vars 和 **kvars 。就如同其他常規變量的命名一樣&#xff0c; args 和 kwargs 只是一種習慣的名稱。 *args 和 **kwargs 一…

聽GPT 講Rust源代碼--src/tools(25)

File: rust/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs 在Rust源代碼中&#xff0c;suspicious_command_arg_space.rs文件位于clippy_lints工具包的methods目錄下&#xff0c;用于實現Clippy lint SUSPICIOUS_COMMAND_ARG_SPACE。 Clippy是Ru…

Java一次編譯,到處運行是如何實現的

Java一次編譯&#xff0c;到處運行是如何實現的 轉自&#xff1a;https://cloud.tencent.com/developer/article/1415194 &#xff08;排版微調&#xff09; JAVA編譯運行總覽 Java是一種高級語言&#xff0c;要讓計算機執行你撰寫的Java程序&#xff0c;也得通過編譯程序的…

JIT(動態編譯)和AOT(靜態編譯)編譯技術比較

JIT&#xff08;動態編譯&#xff09;和AOT&#xff08;靜態編譯&#xff09;編譯技術比較 轉自&#xff1a;https://www.cnblogs.com/tinytiny/p/3200448.html Java 應用程序的性能經常成為開發社區中的討論熱點。因為該語言的設計初衷是使用解釋的方式支持應用程序的可移植…

python解釋器

python解釋器 計算機編程語言 本部分參考自&#xff1a;https://zhuanlan.zhihu.com/p/141212114 從計算機編程語言說起&#xff0c;它主要分為三類&#xff1a;機器語言、匯編語言、高級語言。 機器語言是一種計算機可以直接識別并執行的二進制指令集。由于其可以直接交給…

編譯型語言與解釋型語言

編譯型語言與解釋型語言 首先要說明&#xff0c;編譯型語言與解釋型語言這種分類方法是不科學的&#xff0c;或者說已經過時了&#xff0c;但是這種稱呼大抵還是能夠讓人明白我們將要討論的是什么東西。 文中所列參考是筆者認為比較有幫助的一些擴展閱讀內容。 首先貼一個很形…

常見的各種shell及其區別

常見的各種shell及其區別 引子 for((i1;i<10;i)); do echo $(expr $i \* 3 1); done 網上搜到的 shell for循環腳本&#xff0c;別人都能正常運行&#xff0c;我卻報錯&#xff1a; Syntax error: Bad for loop variable究竟是怎么回事呢&#xff1f; shell簡介…

shell腳本 變量

shell腳本 變量類型 什么是Shell變量 用一個固定的字符串去表示不固定的內容。 Shell變量的類型 shell腳本中自定義變量的類型&#xff0c;我們這里分為&#xff1a; 自定義變量環境變量位置變量與定義變量 這四類&#xff0c;它們有一些相同點&#xff0c;但又有些不同點…

攻防世界web新手區解題 /cookie / disabled_button / weak_auth

cookie 題目描述&#xff1a;X老師告訴小寧他在cookie里放了些東西&#xff0c;小寧疑惑地想&#xff1a;‘這是夾心餅干的意思嗎&#xff1f;’ 使用burp suite抓包查看 發現提示&#xff1a; look-herecookie.php 于是在url后加上 cookie.php 得到提示查看返回 就得到了f…

Python 函數式編程

Python 函數式編程 轉自&#xff1a;https://www.liaoxuefeng.com/wiki/1016959663602400/1017328525009056&#xff0c;推薦去該鏈接讀原文&#xff0c;有習題和熱烈的評論區交流。 函數式編程 函數是Python內建支持的一種封裝&#xff0c;我們通過把大段代碼拆成函數&…

Python中的生成器與迭代器

Python中的生成器與迭代器 轉自&#xff1a;https://www.liaoxuefeng.com/wiki/1016959663602400/1017323698112640&#xff0c;推薦去該鏈接讀原文&#xff0c;有習題和熱烈的評論區交流。 生成器 通過列表生成式&#xff0c;我們可以直接創建一個列表。但是&#xff0c;受…

基于GET報錯的sql注入,sqli-lab 1~4

根據注入類型可將sql注入分為兩類&#xff1a;數字型和字符型 例如&#xff1a; 數字型&#xff1a; sleect * from table where if 用戶輸入id 字符型&#xff1a;select * from table where id 用戶輸入id &#xff08;有引號) 通過URL中修改對應的D值&#xff0c;為正常數字…

Python 裝飾器詳解(上)

Python 裝飾器詳解&#xff08;上&#xff09; 轉自&#xff1a;https://blog.csdn.net/qq_27825451/article/details/84396970&#xff0c;博主僅對其中 demo 實現中不適合python3 版本的語法進行修改&#xff0c;并微調了排版&#xff0c;本轉載博客全部例程博主均已親測可行…

xss原理和注入類型

XSS漏洞原理 : XSS又叫CSS(cross Site Script), 跨站腳本攻擊,指的是惡意攻擊者往Web頁面里插入惡意JS代碼,當用戶瀏覽該頁時,嵌入其中的Web里的JS代碼就會被執行,從而達到惡意的特殊目的. 比如:拿到cooike XSS漏洞分類: 反射性(非存儲型) payload沒有經過存儲,后端接收后,直接…

Python 裝飾器詳解(中)

Python 裝飾器詳解&#xff08;中&#xff09; 轉自&#xff1a;https://blog.csdn.net/qq_27825451/article/details/84581272&#xff0c;博主僅對其中 demo 實現中不適合python3 版本的語法進行修改&#xff0c;并微調了排版&#xff0c;本轉載博客全部例程博主均已親測可行…

存儲型xss案例

存儲型xss原理: 攻擊者在頁面插入xss代碼,服務端將數據存入數據庫,當用戶訪問存在xss漏洞的頁面時,服務端從數據庫取出數據展示到頁面上,導致xss代碼執行,達到攻擊效果 案例: 在一個搭建的論壇網站中, 根據存儲型xss注入的條件,要找到可以存儲到數據庫的輸入位置,并且這個位置…

反射型XSS案例

**原理:**攻擊者將url中插入xss代碼,服務端將url中的xss代碼輸出到頁面上,攻擊者將帶有xss代碼的url發送給用戶,用戶打開后受到xss攻擊 需要url中有可以修改的參數 案例: 可能存在反射型xss的功能(點) : 搜索框等&#xff08;所有url會出現參數的地方都可以嘗試&#xff09;……

Python 裝飾器詳解(下)

Python 裝飾器詳解&#xff08;下&#xff09; 轉自&#xff1a;https://blog.csdn.net/qq_27825451/article/details/84627016&#xff0c;博主僅對其中 demo 實現中不適合python3 版本的語法進行修改&#xff0c;并微調了排版&#xff0c;本轉載博客全部例程博主均已親測可行…