1. 程式人生 > >編譯原理LR(0)專案集規範族的構造和分析的構造

編譯原理LR(0)專案集規範族的構造和分析的構造

學編譯原理的時候,感覺什麼LL(1)、LR(0)、SLR(1)、LALR(1)思想滿天飛。

而且做題的時候,一不留意,一道題就寫了三頁紙了。

就拿今天這個玩意兒來講,我真的是考試前花了最多的時間,搞懂了(差不多搞懂了)這是個什麼玩意兒。

以下內容,做題的話應該夠了而且很!容!易!理!解!,其他學術情況恕博主也是個菜雞。

廢話就不多扯了,能搜到看到這篇文章的小夥伴也不容易,挺有緣的,根據步驟想參考資料的話,就拿出你的《編譯原理第二版·清華大學出版社》吧,第二版哦!我也不知道第三版一不一樣,反正頁數好像是不一樣。

我這裡就用書上現成的例子了吧,第二版的7.2.4 LR(0)專案集規範族的構造這節本身其實寫得很詳細很學術很看不懂。大概跟本文有關而且有意思很重要的內容是這樣的:

現在得到了一個拓廣文法G'(前面有介紹怎麼求,很簡單就加個S'的規則就行),好這勢必是一個好的開頭。

S'->E

E->aA | bB

A->cA | d

B->cB | d

接下來求文法的專案,這個也簡單,就給每個規則加一個點以後然後挪位置,挪一個位置就得到一個專案,操作完了以後你就得到了一堆專案,這就是你接下來要面對的核心的東西了。

1.S'->·E   2.S'->E·   3.E->·aA   4.E->a·A   5.E->aA·   6.A->·cA   7.A->c·A   8.A->cA·   9.A->·d

10.A->d·   11.E->·bB   12.E->b·B   13.E->bB·   14.B->·cB   15.B->c·B   16.B->cB·   17.B->·d   18.B->d·

有關CLOSURE閉包的構造和轉向函式GOTO(I,X)的定義小夥伴們自己看書吧,說實話你要真讓我複述定義我也半吊子,但內涵理解了就做題沒毛病了。不過還是要提到一個“核”的概念,你可以理解為那張圖的每一個狀態最頭上那條規則。

接下來構造專案集規範族那張圖的步驟是這樣的:

把有S'的專案而且點在最左邊的專案作為狀態I0的核,放在開頭。然後看這個點後面的非終結符,是個E,接下來就去專案中找左部是E的而且點在最左邊開頭位置的專案,列在核的下面,這就是狀態I0了,你可以畫個框框然後標記一下。


接下來還是先看核裡面點後的這個非終結符E,輸入E(你可以理解為在箭弧上標了個E),把點向後移一位,得到S'->E·,這其實是得到了一個新的狀態的核。當然另外兩個也一樣,輸入點後面的符號,比如輸入a得到E->a·A為核的新狀態,輸入b得到E->b·B為核的新狀態。得到新狀態的核了,就順便把這個狀態剩下的專案也列出來吧,就是看核的點後面的非終結符,找以這個非終結符為左部的點在最左邊的專案。當然要是點後面沒有東西就不用找了,新的狀態記得標號哦。


其實,講到這裡專案集規範族的構造方法部分就!完!了!接下來就是重複上面的工作,從每一個新狀態出發,逐個輸入每個專案點後面的符號,就是後移一位,又分別作為新的狀態的核然後根據核找下面的同狀態裡的專案。找到找不動為止。比如我再找一個I2後面的試試:


當你求出整張圖的時候,恭喜你萬里長征走完第一步了,後面可能涉及到的LR(0)分析表的構造,本文就“請看下回分解”了。

分析表的構造

上回把文法的LR(0)專案集規範族搞了半天,革命進行了一半。

鼓搗了半天整了一堆專案集規範族出來,總是有用的呀,接下來就是在那堆的基礎上構造分析表了,構造好分析表就能分析輸入串了。本文主要講LR(0)分析表的構造輸入串分析過程

我這個菜雞都覺得是通!俗!易!懂!的!!

憋說話往下看->

多的不扯,博(cai)主(ji)我使用的是清華大學出版社的《編譯原理第二版》,第二版哦,不知道第三版的小夥伴內容是不是一樣的,頁數好像不一樣我記得。在LR分析這一章的第二節後面,就是有專案集規範族那張圖那兒,我們還是以那個文法為主題講。

為了方便我直接為大家列好啦~


OK,這是上回我們構造好的專案集規範族,在構造分析表之前我們先畫好分析表

先寫好ACTION和GOTO兩個列標題,然後在ACTION下面寫一排文法的所有的終結符,別忘了還有#,GOTO下面寫文法中除了S'以外的所有的非終結符。


OK,接下來是這樣的,書上也有詳細的關於分析表構造演算法的解釋,說白了,其意思應該是這樣的:

1、找專案集規範族有S'->A·這種形狀的那個狀態Ik,就是第k個狀態,則把分析表第k行的#列標上acc

2、按順序(我一般是按狀態序號順序)分析狀態的專案和GOTO函式,主要就是看每個專案的點後面的符號

(1)要是是個終結符,看輸入這個終結符後去的哪個狀態,比如當前是狀態I0,對於第二個專案E->·aA,輸入a以後去了狀態I2,那就在分析表中第0行的a列寫上S2,意思就是狀態Ik輸入Vt後去了Ij狀態。

