編譯原理學習筆記-2:文法和語言

上一篇筆記中,咱們談到了爲何須要編譯以及編譯的大體流程。在繼續細講每個流程以前,咱們先經過本篇筆記對一些概念和術語加以瞭解。

1. 前置知識:字母表和符號串

1.1 字母表

字母表也即符號集,用 表示,它是一個包含各類符號的有窮非空集合。以漢語爲例,漢語字母表就是各類漢字、數字、標點符號的集合;以英語爲例,英語字母表就是各類字母、數字、標點符號的集合......那麼到了編程,字母表就多是字母、數字、各類專用符號和保留字了。git

1.2 符號串

相關定義:github

符號串是對於字母表來講的一個概念,字母表的符號串指的就是由字母表中各個字符組成的一個有窮序列編程

注意這裏的「有窮」,指的是符號串自己是由有窮個符號組成,可是符號串的個數是無窮多的(組合方式不一樣)。以字母表 ∑={0,1} 爲例,它的符號串就有:0,1,00,01,10,11,000 等等。閉包

符號串的長度指的是符號串符號的個數,以 m = 000 爲例,|m|= 3編程語言

空符號串 ε 長度爲 0,表示不包含任何符號,相似於編程中的空字符串 ""。因此有 εm = mε= m工具

m = abc 爲例,它的頭是 εaababc;它的尾是 εcbcabc。而它的固有頭不考慮末尾符號 c,固有尾不考慮首部符號 a學習

鏈接、方冪spa

  • 符號串的鏈接:鏈接就是兩個字符串順序拼接,好比 x = abcy = def,那麼 xy = abcdef
  • 符號串的方冪:若是一個符號串由多個重複符號構成,如何方便地表示它呢?好比 y = xxxx...xxxx(n 個 x),那麼就能夠寫成 y = x^n,此時 y 就是 x 的方冪。這點和數學是同樣的。不過要注意,x^0 ≠ 1 = ε

1.3 閉包

以字母表 ∑ = {a,b} 爲例,任何由它的符號串做爲構成元素的集合,均可以稱做字母表的符號串集合。好比說 {ab}{abab,ababab} 等。code

兩個符號串集合的乘積定義爲 AB = {xy| x∈A且y∈b},其實就是笛卡爾積。blog

通常的字符串集合可能並不能囊括一個字母表的全部符號串,可是有一種集合卻能包含全部的符號串,這種特殊的集合稱爲閉包,記做 ∑** 其實就是全選的意思(聯想 CSS 中的通配選擇符就好理解了)。

∑* = {ε,a,b,ab,ab,ba,aba,aab......} = ∑^0 ∪ ∑^1 ∪ ∑^2 ∪......∪ ∑^n

要注意的是,閉包也包含了空符號串

將閉包中的空符號串去掉,就成爲了正閉包,也即 ∑+。顯然:∑*= ∑^0 ∪ ∑+∑+ = ∑∑* = ∑*∑

2. 文法

2.1 文法在語言體系中的位置

語言包括語法語義兩個方面,可是語法和語義都是比較抽象的東西,因此咱們須要藉助一些工具來闡述它們。以語法來講,文法就是闡述它的一個工具。

2.2 文法的形式定義

文法是描述語言語法結構的形式規則。它的形式化定義是一個四元組,即 G = { VN , VT , P , S }。下面咱們先給出一個天然語言的例子,而後藉此來解釋四元組的各個成分都是什麼。

<句子> → <主語> <謂語>

<主語> → <代詞> | <名詞>

<謂語> → <動詞>

<代詞> → 你 | 我 | 他

<名詞> → 張三 | 教師 | 大學生

<動詞> → 教書 | 學習

(1)VT:

VT 指的是終結符集合。終結符即 terminal symbol,它是文法所定義的語言的最基本符號,這意味着一個終結符不可再細分(注意「終結」這個詞)。以上面爲例,VT ={ 你,我,他,張三,教師,大學生,教書,學習 }。在編程語言中,終結符其實就是以前提到的 token,好比保留字、運算符、界符等這些最最基本的符號。

