[語法分析]LR狀態集

    由於識別表達式的工作已經委託給其他的分析器去做了,因此這一階段需要關注的產生式其實很少,它們是:

 

Jerry -> BasicBlock <END>

 

BasicBlock -> ε

BasicBlock -> Sentence BasicBlock

 

Sentence -> <EOS>

Sentence -> IfElseBranch

Sentence -> WhileLoop

Sentence -> Declaration

Sentence -> <IO> Assignment <EOS>

Sentence -> Assignment <EOS>

Sentence -> <BREAK> <EOS>

Sentence -> <LBRACE> BasicBlock <RBRACE>

 

IfElseBranch -> <IF> <LPARENT> Assignment <RPARENT> BasicBlock ElseBlock

ElseBlock -> <ELSE> BasicBlock

ElseBlock -> ε

 

WhileLoop -> <WHILE> <LPARENT> Assignment <RPARENT> BasicBlock

 

Declaration -> <TYPE> VariableRegister <EOS>

VariableRegister -> VariableRegister <COMMA> Variable Initialization

VariableRegister -> Variable Initialization

Initialization -> <ASSIGN> Assignment

Initialization -> ε

 

產生式比一般習題中出現的還是要多,不過進行LR分析比之前要輕鬆得多。首先是狀態0和狀態1:

-------------------------------

狀態0

Jerry -> · BasicBlock <END>

 

BasicBlock -> ·

BasicBlock -> · Sentence BasicBlock

 

Sentence -> · <EOS>

Sentence -> · IfElseBranch

Sentence -> · WhileLoop

Sentence -> · Declaration

Sentence -> · <IO> Assignment <EOS>

Sentence -> · Assignment <EOS> # 注a

Sentence -> · <BREAK> <EOS>

Sentence -> · <LBRACE> BasicBlock <RBRACE>

 

IfElseBranch -> · <IF> <LPARENT> Assignment <RPARENT> BasicBlock ElseBlock

 

WhileLoop -> · <WHILE> <LPARENT> Assignment <RPARENT> BasicBlock

 

Declaration -> · <TYPE> VariableRegister <EOS>

-------------------------------

狀態1  # 一旦接受到<END>就 Accept 的項目

Jerry -> BasicBlock · <END>

-------------------------------

注a:因爲Assignment使用OperationAnalyser來分析,所以這個項目並不衍生出其他項目。並且,在狀態0中,只要遇到First(Assignment)集合中的東西,就拉一個OperationAnalyser到分析器棧頂,然後轉過去。這種先讀入符號再變換分析器的過程稱之爲延遲的變換,對應的,有立即變換,即一旦步入某個狀態,立即更改分析器,比如在這個狀態下:

 

IfElseBranch -> <IF> <LPARENT> · Assignment <RPARENT> BasicBlock ElseBlock

 

毫無疑問,因爲已經沒有別的選了,接下來只可能是Assignment,所以這裏可以立即變換分析器。

    狀態0既是一個規約狀態,也是一個待移進狀態。如果下一個符號是First(Sentence)集合中的符號,那麼就繼續分析,如果是Follow(BasicBlock)就規約。這裏

First(Sentence) = {EOS, WHILE, IF, INTEGER_TYPE, REAL_TYPE, READ, WRITE, BREAK, LBRACE}

                            U First(Assignment)

Follow(BasicBlock) = {ELSE, END, RBRACE}

兩家是井水不犯河水,因此這個衝突可以用SLR(1)方法解決。

    另外,這個狀態1看起來有點怪怪的,這是因爲在Jerry中引入了一個特殊的符號END所致,而END只會出現在輸入結尾,因此可以忽略它,這樣狀態1就跟書上的別無二致了。

 

#############################################

 

    爲了遠離序號式命名帶來的晦澀和難於記憶,以後的狀態採取另一種命名法,對於主項目對應的產生式左部有多個產生式對應的(如SentenceVariableRegister等都有多個產生式與之對應),該狀態命名採取這種方式:

    主項目對應產生式的左部名稱 _ 主項目右部符號名稱序列(當然不全是大寫,可以採用駱駝命名法) _ 點號的位置

如狀態

    Sentence -> <IO> Assignment · <EOS>

可以命名爲“狀態Sentence_IOAssignmentEoS_2”,點號在第二個符號之後,因此後面的數字爲2。對於主項目產生式左部在產生式集合中僅一次作爲左部出現的,不會導致歧義,因此直接這樣命名:

    產生式的左部名稱 _ 點號位置

