前面说过了LLR(1)分析,它是自顶向下分析的,也就是推导。
下面就说LR系列的,它是自底向上分析的,也就是规约。
目录
LR(0)
在LR中,LR(0)是最简单的,也是要求最高的。括号中的数字就是向前看几个字符,显然这里是不向前看的。LR,L就是自左到右扫描输入串,R就是最右推导的逆过程最左规约。
注意:正规文法和规范推导别混淆了。规范文法是右递归或者左递归文法,规范推导就是最右推导,推出的句型是规范句型,其逆过程就是规范规约也就是最左规约。
我们知道,句柄就是最左直接短语,也就是最左规约过程中最先被规约的那个。
那么LR既然是规约的过程,势必先规约句柄。
LR(0)分析法的关键就在于构造相应的分析表。
活前缀:含句柄前面及其自身的前缀都是其活前缀。显然到一个活前缀的末尾时就该规约了。
LR(0)项目:就是文法中右部带 ·的规则
四种LR(0)项目
归约项目,圆点到达最右边
移进项目,圆点后面仍有终结符
待约项目,圆点后面有非终结符
接受项目,归约到文法的开始符号
构造DFA
我们知道NFA 到DFA的方法就是闭包,合并 空转移的状态。
最初我们可以由给出的LR(0)项目写出NFA,然后遇到待约项目可以加空串从而跳到相应非终结符对应的状态,从而构造DFA时要将这种状态合并。
此时的闭包函数CLOSURE,就是将待约项目中 圆点后面的非终结符对应的LR(0)项目加入当前状态中即可。
根据上述DFA写出转移表即可。
(状态,终结符)=终结符入栈+对应的下个状态入栈=Si
上面对应,DFA的移进项目的转移
(状态,终结符)=状态栈出一个状态+符号栈出若干进行对应的归约=Ri
(状态,非终结符)=将下个状态入栈
上面对应,DFA的待约项目中的非终结符完成了归约,然后退回到前一状态,紧接着可以直接跳到下个状态,因为此时归约的非终结符已经在栈中了
对应上面的状态写出即可。
限制:LR(0)文法,LR(0)文法,不能存在移进项目和归约项目、归约项目和归约项目同时并存。于是紧接着出现了下面的SLR(1)来协助解决一下。
SLR(1)
在上面的基础上,SLR(1)就想我能不能往前看一个字符呢,看看能不能根据下一个字符来确定是进行移进还是归约,或是进行哪种归约?
基于这种思想,我们能够解决LR(0)遗留的一部分问题,但是仍然会存在问题。
因为它要求移进与归约冲突中:移进的字符与归约到的非终结符的Follow集不能有交集;或是归约到的非终结符的Follow集之间不能有交集。因为一旦有交集又会冲突。所以又出现了LR(1)来继续协助。
SLR(1)文法就是能通过上面交集的办法解决LR(0)问题的文法。
LR(1)
SR(1)虽然能解决部分LR(0)的问题,但是它自身也存在一些问题。
因为上面的Follow集中出现的字符并非出现在特定的句型中,所以它可能会产生一些错误句型,就是条件相对宽松。
LR(1)也针对此问题给出了相应的办法,就是展望符,展望特定句型中的非终结符的Follow集,这样不会凭空出现新的句型。
LR(1)文法就是LR(1)的项目集中没有 移进-归约冲突 或 归约-归约冲突。
但不是LR(1)分析法能解决所有问题,也只是部分问题。
LALR(1)
LALR(1)分析法就是在LR(1)的基础上进行简化的,因为LR(1)的状态数比较多,存在同心集,就是除了展望符不同,其他都一样。LALR(1)将其合并会简化,但是有可能会出现新的问题就是归约-归约冲突,但是不会出现移进-归约冲突,因为LALR(1)分析法是在LR(1)的基础上,LR(1)是没有移进-归约冲突的,合并后也不会出现移进-归约冲突。但是归约-归约冲突是因为合并同心集时由于展望符不同而可能引发的问题。
至此就是LR的基本系列,我们可以看出LR系列也只是能解决部分问题,仍然有些问题是其不能解决的。