終結符通常用小寫字母表示。

(2)VN:

VN 指的是非終結符集合。非終結符即 nonterminal symbol,它是用來表示語法成分的符號,有時候也稱爲「語法變量」。以上面爲例,VN ={ <句子>,<主語>,<謂語>,<代詞>,<名詞>,<動詞> }。在編程語言中,咱們能夠說表達式或者賦值語句就是一個非終結符,由於它能夠繼續細分爲多個 token。

非終結符的「非終結」,就是說「尚未到盡頭」,還能夠繼續拆分,通常用 <> 括起來。

非終結符通常用大寫字母表示。

PS:終結符和非終結符統稱爲文法符號。

(3)P:

P 即 production,指的是產生式集合。終結符和非終結符的轉換依靠的就是產生式(或者說生成式,推導規則)。產生式形如 a → β (或者 a : : = β ,這種表示方法即巴科斯範式 ),意思是將 a 定義爲 β。a 稱爲產生式左部,它是終結符集合的一個元素;而 β 稱爲產生式右部,它是終結符和非終結符並集的一個元素。根據前面的定義,很容易就能知道產生式的左部不能是終結符,由於左部都是能夠繼續細分的,可是終結符不能再細分了,而右部在一開始多是非終結符(還沒拆完),但在最後必定會變成終結符(拆完了,不能再拆了)。

以上面爲例,P = { <句子> → <主語> <謂語>,<主語> → <代詞> | <名詞>,<謂語> → <動詞> }

(4)S:

S 即 start symbol,指的是開始符號(識別符號)。它是最開始的那條產生式的左部,一切的推導都是從它這裏開始進行的,能夠認爲它就是最大的那個成分。因此也註定了 S 必須在 P 中至少做爲某一條產生式的左部(否則無從推導)。

以上面爲例,S = <句子>。

2.3 更簡潔的形式化定義

假如如今有文法 G =({S,A,B},{0,1},P,S),

其中,P = { S → 0A,S → 1B,A → 1B,B → 1 }。

是否有更簡便的方法來表示它呢?事實上,這裏僅從產生式集合 P 來看,徹底能夠在不引發歧義的狀況下推斷出終結符號集,非終結符號集以及開始符號。這意味着咱們能夠將這三者省略,僅用產生式集合表達文法自己,也即:

G:
S → 0A
S → 1B  
A → 1B
B → 1
B → 0

更進一步地,咱們發現部分產生式的左部都是同樣的,因此能夠繼續簡寫爲:

G:
S → 0A | 1B  
A → 1B
B → 1 | 0

此時,0A 或者 1B 稱爲 S 的候選式(candidate),1 或者 0 稱爲 B 的候選式。

2.4 推導

(1)直接推導:

假如文法 G = { VN , VT , P , S } 有一條產生式爲 a → β ,γ 和 δ 是 V*= VN ∪ VT 中的任意符號(便是文法中的任意終結符或者非終結符),如有符號串知足:

V = γ a δ ,W = γ β δ

那麼就說 V 能夠直接推導獲得 W,或者說 W 是 V 的直接推導,W 直接規約到 V —— 記做 V ⇒ W。咱們看一個例子:

假如如今有文法 G =({S,A,B},{0,1},P,S),其中,P = { S → 0A,S → 1B,A → 1B,B → 1 }。

那麼以產生式 S → 0A 爲例,咱們是能夠說 S ⇒ 0A 的,由於 S = εSε,0A = ε0Aε(別忘了,空符號串也是屬於 V* 的),以此類推,全部的產生式實際上都是一個直接推導。

(2)推導:

推導指的是從文法的開始符號出發,反覆連續地使用產生式,對非終結符施行替換和展開,最終獲得一個僅由終結符構成的符號串,推導過程的每一步都是一個直接推導。