如狀態

    IfElseBranch -> <IF> <LPARENT> · Assignment <RPARENT> BasicBlock ElseBlock

可以命名爲“狀態IfElseBranch_2”。

 

#############################################

 

在繼續之前,強烈建議你拿出一張草稿紙在上面畫畫,特別是對於整個LR狀態集合中最亂的狀態1

 

狀態1移進一個Sentence非終結符就轉移到這個狀態

狀態BasicBlock_SentenceBasicBlock_1

BasicBlock -> Sentence · BasicBlock

BasicBlock -> ·

BasicBlock -> · Sentence BasicBlock

 

Sentence -> · <EOS>

Sentence -> · IfElseBranch

Sentence -> · WhileLoop

Sentence -> · Declaration

Sentence -> · <IO> Assignment <EOS>

Sentence -> · Assignment <EOS> # 注a

Sentence -> · <BREAK> <EOS>

Sentence -> · <LBRACE> BasicBlock <RBRACE>

 

IfElseBranch -> · <IF> <LPARENT> Assignment <RPARENT> BasicBlock ElseBlock

 

WhileLoop -> · <WHILE> <LPARENT> Assignment <RPARENT> BasicBlock

 

Declaration -> · <TYPE> VariableRegister <EOS>

------------------------------

這個狀態的SR衝突解決跟狀態1相同。它移進一個BasicBlock之後變爲狀態

 

狀態BasicBlock_SentenceBasicBlock_2

BasicBlock -> Sentence BasicBlock ·

------------------------------

接下來還是狀態1遇到某些終結符作轉移的目標狀態:

EOS轉狀態Sentence_EoS_1,該狀態遇任何符號都規約

Sentence -> <EOS> ·

------------------------------

IF轉狀態IfElseBranch_1

IfElseBranch -> <IF> · <LPARENT> Assignment <RPARENT> BasicBlock ElseBlock

------------------------------

WHILE轉狀態WhileLoop_1

WhileLoop -> <WHILE> · <LPARENT> Assignment <RPARENT> BasicBlock

------------------------------

Assignment則Goto到狀態Sentence_AssignmentEoS_1

Sentence -> Assignment · <EOS>

------------------------------

BREAK轉狀態Sentence_BreakEoS_1

Sentence -> <BREAK> · <EOS>

------------------------------

LBRACE轉狀態Sentence_LBraceBasicBlockRBrace_1

Sentence -> <LBRACE> · BasicBlock <RBRACE>

 

BasicBlock -> ·

BasicBlock -> · Sentence BasicBlock

 

Sentence -> · <EOS>

Sentence -> · IfElseBranch

Sentence -> · WhileLoop

Sentence -> · Declaration

Sentence -> · <IO> Assignment <EOS>

Sentence -> · Assignment <EOS> # 注a

Sentence -> · <BREAK> <EOS>

Sentence -> · <LBRACE> BasicBlock <RBRACE>

 

IfElseBranch -> · <IF> <LPARENT> Assignment <RPARENT> BasicBlock ElseBlock

 

WhileLoop -> · <WHILE> <LPARENT> Assignment <RPARENT> BasicBlock

 

Declaration -> · <TYPE> VariableRegister <EOS>

------------------------------

INTEGER_TYPE或REAL_TYPE轉狀態Declaration_1

Declaration -> <TYPE> · VariableRegister <EOS>

 

VariableRegister -> · VariableRegister <COMMA> Variable Initialization

VariableRegister -> · Variable Initialization # 注b

------------------------------

注b:Variable也會扔給另一個分析器去分析,因此該狀態會立即變換分析器。

 

    寫到這裏,這一篇已經很長了,並且大部分的工作都很瑣碎無趣。因此接下來之列出狀態名和轉移關係,這些東西只作爲具體實現的參考。

狀態1READ或WRITE狀態Sentence_IOAssignmentEoS_1

狀態Sentence_IOAssignmentEoS_1Assignment則Goto狀態Sentence_IOAssignmentEoS_2

狀態Sentence_IOAssignmentEoS_2遇EOS轉狀態Sentence_IOAssignmentEoS_3

狀態Sentence_IOAssignmentEoS_3遇任何符號都規約

 

狀態IfElseBranch_1LPARENT狀態IfElseBranch_2

狀態IfElseBranch_2Assignment則Goto狀態IfElseBranch_3

