《編譯原理》LR 分析法與構造 LR(1) 分析表的步驟 - 例題解析

《編譯原理》LR 分析法與構造 LR(1) 分析表的步驟 - 例題解析

筆記blog

直接作題是有一些特定步驟,有技巧。但也必須先了解一些基本概念,本篇會經過例題形式解釋概念,會容易理解和記憶,以及解決相似問題。圖片

若是隻想作題能夠直接下拉至習題部分。編譯

(一)關於狀態

對於產生式 A→aBcD,就能夠分解爲下面幾個不一樣的識別狀態:table

(1)A→.aBcD
(2)A→a.BcD
(3)A→aB.cD
(4)A→aBc.D
(5)A→aBcD.class

「.」 的左部符號表示已被識別出來的那部分句柄符號編譯原理

狀態(1)表示:處於句柄的頭
狀態(2)表示:已經識別出字符 a,等待 造成以 B 爲產生式左部的右部
狀態(3)表示:剛剛進行了一次規約,即把關於 B 的產生式右部規約成 B
狀態(4)表示:已經識別出字符 c,等待 造成以 D 爲產生式左部的右部
狀態(5)表示:已經到達句柄的尾巴,能夠把 aBcD 規約爲產生式左部的符號 A原理

(二)什麼是 LR(k) 分析法?

字面意思理解:bfc

字符 含義
L 表示 從左到右 掃描輸入串
R 表示利用 最右分析方法 來識別句子,即構造一個 最右推導的逆過程
k 表示向右查看輸入串符號的個數

LR 分析過程是規範歸約的過程搜索

規範規約是最右推導的逆過程,最右推導是規範推導,因此 最左規約是規範規約。循環

LR 分析法根據當前分析棧中的符號串和向右順序查看輸入串的 k 個符號就能夠惟一肯定分析器的動做是移進仍是歸約、利用那個產生式進行歸約。

當沒有指明 k 是幾的時候,默認爲 1

(三)文法的拓廣?

文法的拓廣是對現有文法,添加一個 S',並對文法進行展開。

例如:

對於文法 G[E]:
E → E+T|T
T → T*F|F
F → i|(E)

能夠把它拓廣爲

