編譯原理 學習記錄11

2021-10-10 17:52:47 字數 3783 閱讀 5202

上回,為了解決移進-規約時的幾個問題,引入了幾個定義:

短語

設有文法g[z],w=xuy是它的乙個句型,如果有:z⇒∗

xu

yz\mathop\rightarrow\limits^* xuy

z⇒∗xuy

並且u ⇒+

uu\mathop\rightarrow\limits^+u

u⇒+u

,則稱句型xuy中子串u為句型xuy(相對於非終結符號u)的短語

特別地,如果是z⇒∗

xu

yz\mathop\rightarrow\limits^* xuy

z⇒∗xuy

並且u ⇒u

u\mathop\rightarrow u

u⇒u,則稱u為句型xuy的直接(簡單)短語

控制代碼

句型的最左直接短語稱為控制代碼

根據定義,短語、直接短語和控制代碼,都和語法樹有關係:

1、語法樹子樹的末端結點符號串即是語法樹所描述句型(相對於子樹的根)的短語

2、簡單子樹(只有父子兩代)的末端結點符號串即是直接短語

3、最左簡單子樹的末端結點符號串即是控制代碼

光從文字來看,這樣的定義還是太抽象了。這個定義應該對後面的自下而上分析方法很重要,所以不得不看懂。然而這三行看了很久都沒看懂,看書也看不懂,最後看了這篇文章才勉強搞懂。現進行舉例:

對於文法g[s]:

s →a

ba→a

a∣bb

b→a∣

sb

\begins&\rightarrow ab\\ a&\rightarrow aa|bb\\ b&\rightarrow a|sb\end

sab​→a

b→aa

∣bb→

a∣sb

​現打算要求句型basb的短語、直接短語和控制代碼。首先使用最右推導的方法,構造出語法樹:

除葉結點單獨形成的子樹之外,這棵語法樹共有4個子樹:

1、b(a)

2、b(s, b)

3、a(b, b(a))

4、s(a(b, b(a)), b(s, b))

因此,短語共有四個:a、sb、ba、basb

而因為前兩棵子樹只有父子兩代,所以直接短語有兩個:a、sb

控制代碼是最左直接短語(位於最左端的簡單子樹),而兩棵子樹中,b(a)在b(s, b)的左邊,所以控制代碼應該為a

在理解定義之後,就開始看lr方法的思想了

此類分析法命名為lr,是用於表達「從左至右」的含義

現在,自上而下語法分析面臨的問題,主要就在於這兩點:

1、如何找出當前句型中的控制代碼

2、應該將控制代碼歸約到哪乙個非終結符號

在進行詳細討論之前,首先大致瀏覽程式的總體結構,以展現出lr分析法相對於ll(1)分析法的簡潔之處

lr分析程式主要有總控程式和分析表這兩個部分

相比於ll(1),lr多出了乙個狀態棧,用於儲存符號棧中各個符號所對應的狀態,而新進棧的符號的狀態則是根據棧頂的狀態和輸入的符號進行查表(分析表)而決定

分析表主要包含:動作部分(action)和狀態轉換部分(goto)。表中使用s表示移進、r表示規約、acc(accept)表示接受、(action部分的)空白表示錯處理(而goto部分的空白則不是出錯處理)

分析表儘管lr分析器有好幾種型別(常見的有lr(0)、slr、lr(1)、lalr),但所有lr分析器的總控程式一致,只是分析表不同而已。由此可知,lr分析法的程式是可以通用的,這再次體現出了lr分析法的乙個優越之處

lr分析過程主要包括移進、規約、接受和出錯四種操作。對過程的簡要描述如下:

1、總控程式在分析的每一步,按照狀態棧頂狀態q和當前輸入符號a,查閱lr分析表,並執行其中action[q,a]和goto部分規定的操作。

初始狀態

2、若action [q

iq_i

qi​,a

ka_k

ak​]= s

js_j

sj​,則:

3、若action [q

iq_i

qi​,a

ka_k

ak​]=rj,且第j條產生式為u→

\rightarrow

→x,|x|=m,lr分析表中有goto[qi−

mq_

qi−m

​,u]=q

tq_t

qt​,則:

