`
NeuronR
  • 浏览: 59844 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

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

分享到:
评论
8 楼 NeuronR 2009-02-22  
lwwin 写道


关于分歧的几个地方我还是不明白会做什么:
(1) 状态IfElseBranch_5遇First(Sentence)规约 ElseBlock -&gt; ε 然后Goto状态 IfElseBranch_6
:规约ElseBlock为空对应的代码有必要进行规约吗?

(2) 状态VariableRegister_VariableInitialization_1遇COMMA或EOS规约Initialization -&gt; ε
:如果(1)条目是有必要的,那么该条目是否应增加GOTO到VariableRegister_VariableInitialization_2这个状态呢?


1
状态IfElseBranch_5遇First(Sentence)表示这时if分支没有else,但是IfElseBranch这个数据结构不会凭空少个指针,所以要规约一个NULL赋值给那个指针。

你也可以这样尝试一下:单独再弄个数据类型,专门用来存放没有else的if分支语句结构(比如叫做ConditionalExecution),那么这时在状态IfElseBranch_5就直接规约为一个ConditionalExecution就可以了。

总之,这个地方进行规约,是为了在LR分析器的符号栈中填充一个空符号。

2
是呀。

状态VariableRegister_VariableInitialization_1遇COMMA或EOS规约Initialization -> ε
状态VariableRegister_VariableInitialization_1遇Initialization则Goto
                                                                 状态VariableRegister_VariableInitialization_2
7 楼 lwwin 2009-02-22  

关于分歧的几个地方我还是不明白会做什么:
(1) 状态IfElseBranch_5遇First(Sentence)规约 ElseBlock -> ε 然后Goto状态 IfElseBranch_6
:规约ElseBlock为空对应的代码有必要进行规约吗?

(2) 状态VariableRegister_VariableInitialization_1遇COMMA或EOS规约Initialization -> ε
:如果(1)条目是有必要的,那么该条目是否应增加GOTO到VariableRegister_VariableInitialization_2这个状态呢?
6 楼 lwwin 2009-02-17  
VSD你居然不知道 OTL 微软的VISIO嘛-3-
那我导出到HTML好嘞(MHT有时候会不兼容?),你可以下载看看

其实就是究竟是STATE0到移进各个符号,还是STATE1移进符号,我现在的理解是STATE0是任意初始状态,比如遇到<IO>或者<IF>就开始下一个状态STATE1……哦,是不是说STATE0是第一次,之后规约后的所有状态都到STATE1?

目前版本是V1.3,你可以下载来看看了^^
5 楼 NeuronR 2009-02-17  
lwwin 写道

改了二遍,基本上理解了
只是,我对状态0和状态1的概念还有疑问,看了几遍还是不清楚,能不能再描述一下
你看我的VSD图上因为和你的文字还是对应不起来,我想能早些找到问题^^,麻烦了~

囧……vsd该怎么打开?

状态0大部分跟状态BasicBlock_SentenceBasicBlock_1是相同的,差别是状态0遇到BasicBlock就跳到状态1
而状态1是个特殊状态,到达这个状态表示一个基本块已经被识别了。但是这样并不意味着整个语法分析结束,也许那只是嵌套在内部的基本块。
4 楼 lwwin 2009-02-17  
改了二遍,基本上理解了
只是,我对状态0和状态1的概念还有疑问,看了几遍还是不清楚,能不能再描述一下
你看我的VSD图上因为和你的文字还是对应不起来,我想能早些找到问题^^,麻烦了~
3 楼 lwwin 2009-02-16  
仔细看了一回,可能还有一些不是太清楚,我画了一张VISIO的框图
(比较单调,其实偷懒了,其实如果是EXCEL更好些……反正直观比较要紧~)
2 楼 NeuronR 2009-02-03  
lwwin 写道

每一个小节之后都要跟上这么一段:

什么是一小节?

跟这么大一段牵扯到LR状态集中,每一个状态的构造,并不是每一个状态都需要跟这么一段的。
1 楼 lwwin 2009-02-03  
看了两回,似乎有点明白
我没怎么看过文法,估计看懂比较困难,自己先大概记忆了……
每一个小节之后都要跟上这么一段:

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
WhileLoop -> · <WHILE> <LPARENT> Assignment <RPARENT> BasicBlock
Declaration -> · <TYPE> VariableRegister <EOS>

不太明白 都一样吗?…………

相关推荐

    LR1语法分析生成器

    在描述中提到的"加上框架代码,构造出LR1语法分析程序",意味着LR1生成器不仅生成状态转换表,还会提供一些基础的框架代码,这些代码可以与状态转换表结合,用于构建完整的LR1解析器。框架代码通常包括输入符号的...

    LR(0).rar_LR 语法分析_LR(0)_LR分析表_lr语法分析_语法分析LR

    LR(0)分析是编译器设计中的一个重要概念,它是一种自底向上的语法分析方法。LR(0)分析表的构建是理解编译器如何处理输入程序的关键步骤。在这个过程中,我们首先需要理解什么是LR分析,特别是LR(0)分析。 LR分析,...

    LR(1)语法分析 编译器 项目集构造课程设计

    LR(1) 语法分析编译器项目集构造课程设计 LR(1) 语法分析编译器项目集构造是编译器设计中的一种重要技术,用于实现语法分析。下面是该技术的详细知识点: 一、LR(1) 语法分析器的设计目的和要求 LR(1) 语法分析器...

    lR语法分析器设计.pdf

    LR语法分析器是一种用于解析上下文无关文法的高效工具,广泛应用于编译器设计中。LR分析器从左向右扫描输入字符串,并自底向上地进行语法分析,旨在判断输入字符串是否符合文法的语句。以下是关于LR分析器设计的一些...

    编译原理自底向上语法分析--LR分析

    编译原理是研究编译器构建的理论基础,其中自底向上的语法分析,特别是LR分析,是编译器设计的重要部分。本文将深入探讨LR分析的基本概念、工作原理以及如何使用C++来实现一个LR分析器,并附带实验报告。 **LR分析*...

    LR实现语法分析

    LR分析是一种在编译原理中广泛使用的自底向上语法分析技术,主要应用于解析程序源代码。LR分析器根据文法规则推导出输入符号串是否符合文法,从而判断其是否为合法的程序结构。本篇文章将深入探讨LR分析方法,特别是...

    编译原理 语法分析器--LR(1)分析法

    1. **状态集**: LR(1)分析器通过构造一系列的状态集来进行语法分析,每个状态集包含一组项目。 2. **项目**: 在构造状态集时使用的基本单元,用于表示文法中某个规则的部分匹配状态。 3. **动作表(Action Table)**...

    LR(0)语法分析器程序

    LR(0)语法分析器是一种在编译原理中常见的解析技术,主要应用于处理上下文无关文法。这个程序是用C语言编写的,因此具备高度的可移植性和效率。 LR(0)分析器的核心思想是基于状态转移表,通过自底向上的方式逐层解析...

    编译原理-LR0语法分析-java

    每个LR状态都包含一个项目集(Item Set),项目集是一组文法规则,每个规则的指针指向下一个待处理的部分。例如,对于规则"A → BC",一个项目可能是"A → B·C",表示我们已经看到"A"并期待"B"。当我们遇到"B"时,...

    LR0语法分析程序生成器

    LR0语法分析程序生成器是一种自动化工具,它用于解析给定的上下文无关文法(Context-Free Grammar, CFG),并生成相应的LR0分析器状态转换表。这个过程是编译器设计中的一个重要环节,因为LR0分析器是编译器前端的...

    LR语法分析器 编译原理课程设计 源码

    LR语法分析器的全称是“左到右扫描,右部优先”的语法分析器,其工作原理是自左向右读取输入符号串,并通过一套状态转移表(通常称为LR分析表)来决定如何进行下一步操作。这个过程涉及到了文法、状态、动作和移进/...

    基于LR(0)方法的语法分析程序

    LR(0)方法是编译原理中用于语法分析的一种重要技术,主要应用于自底向上的解析过程。这个程序设计的任务是构建并使用LR(0)分析表来解析符合特定语法规则的输入串。LR(0)分析器的构建基于状态机模型,它通过一系列的...

    LR1语法分析器 java版本 含报告

    LR1语法分析器是编译原理领域中的一个重要工具,它基于经典的 LR(1) 分析方法,用于解析符合特定上下文无关文法的输入字符串。本项目提供了Java语言实现的LR1语法分析器,适用于学习和实践编译器设计课程的学生。在...

    编译原理LR0语法分析程序加报告

    在编译原理中,LR0(Left-to-Right, Shift-Reduce, 0-follow set)是一种广泛应用的自底向上的语法分析方法。本项目提供的“LR0语法分析程序”是基于C++实现的,适用于理解和实践编译器设计中的语法分析阶段。下面将...

    编译原理上机源代码LR语法分析器

    《编译原理上机源代码LR语法分析器》 编译原理是计算机科学中的核心领域,涉及语言处理、解析技术等方面。LR语法分析是编译器设计中的一个重要环节,用于将高级语言转换为机器可执行的指令。这篇实验报告详细介绍了...

    lr语法分析源码

    LR(LALR或LR(k))语法分析是一种在编译原理中广泛使用的解析技术,主要用于将源代码转换为可执行代码。LR分析器基于上下文无关语言的文法,能够处理复杂的语法结构。本资源包含的是LR语法分析的源代码,对于学习...

    LR(1)语法分析器

    LR(1)语法分析器是一种在编译原理中广泛使用的解析技术,主要用于处理上下文无关文法。这种分析器能够处理更复杂的语言结构,而不仅仅是简单的左递归或右递归表达式。以下是对LR(1)语法分析器及其相关知识点的详细...

    编译原理实验LR语法分析器

    在Java中实现LR语法分析器,首先需要对编译原理中的核心概念有深入理解,包括正规表达式、上下文无关文法(CFG)、状态机、项集、分析表等。LR分析器的核心是LR分析表,这个表包含了每个状态下的动作(Shift、Reduce...

    语法分析器LR(0)

    在实现一个LR(0)语法分析器时,首先需要对输入的文法进行处理,构造出LR(0)项目集,然后生成动作表和.goto表。在图形界面中,用户可以输入文法,分析器根据文法自动构建解析表,并提供解析功能。用户还可以查看解析...

    编译原理 lr语法分析器

    LR语法分析器是编译器设计中的一种重要工具,用于解析程序源代码,将其转化为中间形式,以便后续的编译阶段进行处理。本实验报告将深入探讨LR(0)语法分析器的工作原理及其应用。 LR分析,全称为“Left-to-Right,...

Global site tag (gtag.js) - Google Analytics