文法 G[E']:
E' → E
E → E+T|T
T → T*F|F
F → i|(E)

此時可能會有疑問,不就是加了個開始符號,有什麼意義呢?爲何要再加個開始符號呢?

加開始符號是爲了狀態的表示,這樣原來的 S 會成爲右部,能夠表示 .S 和 S.

那同一非終結符的右部有多種狀況爲何不展開呢?

這裏是說拓廣文法,是添加開始符號,能夠展開能夠不展開,可是通常默認要展開,通常一道題不會只讓求拓廣文法,而是爲了後面。通常題目中是說 「求該文法的拓廣文法並編號」,此時請必定要展開。展開後應該是這樣:

1.E'→E
2.E → E+T
3.E → T
4.T → T*F
5.T → F
6.F → i
7.F → (E)

(四)什麼是項目?項目有哪些分類?等價狀態?

上面提到拓廣文法,展開,以及編號。

先看例題:

對於文法 G[S]:
S → vI:T
I → I,i
I → i
T → r

能夠把它拓廣並編號,以下:

文法 G[S']:
1.S' → S
2.S → vI:T
3.I → I,i
4.I → i
5.T → r

它的所有 LR(0) 項目,以下:

1.S' → .S
2.S' → S.
3.S → .vI:T
4.S → v.I:T
5.S → vI.:T
6.S → vI:.T
7.S → vI:T.
8.I → .I,i
9.I → I.,i
10.I → I,.i
11.I → I,i.
12.I → .i
13.I → i.
14.T → .r
15.T → r.

對上面 LR(0) 項目進行分類

類型 包含 特色
規約項目 2, 7, 11, 13, 15 . 在右部的末尾
接收項目 2 . 在開始符號的末尾
移進項目 3, 5, 9, 10, 12, 14 . 後面跟着終結符,表移進
待約項目 1, 4, 6, 8 . 後面跟着非終結符,表等待後面非終結符的規約,簡稱待約

誰和誰是等價狀態?

例如:

待約項目 4 即 S→v.I:T 它的含義是等待棧頂規約出 I,但還沒有識別對應 I 的那些句柄的任何符號;

項目 8 即 I→.I,i 和項目 12 即 I→.i 的含義也是期待棧頂造成 I 的句柄,因此這三個項目的含義是同樣的,即 4, 8, 12 三個狀態是等價的。

同理:項目 6 即 S → vI:.T 和項目 14 即 T → .r 也是等價的

爲何它們是等價狀態?怎麼判斷等價狀態?

上面有說由於他們表示的含義是同樣的,而且會發現等價確定涉及至少一個待約項目,以及一個 . 在最左端的移進項目。

這是由於,待約項目是 . 後面跟非終結符,這個 . 是在非終結符的前面;當存在該非終結符的產生式時,且 . 在最左端的時候。由於 . 在最左端,其實也是至關於在該非終結符的前面。因此是一個等價的狀態。

(五)LR 分析表介紹

LR 分析器的關鍵部分是 分析表的構造。分析表有如下幾種:

規範的 LR 分析表:

  • LR(0),能力最弱,侷限性較大,但理論上最重要。
  • LR(1),它功能最強,但代價也最大。

簡單的 LR 分析表:

  • 簡稱 SLR ,最容易實現,但功能最弱。

向前看的 LR 分析表:

  • 簡稱 LALR,功能和代價處於前二者之間,適用於絕大多數程序語言的文法

總結: LR(0) 功能最弱,功能弱是說當文法中產生式比較複雜,出現某些問題時,沒法解決。這些問題一部分能夠由 SLR 分析法解決。但還有一部分 SLR 解決不了,能夠用 LR(1) 來解決。

(六)關於 「展望

在規範歸約過程當中,一方面記住已移進和歸約出的整個符號串,即記住 「歷史」,另外一方面根據所用的產生式推測將來可能碰到的輸入符號,即對將來進行 「展望」。

當一串貌似句柄的符號串呈現於分析棧的頂端時,根據所記載的 「歷史」 和 「展望」 材料,來肯定棧頂的符號串是否構成句柄。

爲了記住分析的 「歷史」 和聚集 「展望」 的信息,LR 分析法這樣處理:

將歸約過程的 「歷史」 和 「展望」 材料綜合抽象成某些狀態,存放在一個狀態棧中,棧中每一個狀態都歸納了從分析開始直到某一歸約階段的所有「歷史」和「展望」材料。

LR(1) 分析法這樣處理:

首先,明白了在 LR(1) 分析法中展望是爲了解決其餘分析法解決不了的問題。簡單的說就是,狀態會出現衝突,咱們不能只經過後 1 個輸入串符號,直接肯定選用哪一個產生式,這是嚴重的錯誤。

因此 展望(向前搜索符) 是經過展望後面的內容,因此展望對應的終結符,應該 屬於該非終結符的 FOLLOW 集(確切的說,屬於 FOLLOW 集中的具體哪一個個終結符,應該根據產生式的推導過程肯定,經過語法樹來分析,是比較直觀的方法。也能夠直接經過求該非終結符後的 FIRST 集來肯定,但要注意是對誰求 FIRST 集,可表示爲 FIRST(βa),例題中會提到),來幫助惟一肯定選擇產生式。

拓展注:這裏提到的 FOLLOW 集和 FIRST 集不是衝突的,由於咱們要求的向前搜索符時 FOLLOW 集的子集,有時候不能肯定,因此用 FIRST(βa), β 表示由誰哪一個非終結符推導的,這個非終結符的後面的剩餘串,a 表示它上一個狀態中的向前搜索符。它倆拼接起來的串,對該串求 FIRST 集。
那麼可能會有疑問,利用上一個狀態?那第一個狀態呢?第一個狀態是固定的 S'→S,#
其實 # 就是 S 的 FOLLOW 集中的惟一的元素,它也是開始符號的向前搜索符
因此說 FOLLOW 集和 FIRST(βa) 是均可以求的,FIRST(βa) 是準確的向前搜索符,它是 FOLLOW 集的一部分

在 LR(1) 中,用

狀態, 終結符
例如:S' → # (#表示開始符號FOLLOW集會提到那個符號,有的地方用 $,是同樣的 )

這種形式是表式展望,終結符就是展望的後面的終結符,具體的下面例題中還會提到。

(七)終極例題 - LR(1) 分析表的構造

給定文法 G[S]:

S→L=R | R
L→*R | id
R→L

回答如下問題:

(1)文法的拓廣並編號
(2)LR(1) 項目集規範族所對應的識別活前綴的 DFA
(3)構造 LR(1) 分析表

解析:

1)文法的拓廣並編號:

拓廣文法 G[S']:

(0)S'→S
(1)S→L=R
(2)S→R
(3)L→*R
(4)L→id
(5)R→L

2)LR(1) 項目集規範族所對應的識別活前綴的 DFA*

這裏就涉及到 「展望」 這個知識點了

向前搜索符的 FIRST 集求法:

求法 FIRST(βa)

  • β 表示由誰哪一個非終結符推導的,這個非終結符的後面的剩餘串
  • a 表示它上一個狀態中的向前搜索符。

對於 I0
首先 S' → .S, # 這個是固定的,就是第一個狀態的核心項目
下面對 S 求向前全部符都沒問題,都是 #
到了 L→.*R,這裏,求向前搜索符,使用 FIRST(βa)
應該是求 FIRST(=R#) 因此就是 = 了

爲何是 =R#?

由於 β 表示由誰哪一個非終結符推導的,這裏就是上面狀態【S→.L=R, #】這個非終結符 L 的後面的剩餘串是 =R,a 表示它上一個狀態中的向前搜索符,就是 #,拼接起來就是 =R#。

(圖片來源:中國大學慕課 -《編譯原理》哈爾濱工業大學 陳老師)

該 DFA 有窮自動機的解釋:

(1)這樣表示形式就是自動機,每一個方框表示一個狀態,從 I0 到 I13 因此共有 14 個狀態。
(2)每一個狀態中包含的多個項目,都是等價的。
(3)每一個項目中逗號後面的終結符或者 # 表示展望的終結符。
(4)關於畫出 DFA 的步驟:

  • 以 I0 爲例,首先對於 0 號產生式 S' → S,可知應該有 S' → .S 和 S' → S. 兩個狀態,由於 S' 是開始符號,展望是屬於 FOLLOW 集的,展望應該是 #,能夠得出 S' → .S, #
  • 由於 .S 表示等待規約出 S 的狀態。而且 S→L=R,因此 .S 和 .L=R 是兩個等價的狀態。但須要注意的是此時的 FOLLOW 集應該 S 的 FOLLOW 集,而不是 L 的,也不 R 的
  • 同理,由於有 S→R,則 .S 和 .R 是兩個等價的狀態。
  • 有了 .R,應該繼續去找 R 爲左部的產生式,由於有 R→L,因此 .S 和 .L 是兩個等價的狀態。
  • 注意: 在找 R 的展望終結符時,展望 是經過展望後面的內容,因此展望對應的終結符,應該 屬於該非終結符的 FOLLOW 集(確切的說,屬於 FOLLOW 集中的具體哪一個個終結符,應該根據產生式的推導過程肯定,經過語法樹來分析,是最直觀的方法)


(圖片來源:中國大學慕課 -《編譯原理》哈爾濱工業大學 陳老師)

能夠看出來 R 的展望應該有兩種狀況,一個是 =,一種是 #

但此時,咱們經過 S → R 找到的 R,因此應該是 #

不斷循環經過,將 . 後移,判斷下一個狀態,找出等價狀態,直到判斷完成。

3)構造 LR(1) 分析表

根據自動機便可構造 LL(1) 分析表:


(圖片來源:中國大學慕課 -《編譯原理》哈爾濱工業大學 陳老師)

LL(1) 分析表解釋補充:

(1)內容 LL(1) 分析表 = 動做表 (ACTION) + 狀態轉移表(GOTO)

(2)動做表 中的每個元素 ACTION[S,a] 規定了當 棧頂狀態 爲 S,且面臨輸入符號 a 時應採起的動做。根據自動機中的終結符邊可判斷。

(3)狀態轉換表 中的每個元素 GOTO[S,x] 規定了當狀態 S 面對文法符號位 x 時的下一個狀態。根據自動機中的非終結符邊可判斷。

(4)動做表 的列對應全部終結符加上 #

(5)狀態轉換表 的列對應全部非終結符,不包括 S',由於 S 就是開始符號,S' 是爲了使 「接收狀態」 易於識別,所引入的。

(6)動做表 中例如:

  • ACTION[0, *] 的 S4 表示移進,入棧,就是當前狀態爲 0,當輸入串爲 ,則將狀態 4 移進狀態棧,將 移進文法符號棧
  • ACTION[5, =] 的 r4 表示符合產生式 4,將棧頂符號 id 規約爲產生式左部
  • acc 表示接收

(7)狀態轉換表 中例如:

  • GOTO[0, S] 的 數字爲 1 表示轉入 1 狀態,置當前文法符號棧頂爲 S,棧頂狀態爲 1

(8)構造 LL(1) 分析表的步驟,重要 !!!:

  • 肯定對應行 ,行就是全部狀態
  • 肯定對應列 ,列有兩部分 ACTION 表和 GOTO 表,ACTION 表中列是全部終結符,以及 #。 GOTO 表的對是全部非終結符,不包括 S'
  • !!!GOTO 表的構造:判斷當前輸入串,若是存在自動機的邊,且邊爲非終結符就把狀態編號填入 GOTO 表
  • !!!ACTION 表的構造:

    • 查找該狀態中是否有 . 在最後的狀態,若是有先根據向前搜索符肯定哪一列,再用 rn,填入表示,r 的含義是規約,n 表示的是產生式的序號;若是沒有則說明沒有沒有 r
    • 判斷是否存在該狀態輸出的邊,若是存在則用 Sn 表示,S 表示移進,入棧,n 表示下一個狀態的序號

(9)上面也更深刻的瞭解了展望的意義,首先,展望是存在一個狀態中的,終結符,對應的應該爲是當前等價的狀態,操做也就應該是移進。若是是自動機的邊,就是說不是當前狀態了,因此對應的是規約。


總結

易錯點:

  • 展望對應的終結符 是經過展望後面的內容,因此展望對應的終結符,應該 屬於該非終結符的 FOLLOW 集(確切的說,屬於 FOLLOW 集中的具體哪一個個終結符,應該根據產生式的推導過程肯定,經過語法樹來分析,是最直觀的方法)
  • 各教材描述可能存在差別,但思想是相同的
    • 好比 $ 和 #
    • 好比展望終結的表示方法,有的分開寫,有的直接用或
相關文章
相關標籤/搜索