狀態IfElseBranch_3RPARENT狀態IfElseBranch_4

狀態IfElseBranch_4BasicBlock則Goto狀態IfElseBranch_5 # 注c,解釋在文章最後

狀態IfElseBranch_5ELSE狀態ElseBlock_1

狀態IfElseBranch_5遇First(Sentence)規約 ElseBlock -> ε 然後Goto狀態 IfElseBranch_6

狀態IfElseBranch_5ElseBlock則Goto狀態IfElseBranch_6

狀態IfElseBranch_6遇任何符號都規約

狀態ElseBlock_1BasicBlock則Goto狀態ElseBlock_2

狀態ElseBlock_2遇任何符號都規約

 

狀態WhileLoop_1LPARENT轉狀態WhileLoop_2

狀態WhileLoop_2Assignment則Goto狀態WhileLoop_3

狀態WhileLoop_3RPARENT轉狀態WhileLoop_4

狀態WhileLoop_4BasicBlock則Goto狀態WhileLoop_5

狀態WhileLoop_5遇任何符號都規約

 

狀態Sentence_AssignmentEoS_1遇EOS轉狀態Sentence_AssignmentEoS_2

狀態Sentence_AssignmentEoS_2遇任何符號都規約

 

狀態Sentence_BreakEoS_1遇EOS轉狀態Sentence_BreakEoS_2

 

狀態Sentence_BreakEoS_2遇任何符號都規約

 

狀態Sentence_LBraceBasicBlockRBrace_1遇BasicBlock則Goto狀態Sentence_LBraceBasicBlockRBrace_2

狀態Sentence_LBraceBasicBlockRBrace_2遇RBrace轉狀態Sentence_LBraceBasicBlockRBrace_3

狀態Sentence_LBraceBasicBlockRBrace_3遇任何符號都規約

 

狀態Declaration_1遇Variable則Goto狀態VariableRegister_VariableInitialization_1

狀態VariableRegister_VariableInitialization_1遇ASSIGN轉狀態Initialization_AssignAssignment_1

狀態Initialization_AssignAssignment_1遇Assignment則Goto狀態Initialization_AssignAssignment_2

狀態Initialization_AssignAssignment_2遇任意符號都規約

狀態VariableRegister_VariableInitialization_1遇COMMA或EOS規約Initialization -> ε

狀態VariableRegister_VariableInitialization_1Initialization則Goto

                                                                 狀態VariableRegister_VariableInitialization_2

狀態VariableRegister_VariableInitialization_2遇任意符號都規約

 

狀態Declaration_1VariableRegister則Goto狀態DeclarationVariableRegister # 注d,解釋在文章最後

狀態DeclarationVariableRegister遇COMMA轉狀態Declaration_1

狀態DeclarationVariableRegister遇EOS轉狀態Declaration_3

狀態Declaration_3遇到任何符號都規約

 

注c:遇到BasicBlock似乎是一件很麻煩的事情,只要那個小點打在這傢伙前面,那就會惹來一大堆項目;不過從另一方面考慮,凡是遇到BasicBlock——狀態BasicBlock_SentenceBasicBlock_1除外——就變換分析器,準確地說,是弄一個新的LRAnalyser放到分析器棧棧頂,然後繼續。這樣可以省很多LR狀態的。

 

注d:首先,從形式上,這個叫做DeclarationVariableRegister的狀態包含這麼幾個項目:

 

Declaration -> <TYPE> VariableRegister · <EOS>

VariableRegister -> VariableRegister · <COMMA> Variable Initialization

所以它的名字看起來很詭異。然而,問題在於如果真這樣了,那看起來一個VariableRegister至多導出2個Variable Initialization,這顯然是不科學的。原因在於,實際上狀態Declaration_1

Declaration -> <TYPE> · VariableRegister <EOS>

 

VariableRegister -> · VariableRegister <COMMA> Variable Initialization

VariableRegister -> · Variable Initialization

是一個項目數量任意多的狀態(注意,項目VariableRegister -> · VariableRegister <COMMA> Variable Initialization這是個左遞歸項目)。因此,有些狀態上面甚至並沒有列舉出來。解決這個問題的方法是對左遞歸產生式導致的缺陷視而不見,在實現的時候,每當規約一次

    VariableRegister -> Variable Initialization

就在對應的DeclarationNode中的鏈表內插入對應的對象進去就行了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章