4、若action[q

iq_i

qi​,a

ka_k

ak​]=acc,表示接受,不發生變化,分析成功:

5、若action[q

iq_i

qi​,a

ka_k

ak​]=error,表示出錯,中止變化

lr分析過程非常地簡單,沒有左遞迴、提取公因子的問題,因此關鍵在於:如何構造分析表

這一段目前還沒有很好地理解,所以寫出來也是非常地機械的(大多為照搬),之後會考慮對內容進行改進

對於由n個符號構成的控制代碼,如果每識別乙個控制代碼的符號就對應著乙個狀態,則加上開始狀態後,共有n+1個狀態

可以利用打點的方式記錄狀態,例如,現在有控制代碼xyz,則.xyz表示即將開始得到x,x.yz表示已經得到x,即將得到yz,xy.z表示已經得到xy,即將得到z,xyz.表示已經得到xyz,即將歸約

用lr(0)專案來表示乙個控制代碼的所有識別狀態:

移進專案:u→x

.a

yu\rightarrow x.ay

u→x.ay

。點後為終結符號,需要移入棧中

待約專案:u→x

.v

yu\rightarrow x.vy

u→x.vy

。點後為非終結符號

規約專案:u→x

.u\rightarrow x.

u→x.

。點已經到控制代碼的最後了,已完整地完成

接受專案:s′→

s.

s'\rightarrow s.

s′→s

.。其中,s為開始符號。這裡使用了拓廣文法,引入了乙個新的開始符號s』,和產生式s′→

ss'\rightarrow s

s′→s

即便是在得到完整的產生式右部時,也無法知道能不能規約(資訊還是不夠),說明不能離開句型談控制代碼,即需要句型中的資訊,利用歷史來幫助判斷

由此引入活字首:包含了控制代碼識別到當前時刻的歷史,並逐步向後傳遞,最長活的字首(可歸約字首)包含了控制代碼完全被識別的整個歷史。這樣一來,符號棧中存放的就是活字首,而符號串和輸入串連起來就是句型(從輸入串中乙個個地移進符號串,並在符號串中規約,所以圖中的符號棧和輸入串連起來正好就是乙個句型):

對控制代碼的識別過程就是對規範句型的活字首的識別過程,對於這樣的識別,可以用確定的有窮自動機來進行

在此處,使用拓廣文法:引入乙個新的開始符號s』,及對應的產生式s′→

ss'\rightarrow s

s′→s

將所有的產生式的所有狀態全部列出,然後根據狀態間的轉換關係進行相應的連線:

上述方式構造出的是nfa,如果要轉換為dfa,則需要進行狀態的合併

首先對空弧的閉包進行狀態合併:

合併後,被併入的狀態所對應的產生式稱作派生專案,反之稱為核心專案。例如,在上圖的開始狀態集中,s′→

.s

s'\rightarrow .s

s′→.

s為核心專案,而s→.

aacb

es\rightarrow .aacbe

s→.aac

be則為派生專案

隨後,再對相同輸入所到達的多個狀態進行合併:

這樣便轉換為了dfa

編譯原理 學習記錄4

直接遞迴 呈現出u x uy u rightarrow xuy u xu y形式的文法產生式 間接遞迴 具有u xu yu mathop rightarrow limits xuy u xuy 形式的推導 產生式呈u u yu rightarrow uy u uy 形式如果是經過多步推導得到,則稱之...

編譯原理 學習記錄6

正規集 字母表 sigma 上的正規表示式e,所描述的語言集合l e 從e到l e 的變換有如下規則 el e epsilon empty a e 1e 1 e1 l e 1e 1 e1 e 1e 2e 1e 2 e1 e2 l e 1e 1 e1 l e 2e 2 e2 e 1e 1 e1 e 2...

編譯原理 學習記錄1 程式編譯過程

前端 該階段的編譯工作主要依賴源程式,與目標機無關。語法分析 在詞法分析基礎上,將單詞序列分解成各類語法短語 也稱語法單位,如 程式 語句 表示式 可表示成語法樹 推導樹 通過語法分析,確定乙個輸入串是否構成乙個語法上正確的程式。即 經語法分析可以得到乙個分析樹。問 如何根據單詞序列構造語法分析樹?...