Ⅰ 編譯程序有哪些主要構成成分它們各自的主要功能是什麼
編譯過程分為分析和綜合兩個部分,並進一步劃分為詞法分析、語法分析、語義分析、代碼優化、存儲分配和代碼生成等六個相繼的邏輯步驟。這六個步驟只表示編譯程序各部分之間的邏輯聯系,而不是時間關系。
編譯過程既可以按照這六個邏輯步驟順序地執行,也可以按照平行互鎖方式去執行。在確定編譯程序的具體結構時,常常分若干遍實現。對於源程序或中間語言程序,從頭到尾掃視一次並實現所規定的工作稱作一遍。每一遍可以完成一個或相連幾個邏輯步驟的工作。
例如,可以把詞法分析作為第一遍;語法分析和語義分析作為第二遍;代碼優化和存儲分配作為第三遍;代碼生成作為第四遍。
反之,為了適應較小的存儲空間或提高目標程序質量,也可以把一個邏輯步驟的工作分為幾遍去執行。例如,代碼優化可劃分為代碼優化准備工作和實際代碼優化兩遍進行。
(1)編譯程序由哪些邏輯部分組成擴展閱讀
從左至右逐個字元地對源程序進行掃描,產生一個個的單詞符號,把作為字元串的源程序改造成為單詞符號串的中間程序。執行詞法分析的程序稱為詞法分析程序或掃描器。
源程序中的單詞符號經掃描器分析,一般產生二元式:單詞種別;單詞自身的值。單詞種別通常用整數編碼,如果一個種別只含一個單詞符號,那麼對這個單詞符號,種別編碼就完全代表它自身的值了。若一個種別含有許多個單詞符號,那麼,對於它的每個單詞符號,除了給出種別編碼以外,還應給出自身的值。
詞法分析器一般來說有兩種方法構造:手工構造和自動生成。手工構造可使用狀態圖進行工作,自動生成使用確定的有限自動機來實現。
編譯程序的語法分析器以單詞符號作為輸入,分析單詞符號串是否形成符合語法規則的語法單位,如表達式、賦值、循環等,最後看是否構成一個符合要求的程序,按該語言使用的語法規則分析檢查每條語句是否有正確的邏輯結構,程序是最終的一個語法單位。編譯程序的語法規則可用上下文無關文法來刻畫。
Ⅱ 編譯原理有有符號un-1.u=un嗎
編譯程序把源程序翻譯為目標程序。根據源程序的語言種類,翻譯程序可以分為匯編程序與編譯程序。與之相對,解釋程序是對源程序進行解釋執行的程序。相應的可以將高級語言分為
編譯型 C/C++, Swift, etc.
解釋型 Python, javascript, etc.
混合型 Java, etc.
本文重點放在編譯程序的設計上。典型的編譯程序具有 7 77 個邏輯部分
對源程序掃描一次被稱為一遍 (pass)。典型的一遍掃描編譯程序有如下形式
通常將中間代碼生成前的分析部分稱為編譯器的前端,其後的綜合部分則被稱為後端。這樣就把一個編譯程序分為了與源語言相關和與目標機有關的兩個獨立的部分,降低了程序的耦合。假設 llvm 編譯器 支持 M MM 種源語言到 N NN 種目標語言的編譯
傳統的編譯器如 gcc 可能需要開發 M × N M \times NM×N 個不同的子模塊。而 llvm 使用統一的中間語言 llvm Intermediate Representation 只需要 M MM 個前端與 N NN 個後端,大大降低了開發成本。
文法
設非空有窮集合 Σ \SigmaΣ 為一字母表,則其上的符號串為 ∀ s ∈ Σ ∗ \forall s \in \Sigma^*∀s∈Σ
∗
,其中 ∗ *∗ 表示集合的閉包。特別的記 Σ 0 = ε \Sigma^0 = {\varepsilon}Σ
0
=ε 為空串組成的集合。規則通常寫作
U : : = x or U → x , ∣ U ∣ = 1 , ∣ x ∣ ≥ 0 U ::= x\text{ or }U\rightarrow x,\quad |U| = 1, |x| \ge 0U::=x or U→x,∣U∣=1,∣x∣≥0
其中左部 U UU 是符號,右部 x xx 是有窮符號串。規則的集合 P PP 即可確定一個文法 G GG
<程序> ::= <常量說明><變數說明><函數說明>
<常量說明> ::= {const<常量定義>;}
<常量定義> ::= int<標識符>=<整數>{,<標識符>=<整數>}|char<標識符>=<字元>{,<標識符>=<字元>}
<變數說明> ::= {<類型標識符><變數定義>;}
<變數定義> ::= <標識符>[<下標>]{,<標識符>[<下標>]}
<下標> ::= '['<無符號整數>']' // <無符號整數>表示數組元素的個數,其值需大於0
<函數說明> ::= {(<類型標識符>|void)<函數定義>}void<主函數>
<函數定義> ::= <標識符>'('<參數表>')'<復合語句>
<參數表> ::= [<類型標識符><標識符>{,<類型標識符><標識符>}]
<主函數> ::= main'('')'<復合語句>
<復合語句> ::= '{'<常量說明><變數說明>{<語句>}'}'
<語句> ::= <條件語句>|'{'{<語句>}'}'|<函數調用語句>;|<賦值語句>;|<讀語句>;|<寫語句>;|<返回語句>;|;
<條件語句> ::= <if語句>|<while語句>|<do語句>|<for語句>
<if語句> ::= if'('<條件>')'<語句>[else<語句>]
<while語句> ::= while'('<條件>')'<語句>
<do語句> ::= do<語句>while'('<條件>')'
<for語句> ::= for'('<標識符>=<表達式>;<條件>;<標識符>=<標識符><加法運算符><無符號整數>')'<語句>
<條件> ::= <表達式>[<關系運算符><表達式>] // 表達式為0條件為假,否則為真
<函數調用語句> ::= <標識符>'('[<表達式>{,<表達式>}]')'
<賦值語句> ::= <標識符>['['<表達式>']']=<表達式>
<讀語句> ::= scanf'('<標識符>{,<標識符>}')'
<寫語句> ::= printf'('<字元串>[,<表達式>]')'|printf'('<表達式>')'
<返回語句> ::= return['('<表達式>')']
<表達式> ::= [<加法運算符>]<項>{<加法運算符><項>} // [+|-]只作用於第一個<項>
<項> ::= <因子>{<乘法運算符><因子>}
<因子> ::= <標識符>['['<表達式>']']|'('<表達式>')'|<整數>|<字元>|<函數調用語句>
<整數> ::= [<加法運算符>]<無符號整數>
<標識符> ::= <字母>{<字母>|<數字>}
<無符號整數> ::= <非零數字>{<數字>}|0
<數字> ::= 0|<非零數字>
<非零數字> ::= 1|...|9
<字元> ::= '<加法運算符>'|'<乘法運算符>'|'<字母>'|'<數字>'
<字元串> ::= "{十進制編碼為32,33,35-126的ASCII字元}"
<類型標識符> ::= int|char
<加法運算符> ::= +|-
<乘法運算符> ::= *|/
<關系運算符> ::= <|<=|>|>=|!=|==
<字母> ::= _|a|...|z|A|...|Z
復制
上述文法使用擴充的 BNF 表示法進行描述
符號 定義 說明
∣ \vert∣ 或 作用域由括弧限定
{ t } n m \{t\}^m_n{t}
n
m
將 t tt 重復連接 n ∼ m n \sim mn∼m 次 預設時 m = ∞ , n = 0 m = \infin,\ n = 0m=∞, n=0
[ t ] [t][t] 符號串 t tt 可有可無 等價於 { t } 1 \{t\}^1{t}
1
( t ) (t)(t) 局部作用域 主要用於限定 ∣ \vert∣ 范圍
相關概念有
概念 符號 定義 示例
識別符號 Z ZZ 文法中第一條規則的左部符號 <程序>
字匯表 V VV 文法中出現的全部符號 { <程序>, <常量說明>, …, 0, 1, … }
非終結符號集 V n V_nV
n
全部規則的左部組成的集合 { <程序>, <常量說明>, <變數說明>, … }
終結符號集 V t V_tV
t
V − V n V - V_nV−V
n
{ 0, 1, …, _, a, b, … }
設 U : : = u ∈ P U ::= u \in PU::=u∈P 則對於 ∀ x , y ∈ V ∗ \forall x, y \in V^*∀x,y∈V
∗
有直接推導 x U y ⇒ x u y xUy \Rightarrow xuyxUy⇒xuy 。如果 y ∈ V t ∗ y \in V_t^*y∈V
t
∗
則 x U y ⤃ x u y xUy\ ⤃\ xuyxUy ⤃ xuy 稱為規范推導。直接推導序列 u 0 ⇒ u 1 ⇒ ⋯ ⇒ u n u_0 \Rightarrow u_1 \Rightarrow \cdots \Rightarrow u_nu
0
⇒u
1
⇒⋯⇒u
n
可簡記為
{ u 0 ⇒ + u n n > 0 u 0 ⇒ ∗ u n n ≥ 0 \begin{cases} u_0 \mathop\Rightarrow\limits^+ u_n & n > 0\\ u_0 \mathop\Rightarrow\limits^* u_n & n \ge 0\\ \end{cases}{
u
0
⇒
+
u
n
u
0
⇒
∗
u
n
n
>
0
n
≥
0
進一步定義
句型 V ∗ ∋ x ⇐ ∗ Z V^* \ni x \mathop\Leftarrow\limits^* ZV
∗
∋x
⇐
∗
Z
句子 V t ∗ ∋ x ⇐ + Z V_t^* \ni x \mathop\Leftarrow\limits^+ ZV
t
∗
∋x
⇐
+
Z
語言 L ( G ) = { x ∣ x is sentence } L(G) = \{ x| x\text{ is sentence} \}L(G)={x∣x is sentence}
如果文法 G GG 和 G ′ G'G
′
有 L ( G ) = L ( G ′ ) L(G) = L(G')L(G)=L(G
′
) ,則稱這兩個文法等價。設 w = x u y w=xuyw=xuy 為一句型,稱 u uu 為一個相對於 U ∈ V n U \in V_nU∈V
n
的
w ww 的短語 如果 Z ⇒ ∗ x U y ∧ U ⇒ + u Z \mathop\Rightarrow\limits^* xUy \land U \mathop\Rightarrow\limits^+ uZ
⇒
∗
xUy∧U
⇒
+
u
w ww 的簡單短語 如果 u uu 是短語且 U ⇒ u U \mathop\Rightarrow\limits uU⇒u
句型的最左簡單短語稱為句柄。
二義性
文法 G GG 是二義性的,如果 ∃ x ∈ L ( G ) \exist x \in L(G)∃x∈L(G) 使下列條件之一成立
x xx 可以對應兩顆不同的語法樹
x xx 有兩個不同的規范推導
Ⅲ 一個C++程序是由哪幾個部分構成的其中的每一部分起什麼作用
1、頭文件,每個程序都開頭一堆#include,#define符號,#pragma編譯開關
2、類型聲明和全局變數,用於全局聲明類、結構、枚舉的定義,也可以設置全局變數
3、函數,即程序執行的具體過程、順序、邏輯定義
Ⅳ 典型的編譯器可以劃分成幾個主要的邏輯階段
這是我們今天的作業,
典型的編譯器可以劃分成七個主要的邏輯階段,分別是詞法分析器、語法分析器、語義分析器、中間代碼生成器、獨立於機器的代碼優化器、代碼生成器、依賴於機器的代碼優化器。各階段的主要功能:
(1)詞法分析器:詞法分析閱讀構成源程序的字元流,按編程語言的詞法規則把它們組成詞法記號流。
(2)語法分析器:按編程語言的語法規則檢查詞法分析輸出的記號流是否符合這些規則,並依據這些規則所體現出的該語言的各種語言構造的層次性,用各記號的第一元建成一種樹形的中間表示,這個中間表示用抽象語法的方式描繪了該記號流的語法情況。
(3)語義分析器:使用語法樹和符號表中的信息,依據語言定義來檢查源程序的語義一致性,以保證程序各部分能有意義地結合在一起。它還收集類型信息,把它們保存在符號表或語法樹中。
(4)中間代碼生成器:為源程序產生更低級的顯示中間表示,可以認為這種中間表示是一種抽象機的程序。
(5)獨立於機器的代碼優化器:試圖改進中間代碼,以便產生較好的目標代碼。通常,較好是指執行較快,但也可能是其他目標,如目標代碼較短或目標代碼執行時能耗較低。
(6)代碼生成器:取源程序的一種中間表示作為輸入並把它映射到一種目標語言。如果目標語言是機器代碼,則需要為源程序所用的變數選擇寄存器或內存單元,然後把中間指令序列翻譯為完成同樣任務的機器指令序列。
(7)依賴於機器的代碼優化器:試圖改進目標機器代碼,以便產生較好的目標機器代碼。