仍是以上面的文法爲例,那麼就有 S ⇒ 0A ⇒ 01B ⇒ 011,這個序列就是從 S 到 011 的一個推導,或者說 S 能夠推導出 011。

序列能夠簡寫爲 S +⇒ 011,表示通過一步或者多步推導,而 S *⇒ 011 表示通過 0 步或者多步推導。因此,S *⇒ 011 要麼是 S = 011,要麼是 S +⇒ 011。

(3)最左/最右推導:

推導的過程並非惟一的。對於任何一步 α ⇒ β,若是都是對 α 中的最左非終結符進行替換,那麼就說最左推導,反之就是最右推導。

假如給定文法G:E → E + E | E * E | (E) | i,由該文法最終能夠推導獲得句子 (i * i + i)。若是採用最右推導,那麼過程就是:

E ⇒ (E) ⇒ (E + E) ⇒ (E + i) ⇒ (E * E + i) ⇒ (E * i + i) ⇒ (i * i + i)。

在每一步中,咱們都儘量地替換 α 中的最左非終結符。

2.5 句型、句子、語言

  • 句型:若是 S *⇒ a,開始符號 S 能夠推導獲得某個符號串,那麼這個符號串 a 就稱爲句型。以上面文法爲例,0A ,01B,011 ...... 都是句型。
  • 句子:在推導之初,句型可能既包含終結符也包含非終結符,但最終確定只剩下終結符構成的符號串,此時這個符號串就稱爲句子。以上面文法爲例,011 就是句子。
  • 語言:文法產生的句子的全體就構成了語言,記做 L(G)。以上面文法爲例,L(G) = { 011,11 }。

3. 語法分析樹與文法的二義性

咱們能夠藉助語法分析樹(這裏的語法分析樹是具體語法樹,即 parse tree,不是抽象語法樹)這個結構來描述句型的推導。好比給定文法 G:

G = ( {S,A},{a,b},P,S ),其中 P ={ S → aAS,A → SbA,A → SS,S → a,A → ba }

能夠這樣推導出句子 aabbaa:S ⇒ aAS ⇒ aSbAS ⇒ aabAS ⇒ aabbaS ⇒ aabbaa

那麼如何用分析樹表達這個句子呢?如圖所示:

用根節點表明開始符號,隨着推導的進行,當某個非終結符被它的候選式所替換時,這個非終結符的相應結點就會產生下一代子結點,以此類推。

有時候,對於某個句子,因爲它的推導過程不惟一,因此會致使它的分析樹也不惟一。以前的例子中,咱們給定了文法 G:E → E + E | E * E | (E) | i,由這個文法推導出句子 (i * i + i),實際上有兩種方式:

  • E ⇒ (E) ⇒ ( E + E ) ⇒ ( E + i ) ⇒ ( E * E + i ) ⇒ ( E * i + i ) ⇒ ( i * i + i )
  • E ⇒ (E) ⇒ (E * E ) ⇒ ( i * E ) ⇒ ( i * E + E) ⇒ ( i * i + E) ⇒ ( i * i + i )

對應地有兩種分析樹:

因爲這個文法存在着某個句子對應着兩棵不一樣的分析樹,因此這個文法是二義(歧義)的。

顯然,程序語言不能出現歧義。消除歧義的方法之一是改寫語法,但這種改寫很是困難;另外一種方法就是引入 優先級 ,利用符號的優先級來選擇須要的推導方式。

做爲描述程序語言的上下文無關文法,咱們對它還有一些限制:

  • 文法中不包含形如 P → P 的產生式
  • 每一個非終結符必定能夠被用到,或者自己被 S 推導獲得,或者自己推導獲得其它終結符串。

4. 文法類型

喬姆斯基把文法劃分爲四種類型(從 0 型到 1型),這四種類型層層加強,越到後面限制越大。

