[语法分析]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中的链表内插入对应的对象进去就行了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值