編譯原理存儲分配
動態存儲方式
所謂動態存儲方式是指在程序運行期間根據需要進行動態的分配存儲空間的方式。動態存儲變數是在程序執行過程中,使用它時才分配存儲單元,
使用完畢立即釋放。
典型的例子是函數的形式參數,在函數定義時並不給形參分配存儲單元,只是在函數被調用時,才予以分配,
調用函數完畢立即釋放。如果一個函數被多次調用,則反復地分配、
釋放形參變數的存儲單元。
靜態存儲方式
所謂靜態存儲方式是指在程序編譯期間分配固定的存儲空間的方式。該存儲方式通常是在變數定義時就分定存儲單元並一直保持不變,
直至整個程序結束。全局變數,靜態變數等就屬於此類存儲方式。
總結
從以上分析可知,
靜態存儲變數是一直存在的,
而動態存儲變數則時而存在時而消失。我們又把這種由於變數存儲方式不同而產生的特性稱變數的生存期。
生存期表示了變數存在的時間。
生存期和作用域是從時間和空間這兩個不同的角度來描述變數的特性,這兩者既有聯系,又有區別。
一個變數究竟屬於哪一種存儲方式,
並不能僅從其作用域來判斷,還應有明確的存儲類型說明。
Ⅱ 編譯時分配內存和運行時分配內存
編譯其實只是一個掃描過程,進行詞法語法檢查,代碼優化而已,編譯程序越好,程序運行的時候越高效。
我想你說的「編譯時分配內存」是指「編譯時賦初值」,它只是形成一個文本,檢查無錯誤,並沒有分配內存空間。
當你運行時,系統才把程序導入內存。一個進程(即運行中的程序)在主要包括以下五個分區:
棧、堆、bss、data、code
代碼(編譯後的二進制代碼)放在code區,代碼中生成的各種變數、常量按不同類型分別存放在其它四個區。系統依照代碼順序執行,然後依照代碼方案改變或調用數據,這就是一個程序的運行過程。
Ⅲ c語言數組在內存中是怎麼分配的
C語言中內存為分三類:棧區、堆區、靜態數據區。
局部變數在棧上分配,函數調用前的棧指針,要和函數返回後的棧指針一樣,否則就會出錯。
void test(void)
{
char i,a[10];
printf("0x%x", &i);
printf("0x%x", a);
printf("0x%x", a+1);
printf("0x%x", a+2);
printf("0x%x", a+3);
}
(3)編譯原理存儲分配擴展閱讀
c語言數組在內存分配
示例:
#include<stdio.h>
int main()
{
int a[4] = {11,12,13,14};
int b[4] = {21,22,23,24};
int *pa = &a;
int i = 0;
while(i<8)
{
i++;
printf("now *p value = %d and",*pa);
printf("p addr value = %d ",pa);
pa++;
}
return 0;
}
Ⅳ java中各類數據的存放問題!~!~
按照編譯原理的觀點,程序運行時的內存分配有三種策略,分別是靜態的,棧式的,和堆式的.
靜態存儲分配是指在編譯時就能確定每個數據目標在運行時刻的存儲空間需求,因而在編譯時就可以給他們分配固定的內存空間.這種分配策略要求程序代碼中不允許有可變數據結構(比如可變數組)的存在,也不允許有嵌套或者遞歸的結構出現,因為它們都會導致編譯程序無法計算準確的存儲空間需求.
棧式存儲分配也可稱為動態存儲分配,是由一個類似於堆棧的運行棧來實現的.和靜態存儲分配相反,在棧式存儲方案中,程序對數據區的需求在編譯時是完全未知的,只有到運行的時候才能夠知道,但是規定在運行中進入一個程序模塊時,必須知道該程序模塊所需的數據區大小才能夠為其分配內存.和我們在數據結構所熟知的棧一樣,棧式存儲分配按照先進後出的原則進行分配。
靜態存儲分配要求在編譯時能知道所有變數的存儲要求,棧式存儲分配要求在過程的入口處必須知道所有的存儲要求,而堆式存儲分配則專門負責在編譯時或運行時模塊入口處都無法確定存儲要求的數據結構的內存分配,比如可變長度串和對象實例.堆由大片的可利用塊或空閑塊組成,堆中的內存可以按照任意順序分配和釋放.
2.2 堆和棧的比較
上面的定義從編譯原理的教材中總結而來,除靜態存儲分配之外,都顯得很呆板和難以理解,下面撇開靜態存儲分配,集中比較堆和棧:
從堆和棧的功能和作用來通俗的比較,堆主要用來存放對象的,棧主要是用來執行程序的.而這種不同又主要是由於堆和棧的特點決定的:
在編程中,例如C/C++中,所有的方法調用都是通過棧來進行的,所有的局部變數,形式參數都是從棧中分配內存空間的。實際上也不是什麼分配,只是從棧頂向上用就行,就好像工廠中的傳送帶(conveyor belt)一樣,Stack Pointer會自動指引你到放東西的位置,你所要做的只是把東西放下來就行.退出函數的時候,修改棧指針就可以把棧中的內容銷毀.這樣的模式速度最快, 當然要用來運行程序了.需要注意的是,在分配的時候,比如為一個即將要調用的程序模塊分配數據區時,應事先知道這個數據區的大小,也就說是雖然分配是在程序運行時進行的,但是分配的大小多少是確定的,不變的,而這個"大小多少"是在編譯時確定的,不是在運行時.
堆是應用程序在運行的時候請求操作系統分配給自己內存,由於從操作系統管理的內存分配,所以在分配和銷毀時都要佔用時間,因此用堆的效率非常低.但是堆的優點在於,編譯器不必知道要從堆里分配多少存儲空間,也不必知道存儲的數據要在堆里停留多長的時間,因此,用堆保存數據時會得到更大的靈活性。事實上,面向對象的多態性,堆內存分配是必不可少的,因為多態變數所需的存儲空間只有在運行時創建了對象之後才能確定.在C++中,要求創建一個對象時,只需用 new命令編制相關的代碼即可。執行這些代碼時,會在堆里自動進行數據的保存.當然,為達到這種靈活性,必然會付出一定的代價:在堆里分配存儲空間時會花掉更長的時間!這也正是導致我們剛才所說的效率低的原因,看來列寧同志說的好,人的優點往往也是人的缺點,人的缺點往往也是人的優點(暈~).
2.3 JVM中的堆和棧
JVM是基於堆棧的虛擬機.JVM為每個新創建的線程都分配一個堆棧.也就是說,對於一個Java程序來說,它的運行就是通過對堆棧的操作來完成的。堆棧以幀為單位保存線程的狀態。JVM對堆棧只進行兩種操作:以幀為單位的壓棧和出棧操作。
我們知道,某個線程正在執行的方法稱為此線程的當前方法.我們可能不知道,當前方法使用的幀稱為當前幀。當線程激活一個Java方法,JVM就會在線程的 Java堆棧里新壓入一個幀。這個幀自然成為了當前幀.在此方法執行期間,這個幀將用來保存參數,局部變數,中間計算過程和其他數據.這個幀在這里和編譯原理中的活動紀錄的概念是差不多的.
從Java的這種分配機制來看,堆棧又可以這樣理解:堆棧(Stack)是操作系統在建立某個進程時或者線程(在支持多線程的操作系統中是線程)為這個線程建立的存儲區域,該區域具有先進後出的特性。
每一個Java應用都唯一對應一個JVM實例,每一個實例唯一對應一個堆。應用程序在運行中所創建的所有類實例或數組都放在這個堆中,並由應用所有的線程共享.跟C/C++不同,Java中分配堆內存是自動初始化的。Java中所有對象的存儲空間都是在堆中分配的,但是這個對象的引用卻是在堆棧中分配,也就是說在建立一個對象時從兩個地方都分配內存,在堆中分配的內存實際建立這個對象,而在堆棧中分配的內存只是一個指向這個堆對象的指針(引用)而已。
2.4 GC的思考
Java為什麼慢?JVM的存在當然是一個原因,但有人說,在Java中,除了簡單類型(int,char等)的數據結構,其它都是在堆中分配內存(所以說Java的一切都是對象),這也是程序慢的原因之一。
我的想法是(應該說代表TIJ的觀點),如果沒有Garbage Collector(GC),上面的說法就是成立的.堆不象棧是連續的空間,沒有辦法指望堆本身的內存分配能夠象堆棧一樣擁有傳送帶般的速度,因為,誰會為你整理龐大的堆空間,讓你幾乎沒有延遲的從堆中獲取新的空間呢?
這個時候,GC站出來解決問題.我們都知道GC用來清除內存垃圾,為堆騰出空間供程序使用,但GC同時也擔負了另外一個重要的任務,就是要讓Java中堆的內存分配和其他語言中堆棧的內存分配一樣快,因為速度的問題幾乎是眾口一詞的對Java的詬病.要達到這樣的目的,就必須使堆的分配也能夠做到象傳送帶一樣,不用自己操心去找空閑空間.這樣,GC除了負責清除Garbage外,還要負責整理堆中的對象,把它們轉移到一個遠離Garbage的純凈空間中無間隔的排列起來,就象堆棧中一樣緊湊,這樣Heap Pointer就可以方便的指向傳送帶的起始位置,或者說一個未使用的空間,為下一個需要分配內存的對象"指引方向".因此可以這樣說,垃圾收集影響了對象的創建速度,聽起來很怪,對不對?
那GC怎樣在堆中找到所有存活的對象呢?前面說了,在建立一個對象時,在堆中分配實際建立這個對象的內存,而在堆棧中分配一個指向這個堆對象的指針(引用),那麼只要在堆棧(也有可能在靜態存儲區)找到這個引用,就可以跟蹤到所有存活的對象.找到之後,GC將它們從一個堆的塊中移到另外一個堆的塊中,並將它們一個挨一個的排列起來,就象我們上面說的那樣,模擬出了一個棧的結構,但又不是先進後出的分配,而是可以任意分配的,在速度可以保證的情況下, Isn't it great?
但是,列寧同志說了,人的優點往往也是人的缺點,人的缺點往往也是人的優點(再暈~~).GC()的運行要佔用一個線程,這本身就是一個降低程序運行性能的缺陷,更何況這個線程還要在堆中把內存翻來覆去的折騰.不僅如此,如上面所說,堆中存活的對象被搬移了位置,那麼所有對這些對象的引用都要重新賦值.這些開銷都會導致性能的降低.
此消彼長,GC()的優點帶來的效益是否蓋過了它的缺點導致的損失,我也沒有太多的體會,Bruce Eckel 是Java的支持者,王婆賣瓜,話不能全信.個人總的感覺是,Java還是很慢,它的發展還需要時間.
Ⅳ 編譯程序包括哪幾個主要組成部分
編譯過程分為分析和綜合兩個部分,並進一步劃分為詞法分析、語法分析、語義分析、代碼優化、存儲分配和代碼生成等六個相繼的邏輯步驟。這六個步驟只表示編譯程序各部分之間的邏輯聯系,而不是時間關系。
編譯過程既可以按照這六個邏輯步驟順序地執行,也可以按照平行互鎖方式去執行。在確定編譯程序的具體結構時,常常分若干遍實現。對於源程序或中間語言程序,從頭到尾掃視一次並實現所規定的工作稱作一遍。每一遍可以完成一個或相連幾個邏輯步驟的工作。
(5)編譯原理存儲分配擴展閱讀:
對於c編譯程序來說,其語言的特點如下:
1、c語言是一種結構化語言。它層次清晰,便於按模塊化方式組織程序,易於調試和維護,而且表現能力和處理能力極強。
2、c語言具有豐富的運算符和數據類型,便於實現各類復雜的數據結構。它還可以直接訪問內存的物理地址,進行位(bit)一級的操作。
3、由於c語言實現了對硬體的編程操作,因此集高級語言和低級語言的功能於一體。它既可用於系統軟體的開發,也適合於應用軟體的開發。
4、此外,c語言還具有效率高、可移植性強等特點。因此它廣泛地移植到了各類各型計算機上,從而形成了多種版本。
Ⅵ 請問pascal編譯程序的功能是什麼
編輯詞條編譯程序
編譯程序
compiler
把用高級程序設計語言書寫的源程序,翻譯成等價的計算機匯編語言或機器語言的目標程序的翻譯程序。編譯程序屬於採用生成性實現途徑實現的翻譯程序。它以高級程序設計語言書寫的源程序作為輸入,而以匯編語言或機器語言表示的目標程序作為輸出。編譯出的目標程序通常還要經歷運行階段,以便在運行程序的支持下運行,加工初始數據,算出所需的計算結果。編譯程序的實現演算法較為復雜。這是因為它所翻譯的語句與目標語言的指令不是一一對應關系,而是一多對應關系;同時也因為它要處理遞歸調用、動態存儲分配、多種數據類型,以及語句間的緊密依賴關系。但是,由於高級程序設計語言書寫的程序具有易讀、易移植和表達能力強等特點,編譯程序廣泛地用於翻譯規模較大、復雜性較高、且需要高效運行的高級語言書寫的源程序。
功能 編譯程序的基本功能是把源程序翻譯成目標程序。但是,作為一個具有實際應用價值的編譯系統,除了基本功能之外,還應具備語法檢查、調試措施、修改手段、覆蓋處理、目標程序優化、不同語言合用以及人-機聯系等重要功能。①語法檢查:檢查源程序是否合乎語法。如果不符合語法,編譯程序要指出語法錯誤的部位、性質和有關信息。編譯程序應使用戶一次上機,能夠盡可能多地查出錯誤。②調試措施:檢查源程序是否合乎設計者的意圖。為此,要求編譯程序在編譯出的目標程序中安置一些輸出指令,以便在目標程序運行時能輸出程序動態執行情況的信息,如變數值的更改、程序執行時所經歷的線路等。這些信息有助於用戶核實和驗證源程序是否表達了演算法要求。③修改手段:為用戶提供簡便的修改源程序的手段。編譯程序通常要提供批量修改手段(用於修改數量較大或臨時不易修改的錯誤)和現場修改手段(用於運行時修改數量較少、臨時易改的錯誤)。④覆蓋處理:主要是為處理程序長、數據量大的大型問題程序而設置的。基本思想是讓一些程序段和數據公用某些存儲區,其中只存放當前要用的程序或數據;其餘暫時不用的程序和數據,先存放在磁碟等輔助存儲器中,待需要時動態地調入。⑤目標程序優化:提高目標程序的質量,即佔用的存儲空間少,程序的運行時間短。依據優化目標的不同,編譯程序可選擇實現表達式優化、循環優化或程序全局優化。目標程序優化有的在源程序級上進行,有的在目標程序級上進行。⑥不同語言合用:其功能有助於用戶利用多種程序設計語言編寫應用程序或套用已有的不同語言書寫的程序模塊。最為常見的是高級語言和匯編語言的合用。這不但可以彌補高級語言難於表達某些非數值加工操作或直接控制、訪問外圍設備和硬體寄存器之不足,而且還有利於用匯編語言編寫核心部分程序,以提高運行效率。⑦人-機聯系:確定編譯程序實現方案時達到精心設計的功能。目的是便於用戶在編譯和運行階段及時了解內部工作情況,有效地監督、控制系統的運行。
早期編譯程序的實現方案,是把上述各項功能完全收納在編譯程序之中。然而,習慣做法是在操作系統的支持下,配置調試程序、編輯程序和連接裝配程序,用以協助實現程序的調試、修改、覆蓋處理,以及不同語言合用功能。但在設計編譯程序時,仍須精心考慮如何與這些子系統銜接等問題。
工作過程 編譯程序必須分析源程序,然後綜合成目標程序。首先,檢查源程序的正確性,並把它分解成若干基本成分;其次,再根據這些基本成分建立相應等價的目標程序部分。為了完成這些工作,編譯程序要在分析階段建立一些表格,改造源程序為中間語言形式,以便在分析和綜合時易於引用和加工(圖1)。
數據結構 分析和綜合時所用的主要數據結構,包括符號表、常數表和中間語言程序。符號表由源程序中所用的標識符連同它們的屬性組成,其中屬性包括種類(如變數、數組、結構、函數、過程等)、類型(如整型、實型、字元串、復型、標號等),以及目標程序所需的其他信息。常數表由源程序中用的常數組成,其中包括常數的機內表示,以及分配給它們的目標程序地址。中間語言程序是將源程序翻譯為目標程序前引入的一種中間形式的程序,其表示形式的選擇取決於編譯程序以後如何使用和加工它。常用的中間語言形式有波蘭表示、三元組、四元組以及間接三元組等。
分析部分 源程序的分析是經過詞法分析、語法分析和語義分析三個步驟實現的。詞法分析由詞法分析程序(又稱為掃描程序)完成,其任務是識別單詞(即標識符、常數、保留字,以及各種運算符、標點符號等)、造符號表和常數表,以及將源程序換碼為編譯程序易於分析和加工的內部形式。語法分析程序是編譯程序的核心部分,其主要任務是根據語言的語法規則,檢查源程序是否合乎語法。如不合乎語法,則輸出語法出錯信息;如合乎語法,則分解源程序的語法結構,構造中間語言形式的內部程序。語法分析的目的是掌握單詞是怎樣組成語句的,以及語句又是如何組成程序的。語義分析程序是進一步檢查合法程序結構的語義正確性,其目的是保證標識符和常數的正確使用,把必要的信息收集和保存到符號表或中間語言程序中,並進行相應的語義處理。
綜合部分 綜合階段必須根據符號表和中間語言程序產生出目標程序,其主要工作包括代碼優化、存儲分配和代碼生成。代碼優化是通過重排和改變程序中的某些操作,以產生更加有效的目標程序。存儲分配的任務是為程序和數據分配運行時的存儲單元。代碼生成的主要任務是產生與中間語言程序符等價的目標程序,順序加工中間語言程序,並利用符號表和常數表中的信息生成一系列的匯編語言或機器語言指令。
結構 編譯過程分為分析和綜合兩個部分,並進一步劃分為詞法分析、語法分析、 語義分析、 代碼優化、存儲分配和代碼生成等六個相繼的邏輯步驟。這六個步驟只表示編譯程序各部分之間的邏輯聯系,而不是時間關系。編譯過程既可以按照這六個邏輯步驟順序地執行,也可以按照平行互鎖方式去執行。在確定編譯程序的具體結構時,常常分若干遍實現。對於源程序或中間語言程序,從頭到尾掃視一次並實現所規定的工作稱作一遍。每一遍可以完成一個或相連幾個邏輯步驟的工作。例如,可以把詞法分析作為第一遍;語法分析和語義分析作為第二遍;代碼優化和存儲分配作為第三遍;代碼生成作為第四遍。反之,為了適應較小的存儲空間或提高目標程序質量,也可以把一個邏輯步驟的工作分為幾遍去執行。例如,代碼優化可劃分為代碼優化准備工作和實際代碼優化兩遍進行。
一個編譯程序是否分遍,以及如何分遍,根據具體情況而定。其判別標准可以是存儲容量的大小、源語言的繁簡、解題范圍的寬窄,以及設計、編制人員的多少等。分遍的好處是各遍功能獨立單純、相互聯系簡單、邏輯結構清晰、優化准備工作充分。缺點是各遍之中不可避免地要有些重復的部分,而且遍和遍之間要有交接工作,因之增加了編譯程序的長度和編譯時間。
一遍編譯程序是一種極端情況,整個編譯程序同時駐留在內存,彼此之間採用調用轉接方式連接在一起(圖2)。當語法分析程序需要新符號時,它就調用詞法分析程序;當它識別出某一語法結構時,它就調用語義分析程序。語義分析程序對識別出的結構進行語義檢查,並調用「存儲分配」和「代碼生成」程序生成相應的目標語言指令。
隨著程序設計語言在形式化、結構化、直觀化和智能化等方面的發展,作為實現相應語言功能的編譯程序,也正向自動程序設計的目標發展,以便提供理想的程序設計工具。
參考書目
陳火旺、錢家驊、孫永強編:《編譯原理》,國防工業出版社,北京,1980。
A.V.Aho, Principles of Compiler Design,Addison Wes-ley, Reading, Massachusetts, 1977.
--------------------------------------------------------------------------------
編譯程序 (compiler)
將用高級程序設計語言書寫的源程序,翻譯成等價的用計算機匯編語言、機器語言或某種中間語言表示的目標程序的翻譯程序。用戶利用編譯程序實現數據處理任務時,先要經歷編譯階段,再經歷運行階段。編譯階段以源程序作為輸入,以目標程序作為輸出,其主要任務是將源程序翻譯成目標程序。運行階段的任務是運行所編譯出的目標程序,實現源程序中指定的數據處理任務,其工作通常包括:輸入初始數據,對數據或文件進行數據加工,輸出必要信息和加工結果等。編譯程序的實現演算法較為復雜。這是因為它所翻譯的語句與目標語言的指令不是一一對應關系,而是一多對應關系;同時因為它要在編譯階段處理遞歸調用、動態存儲分配、多種數據類型 實現 、 代碼生成與代碼優化等繁雜技術問題;還要在運行階段提供良好、有效的運行環境。由於高級程序設計語言書寫的程序具有易讀、易移植和表達能力強等特點,所以編譯程序廣泛地用於翻譯規模較大、復雜性較高、且需要高效運行的高級語言書寫的源程序。
功能 編譯程序的基本功能是把源程序翻譯成目標程序。此外,還要具備語法檢查、調試措施、修改手段、覆蓋處理、目標程序優化、不同語言合用以及人機聯系等具有實際應用價值的重要功能。①語法檢查。檢查源程序是否合乎語法 。②調試措施。檢查源程序是否合乎用戶的設計意圖。③修改手段。為用戶提供簡便的修改源程序的手段。④覆蓋處理。主要為處理程序較長、數據量較大的大型問題程序而設置。基本思想是讓一些程序段和數據公用某些存儲區,其中只存放當前要用的程序段或數據,其餘暫時不用的程序段和數據均存放在磁碟等輔助存儲器中,待需要時動態地調入存儲區中運行。⑤目標程序優化。提高目標程序的質量,即使編譯出的目標程序運行時間短、佔用存儲少。⑥不同語言合用 。便於用戶利用多種程序設計語言編寫應用程序或套用已有的不同語言書寫的程序模塊。最為常見的是高級語言和匯編語言的合用。⑦人機聯系。便於用戶在編譯和運行階段及時了解系統內部工作情況,有效地監督、控制系統的運行。
早期編譯程序的實現方案,是把上述各項功能完全收納在編譯程序之中 。後來的習慣方法是在操作系統的支持下,配置編輯程序、調試程序、連接裝配程序等實用程序或工具軟體,目的是創造一個良好的開發環境和運行環境,便於應用軟體的編程、修改、調試、集成以及報表生成、界面設計等工作。但編譯程序設計者設計編譯方案時,仍需精心考慮上述各項功能,較好地解決目標程序與這些實用程序或軟體工具之間的配合與銜接等問題。
工作過程 編譯程序必須分析源程序,然後綜合成目標程序。為達到這個目的,編譯程序要在分析階段建立一些表格,改造源程序為中間語言形式,以便在分析和綜合時易於引用和加工。
數據結構 分析和綜合時所用的主要數據結構,包括符號表、常數表和中間語言程序。符號表由源程序中所用的標識符連同它們的屬性組成,其中屬性包括種類(如變數、數組、結構、函數、過程等)、類型(如整型、實型、字元串、復型、標號等),以及目標程序所需的其他信息。常數表由源程序中用的常數組成,其中包括常數的機內表示以及分配給它們的目標程序地址。中間語言程序是將源程序翻譯成目標程序前引入的一種中間形式的程序,其表示形式的選擇取決於編譯程序以後如何使用它和如何加工它。常用的中間語言形式有波蘭表示、三元組、四元組以及間接三元組等。
分析部分 源程序的分析是經過詞法分析、語法分析和語義分析三個步驟實現的。詞法分析由詞法分析程序(又稱為掃描程序 )完成,其任務是識別單詞(即標識符 、常數、保留字,以及各種運算符、標點符號等)、造符號表和常數表,以及將源程序換碼為編譯程序易於分析和加工的內部形式。語法分析程序是編譯程序的核心部分,其主要任務是根據語言的語法規則,檢查源程序是否合乎語法,並分解源程序。如果不合乎語法,則輸出語法出錯信息;如果合乎語法,則分解源程 序的語法結構, 構造中間語 言形式的內部程序。語法分析的目的是掌握單詞是怎樣組成語句的,以及語句又是如何組成程序的。語義分析程序進一步檢查合法程序結構的語義正確性,其目的是保證標識符和常數的正確使用,把必要的信息收集和保存到符號表或中間語言程序中,並進行相應的語義處理。
綜合部分 綜合階段根據符號表和中間語言程序產生出目標程序,其主要工作包括代碼優化、存儲分配和代碼生成。代碼優化是通過重排和改變程序中的某些操作,以產生更加有效的目標程序。存儲分配是為程序和數據分配運行時的存儲單元。 代碼生成是產 生與中間語 言程序等價的目標程序,亦即,順序加工中間語言程序,利用符號表和常數表中的信息生成一系列的匯編語言或機器語言指令。
動態 20世紀80年代以後,程序設計語言在形式化、結構化、直觀化和智能化等方面有了長足的進步和發展,主要表現在兩個方面:①隨著程序設計理論和方法的發展,相繼推出了一系列新型程序設計語言,如結構化程序設計語言、並發程序設計語言、分布式程序設計語言、函數式程序設計語言、智能化程序設計語言、面向對象程序設計語言等;②基於語法、語義和語用方面的研究成果,從不同的角度和層次上深刻地揭示了程序設計語言的內在規律和外在表現形式。與此相應地,作為實現程序設計語言重要手段之一的編譯程序,在體系結構、設計思想、實現技術和處理內容等方面均有不同程度的發展、變化和擴充。另外,編譯程序已作為實現編程的重要軟體工具,被納入到軟體支援環境的基本層軟體工具之中。因此,規劃編譯程序實現方案時,應從所處的具體軟體支援環境出發,既要遵循整個環境的全局性要求和規定,又要精心考慮與其他諸層軟體 工具之間的相互支援、配合和銜接關系。
Ⅶ 編譯原理全部的名詞解釋
書上有別那麼懶!.
編譯過程的六個階段:詞法分析,語法分析,語義分析,中間代碼生成,代碼優化,目標代碼生成
解釋程序:把某種語言的源程序轉換成等價的另一種語言程序——目標語言程序,然後再執行目標程序.解釋方式是接受某高級語言的一個語句輸入,進行解釋並控制計算機執行,馬上得到這句的執行結果,然後再接受下一句.
編譯程序:就是指這樣一種程序,通過它能夠將用高級語言編寫的源程序轉換成與之在邏輯上等價的低級語言形式的目標程序(機器語言程序或匯編語言程序).
解釋程序和編譯程序的根本區別:是否生成目標代碼
句子的二義性(這里的二義性是指語法結構上的.):文法G[S]的一個句子如果能找到兩種不同的最左推導(或最右推導),或者存在兩棵不同的語法樹,則稱這個句子是二義性的.
文法的二義性:一個文法如果包含二義性的句子,則這個文法是二義文法,否則是無二義文法.
LL(1)的含義:(LL(1)文法是無二義的; LL(1)文法不含左遞歸)
第1個L:從左到右掃描輸入串 第2個L:生成的是最左推導
1 :向右看1個輸入符號便可決定選擇哪個產生式
某些非LL(1)文法到LL(1)文法的等價變換: 1. 提取公因子 2. 消除左遞歸
文法符號的屬性:單詞的含義,即與文法符號相關的一些信息.如,類型、值、存儲地址等.
一個屬性文法(attribute grammar)是一個三元組A=(G, V, F)
G:上下文無關文法.
V:屬性的有窮集.每個屬性與文法的一個終結符或非終結符相連.屬性與變數一樣,可以進行計算和傳遞.
F:關於屬性的斷言或謂詞(一組屬性的計算規則)的有窮集.斷言或語義規則與一個產生式相聯,只引用該產生式左端或右端的終結符或非終結符相聯的屬性.
綜合屬性:若產生式左部的單非終結符A的屬性值由右部各非終結符的屬性值決定,則A的屬性稱為綜合屬
繼承屬性:若產生式右部符號B的屬性值是根據左部非終結符的屬性值或者右部其它符號的屬性值決定的,則B的屬性為繼承屬性.
(1)非終結符既可有綜合屬性也可有繼承屬性,但文法開始符號沒有繼承屬性.
(2) 終結符只有綜合屬性,沒有繼承屬性,它們由詞法程序提供.
在計算時: 綜合屬性沿屬性語法樹向上傳遞;繼承屬性沿屬性語法樹向下傳遞.
語法制導翻譯:是指在語法分析過程中,完成附加在所使用的產生式上的語義規則描述的動作.
語法制導翻譯實現:對單詞符號串進行語法分析,構造語法分析樹,然後根據需要構造屬性依賴圖,遍歷語法樹並在語法樹的各結點處按語義規則進行計算.
中間代碼(中間語言)
1、是復雜性介於源程序語言和機器語言的一種表示形式.
2、一般,快速編譯程序直接生成目標代碼.
3、為了使編譯程序結構在邏輯上更為簡單明確,常採用中間代碼,這樣可以將與機器相關的某些實現細節置於代碼生成階段仔細處理,並且可以在中間代碼一級進行優化工作,使得代碼優化比較容易實現.
何謂中間代碼:源程序的一種內部表示,不依賴目標機的結構,易於代碼的機械生成.
為何要轉換成中間代碼:(1)邏輯結構清楚;利於不同目標機上實現同一種語言.
(2)便於移植,便於修改,便於進行與機器無關的優化.
中間代碼的幾種形式:逆波蘭記號 ,三元式和樹形表示 ,四元式
符號表的一般形式:一張符號表的的組成包括兩項,即名字欄和信息欄.
信息欄包含許多子欄和標志位,用來記錄相應名字和種種不同屬性,名字欄也稱主欄.主欄的內容稱為關鍵字(key word).
符號表的功能:(1)收集符號屬性 (2) 上下文語義的合法性檢查的依據: 檢查標識符屬性在上下文中的一致性和合法性.(3)作為目標代碼生成階段地址分配的依據
符號的主要屬性及作用:
1. 符號名 2. 符號的類型 (整型、實型、字元串型等))3. 符號的存儲類別(公共、私有)
4. 符號的作用域及可視性 (全局、局部) 5. 符號變數的存儲分配信息 (靜態存儲區、動態存儲區)
存儲分配方案策略:靜態存儲分配;動態存儲分配:棧式、 堆式.
靜態存儲分配
1、基本策略
在編譯時就安排好目標程序運行時的全部數據空間,並能確定每個數據項的單元地址.
2、適用的分配對象:子程序的目標代碼段;全局數據目標(全局變數)
3、靜態存儲分配的要求:不允許遞歸調用,不含有可變數組.
FORTRAN程序是段結構,不允許遞歸,數據名大小、性質固定. 是典型的靜態分配
動態存儲分配
1、如果一個程序設計語言允許遞歸過程、可變數組或允許用戶自由申請和釋放空間,那麼,就需要採用動態存儲管理技術.
2、兩種動態存儲分配方式:棧式,堆式
棧式動態存儲分配
分配策略:將整個程序的數據空間設計為一個棧.
【例】在具有遞歸結構的語言程序中,每當調用一個過程時,它所需的數據空間就分配在棧頂,每當過程工作結束時就釋放這部分空間.
過程所需的數據空間包括兩部分
一部分是生存期在本過程這次活動中的數據對象.如局部變數、參數單元、臨時變數等;
另一部分則是用以管理過程活動的記錄信息(連接數據).
活動記錄(AR)
一個過程的一次執行所需要的信息使用一個連續的存儲區來管理,這個區 (塊)叫做一個活動記錄.
構成
1、臨時工作單元;2、局部變數;3、機器狀態信息;4、存取鏈;
5、控制鏈;6、實參;7、返回地址
什麼是代碼優化
所謂優化,就是對代碼進行等價變換,使得變換後的代碼運行結果與變換前代碼運行結果相同,而運行速度加快或佔用存儲空間減少.
優化原則:等價原則:經過優化後不應改變程序運行的結果.
有效原則:使優化後所產生的目標代碼運行時間較短,佔用的存儲空間較小.
合算原則:以盡可能低的代價取得較好的優化效果.
常見的優化技術
(1) 刪除多餘運算(刪除公共子表達式) (2) 代碼外提 +刪除歸納變數+ (3)強度削弱; (4)變換循環控制條件 (5)合並已知量與復寫傳播 (6)刪除無用賦值
基本塊定義
程序中只有一個入口和一個出口的一段順序執行的語句序列,稱為程序的一個基本塊.
給我分數啊.
Ⅷ 編譯原理:靜態數組的存儲空間可以在編譯時確定。這句話為什麼是錯的。請給出詳細原因,謝謝。
靜態數組指的是寫代碼期間就知道大小的數組,比如int a[10];
char s[] = "hello";
這個靜態和動態分配相區別,不要和static弄混了,static/extern/auto是用於說明變數的存儲方式——也就是說,靜態數組也可以是static的,也可以是extern的,也可以是auto的。
舉個例子,下面就是一個靜態數組,但是存儲方式是auto的。
voidtest()
{
inta[10];
}
這個數組的存儲空間無法在編譯時候確定,只能在運行期間確定,原因是:盡管可以確定數組的大小,但是不能確定它的首地址。
再比如:
static int sa[10] = {0};
這個數組的存儲空間在編譯時,就可以確定了。