上回,為了解決移進-規約時的幾個問題,引入了幾個定義:
短語:
設有文法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 程式編譯過程
前端 該階段的編譯工作主要依賴源程式,與目標機無關。語法分析 在詞法分析基礎上,將單詞序列分解成各類語法短語 也稱語法單位,如 程式 語句 表示式 可表示成語法樹 推導樹 通過語法分析,確定乙個輸入串是否構成乙個語法上正確的程式。即 經語法分析可以得到乙個分析樹。問 如何根據單詞序列構造語法分析樹?...