(2)要是是個非終結符,這個更好理解,比如從狀態Ik輸入這個非終結符以後去了狀態Ij,那就在GOTO表的第k行第Vn列寫j。

3、你會發現有的專案的點是在最後,這就是分析表裡面那些小r的來歷了。先看這個專案所在的狀態,再看點前面的規則是文法裡面的第幾個規則,比如說狀態I10的A->d·裡面的A->d就是文法的第4條規則,那就在分析表的第10行所有的終結符列包括#列寫上r4,就是ACTION列的一行寫滿。即狀態Ik的專案來自於文法的第j條規則,則分析表的第k行都是rj。

我們具體試試吧:

1、先找acc,以免高興過頭了忘記。狀態I1裡面有S'->E·,所以acc在第1行。


2、按順序開始看I0,第一個專案點後面是非終結符E,輸入E前往狀態I1,所以GOTO表的第0行第E列寫1。第二個專案點後面是a,輸入a以後前往I2,則ACTION表第0行第a列寫S2。第三個專案點後面是b,輸入b後前往I3,則ACTION表第0行第b列寫S3。


3、狀態I1有acc了,不管了。跳過看I2。同理,輸入A的時候改GOTO表,輸入c和d的時候改ACTION表,而且都是寫S形式的。你會發現一直到I5都是這樣。


4、狀態I6,這是個點在最後面的專案,看前面的規則,是文法的第1個規則,那第6行就寫一行r1。狀態I7,點前面的規則是文法的第2條規則,則第7行寫一行r2。同理到狀態I11。

書中 的文法G是

E->aA|bB

A->cA|d

B->cB|d

所以這裡的

r1代表E->aA

r2代表E->bB

r3代表A->cA

r4代表A->d

r5代表B->cB

r6代表B->d

即當 . 為結束時,就意味著有了一個可歸納的控制代碼,此時用ri代表的句型歸納


到這裡該文法的LR(0)分析表就!構!造!完!了!

是不是很心累,要是看書看不懂聽課犯糊塗更心累!別問我為啥知道......

順便說說這個表又是拿來幹嘛的吧,搞了半天當然是有用的有實際價值的是符合社會發展所需要求的。

輸入串的分析過程,在實際的分析程式裡面還有兩個重要的輔助英雄角色,狀態棧和符號棧。要是做題的話就寫在草稿紙上吧,考試的時候應該也不會讓你分析超長的串。分析前先往狀態棧壓一個0進去,符號棧壓一個#進去,輸入串最後加個#。

比如我要分析bccd,書上也有例子。

當前輸入串bccd#,即將輸入b,看狀態棧頂,是0,去看分析表,第0行第b列是S3,不是r什麼什麼。好,把角標3壓狀態棧,b壓符號棧,輸入串少一個。

當前為ccd#,即將壓c,狀態棧頂為3,看分析表第3行第c列,是S5,好,5和c分別壓棧。

當前為cd#,即將壓c,狀態棧頂為5,看分析表第5行第c列,是S5,好,5和c分別壓棧。

當前為d#,即將壓d,狀態棧頂為5,看分析表第5行第d列,是S11,好,11和d分別壓棧。

當前為#,即將壓#,狀態棧頂為11,看分析表第11行第#列,是r6。好,歷史走到了轉折點。趕緊去看文法的第6條規則,把符號棧頂歸約為B,狀態棧頂11彈出。然後再看狀態棧頂5和符號棧頂B,GOTO表第5行第B列是9,記得在分析過程這一步的GOTO寫9,然後把9壓狀態棧。這裡要分清棧操作的先後順序。

當前為#,即將壓#,狀態棧頂為9,看分析表第9行第#列,是r5,好,同上一個步驟找規則歸約掉然後壓棧,然後找GOTO表把新狀態壓棧。

重複上面的操作。

最後一步是這樣的,狀態棧頂為1,即將壓#,分析表第1行第#列為acc,至此分析結束,bccd是該文法的產生式。

如果是錯誤串呢?

你放心,早做不下去了,崩了。

以上用於知道怎麼做題

再貼道題目

6證明文法     S ® bB        B® B*a   B ® a

不是LR(0)文法,而是 SLR(1)文法。

【解】

對該文法拓廣,得其拓廣文法G[S]:

(0) S→S     (1) S ->bB      (2) B-> B*a  (3) B -> a

計算其LR(0)專案集規範族如下:

I0 = closure{ S→.S } ={ S→.S , S→. bB }

I1 = GOTO(I0S) = { S→S.}

I2 = GOTO(I0b) = { S→b.BB->.B*aB ->.a }

I3 = GOTO(I2B) = { S→bB.B-> B.*a }

I4 = GOTO(I2a) = { B -> a. }

I5 = GOTO(I3*) = { B-> B*.a }

I6 = GOTO(I5a) = { B-> B*a. }

因為該文法的LR(0)專案集規範族中有一個專案集I3同時存在移進專案與歸約專案,即“移進-歸約”衝突,所以不是LR(0)文法

     I3  = { S→bB.B-> B.*a }

而,FOLLOWS={ # }

Follow(S) ∩ { * } = φ

即可採用Follow集能解決其衝突,所以該文法是SLR(1)文法。


轉載於https://blog.csdn.net/Johan_Joe_King/article/details/79051993