編譯過程中間語言
❶ 編譯過程中,源程序為什麼要通過中間代碼生成目標程序
源程序是指程序員編寫的代碼,可以被編譯程序編譯為目標程序。
如果是c++,那麼後綴為.cpp
目標程序是編譯程序將源程序編譯後的結果,如果是c++,那麼後綴是.o
編譯程序一般是編譯器公司(比如微軟
intel他們都生產編譯器)做的,它將源代碼轉化為機器可識別的文件,經過鏈接,生成可執行程序。
解釋程序即解釋器,它不需要經過編譯階段即可根據用戶源程序執行。
程序語言分編譯類和解釋類語言。
❷ 編譯過程分為哪幾個階段各階段的遵循的原則、識別機構、使用的文法編譯原理
編譯原理中的遍概念
編譯階段也常常劃分為兩大步驟,分析步驟和綜合步驟 分析步驟和綜合步驟 分析步驟是指對源程序的分析 -線性分析(詞法分析或掃描) -層次分析(語法分析) -語義分析 綜合步驟是指後端的工作,為目標程序的生成而進行的綜合
你分析過嗎?若按照這種組合方式實現編譯程序,可以設想,某一編譯程序的前端加上相應不同的後 端則可以為不同的機器構成同一個源語言的編譯程序。也可以設想,不同語言編譯的前端生成同一種中間 語言,再使用一個共同的後端,則可為同一機器生成幾個語言的編譯程序。
一個編譯過程可由一遍、兩遍或多遍完成。所謂"遍",也稱作"趟",是對源程序或其等價的中間語言程 序從頭到尾掃視並完成規定任務的過程。每一遍掃視可完成上述一個階段或多個階段的工作。例如一遍可 以只完成詞法分析工作;一遍完成詞法分析和語法分析工作;甚至一遍完成整個編譯工作。對於多遍的編 譯程序,第一遍的輸入是用戶書寫的源程序,最後一遍的輸出是目標語言程序,其餘是上一遍的輸出為下 一遍的輸入。
在實際的編譯系統的設計中,編譯的幾個階段的工作究竟應該怎樣組合,即編譯程序究竟分成幾遍, 參考的因素主要是源語言和機器(目標機)的特徵。比如源語言的結構直接影響編譯的遍的劃分;像 PL/1 或 ALGOL 68 那樣的語言,允許名字的說明出現在名字的使用之後,那麼在看到名字之前是不便為包含該名 字的表達式生成代碼的,這種語言的編譯程序至少分成兩遍才容易生成代碼。另外機器的情況,即編譯程 序工作的環境也影響編譯程序的遍數的劃分。遍數多一點,整個編譯程序的邏輯結構可能清晰些,但遍數 多即意味著增加讀寫中間文件的次數,勢必消耗較多時間,一般會比一遍的編譯要慢。
❸ 為什麼在許多高級語言的編譯過程中需要先將源代碼編譯為中間代碼
因為這樣可以跨平台運行,由底層解釋軟體,C和C++不用,直接編譯為目標文件,
❹ 簡單描述編譯的幾個處理步驟
編譯過程分為分析和綜合兩個部分,並進一步劃分為詞法分析、語法分析、語義分析、代碼優化、存儲分配和代碼生成等六個相繼的邏輯步驟。這六個步驟只表示編譯程序各部分之間的邏輯聯系,而不是時間關系。
編譯過程既可以按照這六個邏輯步驟順序地執行,也可以按照平行互鎖方式去執行。在確定編譯程序的具體結構時,常常分若干遍實現。對於源程序或中間語言程序,從頭到尾掃視一次並實現所規定的工作稱作一遍。每一遍可以完成一個或相連幾個邏輯步驟的工作。
(4)編譯過程中間語言擴展閱讀:
對於c編譯程序來說,其語言的特點如下:
1、c語言是一種結構化語言。它層次清晰,便於按模塊化方式組織程序,易於調試和維護,而且表現能力和處理能力極強。
2、c語言具有豐富的運算符和數據類型,便於實現各類復雜的數據結構。它還可以直接訪問內存的物理地址,進行位(bit)一級的操作。
3、由於c語言實現了對硬體的編程操作,因此集高級語言和低級語言的功能於一體。它既可用於系統軟體的開發,也適合於應用軟體的開發。
4、此外,c語言還具有效率高、可移植性強等特點。因此它廣泛地移植到了各類各型計算機上,從而形成了多種版本。
❺ 編譯程序包括哪幾個主要組成部分
編譯過程分為分析和綜合兩個部分,並進一步劃分為詞法分析、語法分析、語義分析、代碼優化、存儲分配和代碼生成等六個相繼的邏輯步驟。這六個步驟只表示編譯程序各部分之間的邏輯聯系,而不是時間關系。
編譯過程既可以按照這六個邏輯步驟順序地執行,也可以按照平行互鎖方式去執行。在確定編譯程序的具體結構時,常常分若干遍實現。對於源程序或中間語言程序,從頭到尾掃視一次並實現所規定的工作稱作一遍。每一遍可以完成一個或相連幾個邏輯步驟的工作。
(5)編譯過程中間語言擴展閱讀:
對於c編譯程序來說,其語言的特點如下:
1、c語言是一種結構化語言。它層次清晰,便於按模塊化方式組織程序,易於調試和維護,而且表現能力和處理能力極強。
2、c語言具有豐富的運算符和數據類型,便於實現各類復雜的數據結構。它還可以直接訪問內存的物理地址,進行位(bit)一級的操作。
3、由於c語言實現了對硬體的編程操作,因此集高級語言和低級語言的功能於一體。它既可用於系統軟體的開發,也適合於應用軟體的開發。
4、此外,c語言還具有效率高、可移植性強等特點。因此它廣泛地移植到了各類各型計算機上,從而形成了多種版本。
❻ C語言源程序的編譯過程包括哪三個階段
編譯:將源程序轉換為擴展名為.obj的二進制代碼
連接:將obj文件進行連接,加入庫函數等生成可執行文件
運行:執行可執行文件,有錯返回修改,無錯結束
❼ C語言的編譯過程
C編譯的整個過程很復雜,大致可以分為以下四個階段:
預處理階段在該階段主要完成對源代碼的預處理工作,主要包括對宏定義指令,頭文件包含指令,預定義指令和特殊字元的處理,如對宏定義的替換以及文件頭中所包含的文件中預定義代碼的替換等,總之這步主要完成一些替換工作,輸出是同源文件含義相同但內容不同的文件。
編譯、優化階段編譯就是將第一階段處理得到的文件通過詞法語法分析等轉換為匯編語言。優化包括對中間代碼的優化,如刪除公共表達式,循環優化等;和對目標代碼的生成進行的優化,如如何充分利用機器的寄存器存放有關變數的值,以減少內存訪問次數。
匯編階段將匯編語言翻譯成機器指令。
鏈接階段鏈接階段的主要工作是將有關的目標文件連接起來,即將在一個文件中引用的符號同該符號在另外一個文件中的定義連接起來,使得所有的目標文件成為一個能夠被操作系統裝入執行的統一整體。
❽ 為什麼要採用中間代碼中間代碼有哪幾種形式(編譯原理)
採用中間代碼是把源程序映射成中間代碼表示,再映射成目標代碼的工作分在幾個階段進行,使編譯演算法更加清晰。中間代碼有四種形式:
1、逆波蘭表示
逆波蘭表示又稱後綴表示法,它是最簡單的一種中間代碼表示形式,早在編譯程序出現之前,它就用於表示算術表達式。
2、四元式
四元式也是一種比較普遍採用的中間代碼形式,
其形式為:(OP,ARG1,ARG2,RESULT)
3、三元式
三元式表示是與四元式類似的一種表示法,所不同的僅是三元式中沒有表示運算結果的部分,凡要涉及到運算結果的均用三元式的位置或序號來代替。
4、樹表示
樹形表示是三元式的翻版。在樹的表示中,樹葉均為運算對象,即常量或變數,其他結點表示運算符。表達式的樹形表示很容易實現:簡單變數或常量的樹就是該變數或常量自身。
(8)編譯過程中間語言擴展閱讀
中間語言的優點:
1、中間語言與具體機器特性無關,一種中間語言可以為生成多種不同型號的目標機的目標代碼服務。
2、可對中間語言進行與機器無關的優化,有利於提高目標代碼的質量。
對於中間語言,要求其不但與機器無關,而且有利於代碼生成。
❾ 什麼叫中間語言
中間語言MSIT
在.Net框架中,公共語言基礎結構使用公共語言規范來綁定不同的語言。通過要求不同的語言至少要實現公共類型系統(CTS)包含在公共語言規范中的部分,公共語言基礎結構允許不同的語言使用.Net框架。因此在.Net框架中,所有的語言(C#,VB.Net,Effil.Net等)最後都被轉換為了一種通用語言:微軟中間語言(MSIL)。
MSIL是將.Net代碼轉化為機器語言的一個中間過程。它是一種介於高級語言和基於Intel的匯編語言的偽匯編語言。當用戶編譯一個.Net程序時,編譯器將源代碼翻譯成一組可以有效地轉換為本機代碼且獨立於CPU 的指令。當執行這些指令時,實時(JIT)編譯器將它們轉化為CPU特定的代碼。由於公共語言運行庫支持多種實時編譯器,因此同一段MSIL代碼可以被不同的編譯器實時編譯並運行在不同的結構上。從理論上來說,MSIL將消除多年以來業界中不同語言之間的紛爭。在.Net的世界中可能出現下面的情況:一部分代碼可以用Effil實現,另一部分代碼使用C#或VB完成的,但是最後這些代碼都將被轉換為中間語言。這給程序員提供了極大的靈活性,程序員可以選擇自己熟悉的語言,並且再也不用為學習不斷推出的新語言而煩惱了。
解密微軟中間語言的系列文章將通過一些簡單易懂的方式來揭示中間語言的復雜原理。這些原理通過詳細的例子來闡述。在一些例子中同時給出了源代碼和中間代碼,通過比較源代碼和中間代碼,我們可以更好地理解編譯器的局限性,指導我們編寫出更好更快的代碼。
微軟中間語言概述 1.用中間語言編寫的一個簡單程序
讓我們從經典的Hello World例子開始。首先在一個文本編輯器中輸入以下的代碼,並保存為HelloWorld.il:
.assembly HelloWorldIL {}
.method static void HelloWorld() {
.entrypoint
ldstr "Hello World."
call void [mscorlib]System.Console::WriteLine(class System.String)
ret
}
在一個中間語言程序中,如果某一行以「.」開始,則代表這是一個傳輸給匯編工具的指令,該指令要求匯編工具執行某些操作,例如生成一個函數或類。而沒有以「.」開始的行是中間語言的代碼。在中間語言中方法通過匯編命令method來定義,匯編命令後跟方法的返回值、名稱和參數。方法體被包含在{}中。例子中的ret代表該方法的結束。
一個中間語言文件可以包含很多函數,匯編工具沒有辦法分辨應該首先執行哪一個方法。在諸如C#或VB這一類高級語言中,程序的入口方法通常都有特定的名稱,例如在C#中的public static void Main()。這就是上面的匯編工具發出錯誤提示的原因。在中間語言中,第一個被執行的方法被稱為入口函數(EntryPoint Function)。為了告訴匯編工具HelloWorld是入口函數,我們需要在代碼中增加一條匯編命令entrypoint,該命令可以放在方法體中的任何位置。需要注意的是在一個程序集中只能有一個入口函數。
中間語言代碼通常被編譯成一個模塊,該模塊隸屬於一個程序集。在.Net中模塊和程序集的概念非常重要,因此開發人員需要很清楚地了解它們。在後面的文章中我們將詳細討論.Net程序的結構。通過在代碼中加入assembly命令,可以告訴匯編工具中間代碼隸屬於那個程序集。assembly命令的格式如下:
.assembly <程序集名稱> {}
需要注意在method命令後加入了static關鍵字,這是因為每個入口函數必須是靜態的,例如在C#中我們將Main方法定義為public static void Main()。
接下來我們需要調用WriteLine方法將HelloWorld字元串輸出到屏幕。通過使用call指令(Instruction)我們可以達到這個目的。指令的格式如下:
call <return type> <namespace>.<class name>::<method name>
這里我們可以看到當調用一個方法時,中間語言和其他的編程語言有很大的區別。在中間語言中,如果需要調用一個方法,需要指定方法的全名,包括他的名稱域(namespace)、類名、返回值類型和參數的數據類型。這樣就保證了匯編工具能夠找到正確的方法。
在調用WriteLine方法時需要一個字元串參數。所有傳遞給方法或函數的參數都被保存在內存的堆棧中。在中間語言中有一個指令ldstr可以從堆棧中載入一個字元串。(堆棧是內存中的一塊區域,它被用於將參數傳輸給方法,在後面我們會詳細討論堆棧的問題)。所有的方法都從堆棧中獲取它們的參數,因此ldstr指令是必不可少的。ldstr指令的格式如下所示:
ldstr <parameter string>
我們可以用ILAsm.exe來編譯這個程序。在運行ILAsm.exe之前,首先需要確認一下該程序已經包含在了Windows操作系統的Path環境變數中。ILAsm.exe 可在下面的路徑中找到:
%windir%\Microsoft.NET\Framework\v1.0.xxxx
其中xxxx是正在使用的.NET框架的內部版本號。例如我使用的版本號是3705,則應該如下設置Path環境變數:
Set Path = %Path%;c:\Windows\Microsoft.NET\Framework\v1.0.3705
然後運行cmd.exe(開始->運行->輸入cmd->按下確認鍵)。在彈出的命令窗口中輸入:
J:\Testcode>ilasm HelloWorld.il
匯編代碼後運行程序就可以看到Hello World.的輸出。
通過上面的例子,我們了解了中間語言的程序結構,一些命令和指令。同時需要提醒大家的是中間語言是區分大小寫的。
2.改進的HelloWorld例子
在.Net中的所有語言都是面向對象的語言,但是上面的HelloWorld例子是一個結構化的例子。下面讓我們來看一下如何將它轉化為面向對象的代碼。在面向對象的編程中,我們將操作定義在類中。為了將上面的HelloWorld例子轉化為面向對象的代碼,可以使用class命令:
.class HelloWorld { }
class命令後緊跟的是類的名稱。類的名稱在中間語言中是可選的。同時我們還需要為該指令添加一些屬性,例如存取控制類在內存中的布局和互用性等。這樣代碼就變成了:
.assembly HelloWorldIL {}
.class public auto ansi HelloWorld extends [mscorlib]System.Object {
.method public hidebysig static void HelloWorld() cil managed {
.entrypoint
ldstr "Hello World."
call void [mscorlib]System.Console::WriteLine(class System.String)
ret
}
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed {
ldarg.0
call instance void [mscorlib]System.Object::.ctor()
ret
}
}
在代碼中用到了三個屬性:
· public:public是訪問控制屬性,它表明了對於訪問該類的成員沒有限制。
· auto:auto屬性表明了當類被載入到內存中時,在內存中的布局是由公共運行庫而不是程序決定的。
· ansi:指定ansi屬性是為了在沒有被管理和被管理的代碼之間實現無縫的轉化。在.Net中,那些不可直接應用在公共語言基礎設施之上的代碼被稱為沒有被管理的代碼,例如C、C++和VB6的代碼。我們需要一個屬性來處理被管理的代碼和沒有被管理的代碼之間的互用性。在被管理的代碼中,字元串用雙位元組的Unicode字元表示,而在被管理的代碼中,字元串有可能用單位元組的ANSI字元表示。指定了ansi屬性就可以在不同的代碼間轉化字元串了。
我們知道在.Net框架中,所有的類都直接或間接地繼承了System.Object類。在代碼中我們明確指定了HelloWorld繼承了System.Object。
在HelloWorld方法中加入了public、hidebysig、cil managed屬性,下面是對這些屬性的解釋:
· public:在C#或VB.Net中,當我們定義一個方法時,需要指定方法的訪問修飾符。訪問修飾符可以是public、protected、internal或private 。
· hidebysig:一個類可以繼承其他的類,hidebysig屬性保證當前類中的方法在作為父類時不會被子類繼承。例如如果HelloWorldChild類繼承了HelloWorld類,在HelloWorldChild中不會看到HelloWorld方法。
· cil managed:該屬性將在後面討論。
在高級語言中(C#,VB.Net等),每個類必須有構造函數,而且構造函數的第一行需要調用基類的構造函數。如果類中沒有構造函數,基類的構造函數將被自動調用。通常這是由編譯器自動完成的,現在我們要在的代碼中加入構造函數,該構造函數通過.ctor命令調用基類的構造函數。
小結
本文我們從經典的Hello World例子開始,通過實例了解了微軟中間語言的基本語法規則以及中間語言與其他開發語言的關系。在下一篇文章中,我們將在此基礎上,運用實常式序講述.net應用程序的格式和結構等內容。
❿ 編譯程序的工作過程
編譯程序必須分析源程序,然後綜合成目標程序。首先,檢查源程序的正確性,並把它分解成若干基本成分;其次,再根據這些基本成分建立相應等價的目標程序部分。為了完成這些工作,編譯程序要在分析階段建立一些表格,改造源程序為中間語言形式,以便在分析和綜合時易於引用和加工(圖1)。
數據結構分析和綜合時所用的主要數據結構,包括符號表、常數表和中間語言程序。符號表由源程序中所用的標識符連同它們的屬性組成,其中屬性包括種類(如變數、數組、結構、函數、過程等)、類型(如整型、實型、字元串、復型、標號等),以及目標程序所需的其他信息。常數表由源程序中用的常數組成,其中包括常數的機內表示,以及分配給它們的目標程序地址。中間語言程序是將源程序翻譯為目標程序前引入的一種中間形式的程序,其表示形式的選擇取決於編譯程序以後如何使用和加工它。常用的中間語言形式有波蘭表示、三元組、四元組以及間接三元組等。
分析部分源程序的分析是經過詞法分析、語法分析和語義分析三個步驟實現的。詞法分析由詞法分析程序(又稱為掃描程序)完成,其任務是識別單詞(即標識符、常數、保留字,以及各種運算符、標點符號等)、造符號表和常數表,以及將源程序換碼為編譯程序易於分析和加工的內部形式。語法分析程序是編譯程序的核心部分,其主要任務是根據語言的語法規則,檢查源程序是否合乎語法。如不合乎語法,則輸出語法出錯信息;如合乎語法,則分解源程序的語法結構,構造中間語言形式的內部程序。語法分析的目的是掌握單詞是怎樣組成語句的,以及語句又是如何組成程序的。語義分析程序是進一步檢查合法程序結構的語義正確性,其目的是保證標識符和常數的正確使用,把必要的信息收集和保存到符號表或中間語言程序中,並進行相應的語義處理。