(1) 0 型文法

0 型文法也叫短語文法。設 G = { VN , VT , P , S },若是它的每一個產生式 α→β 都知足:

α∈(VN∪VT)* 且至少含有一個非終結符,而 β∈(VN∪VT)*

那麼這種文法就稱爲 0 型文法。其中,VN∪VT 表明的是終結符合集和非終結符號集的並集,注意這一樣是一個字母集,因此外面加上星號,就成爲咱們開篇所說的字母集的閉包。也就是說,產生式的左部或者右部,必須是由終結符和非終結符構成的符號串。

(2) 1 型文法

在 0 型文法的基礎上加以限制,規定對於每個 α→β,都必須知足 |α| <= |β|。也就是說,產生式左部符號串長度必須小於等於右部符號串長度。這裏要注意一個特例就是: α → ε,雖然左部長度必定大於右部長度,但它仍然符合 1 型文法。

1 型文法也叫上下文有關文法。

(3) 2 型文法

在 1 型文法的基礎上加以限制,規定對於每個 α→β,都必須知足 α 是一個非終結符。也就是說,產生式左部必須得是一個非終結符。

2 型文法也叫上下文無關文法。

(4) 3 型文法

在 3 型文法的基礎上加以限制,規定對於每個 α→β,要麼必須知足 A→ α | αB(右線性),要麼必須知足 A→ α | Bα(左線性)。這裏的 AB 表明非終極符號。

3 型文法也叫正規文法。

5. 文法和上下文

上下文其實是在替換非終結符的時候給予的一個限制條件。也就是說,若是文法是上下文有關的,那麼進行替換的時候須要考慮上下文,反之則沒必要。比方說,γ a δ → γ β δ 是 1 型文法的一個產生式,γ 和 δ 都不爲空,則非終結符 a 只有在 γ 和 δ 這樣的一個上下文環境裏才能被替換成 β。

下面咱們用更加通俗的例子來解釋這兩種文法:

定義上下文無關文法 G :

Grammar → X Y Z
X → 我 | 學校
Y → 去 | 沒有
Z → 公園 | 人

那麼以 Grammar 做爲開始符號,就會產生各類句子,其中既有像「我去公園」,「學校沒有人」這種句意通順的,也不乏「我沒有人」,「學校去公園」這種狗屁不通的。爲何會產生不符合語義的句子?這是由於咱們沒有給定上下文的約束,也就是說,由於有了 Y → 去 | 沒有 這條產生式,因此只要遇到 Y,推導出「去」或者「沒有」就都是合理的,而全然不須要關注「去「的上文是什麼,」去「的下文是什麼。

可是若是定義上下文有關文法 G‘:

Grammar → X Y Z
X → 我 | 學校
我 Y → 我去
學校 Y → 學校沒有
去 C → 去公園
沒有 C → 沒有人

那麼就徹底不同了。這時候非終結符的替換是受到上下文限制的 ——

Y 只有在上文是」我「 的時候才能被替換成」去「,只有在上文是」學校「 的時候才能被替換成」沒有「,所以不會產生諸如」學校去「或者」我沒有「這樣的句子;同理,C 只有在上文是」去「 的時候才能被替換成」公園「,只有在上文是」沒有「 的時候才能被替換成」人「,所以不會產生諸如」沒有公園「或者」去人「這樣的句子。這樣就保證了產生的句子是符合語義的。

最後咱們再來總結本篇筆記所講的內容。在文章開始,咱們先給出了一些相關術語的概念和形式,這是爲了更好地在後面形式化地表示文法;接着,咱們引入了文法的概念,包括它的形式化定義,它的推導;而後,咱們引入了語法樹的概念,用以描述推導的過程;最後,咱們解釋了文法的幾種類型(0 ~ 3),並經過例子補充了文法在有/無上下文約束的狀況下分別會推導出什麼句型。

相關文章
相關標籤/搜索