[Theory] Parsing Techniques 读书笔记(六):确定性自底向上解析

9. Deterministic Bottom-Up Parsing

名词定义

handle:别识别出的字符串片段(segment),和产生是规则(production rule)。

操作符文法(operator grammar):是一种上下文无关文法,每条产生式的右边至少包含一个终结符或一个非终结符,并且右边的任意两个非终结符都不相连。操作符文法中的终结符,称为操作符(operator)。

有界上下文文法(bounded-context grammar):对归约进行了上下文限制,产生式 A -> α 的右边 α,只有当出现在合适的上下文 β_1 α β_2 中时,才会被归约为 A。其中 β_1 称为左上下文,β_2 称为右上下文,它们都是有限长度的,分别为 m,n。如果对于任意的 α,存在唯一确定的上下文 β_1 α β_2,就称该文法为有界上下文文法,记为 BC(m,n)。

右界上下文文法(bounded-right context grammar):如果有界上下文文法中的右边界(right context)只包含终结符,该文法就称为右界上下文文法,记为 BRC(m,n)。

station:handle查找自动机(handle-finding automata)的一种状态,它表示只有通过ε 字符转入的边,没有跳转出去的边。

不充分状态(inadequate state):确定性自动机中的,包含歧义的状态。
LR(0)文法:可以构造一个不含歧义状态LR(0)自动机的文法,称为LR(0)文法。
LR(1)文法:通过前瞻一个字符,可以得到一个不含歧义的LR(1)自动机,这样的文法称为LR(1)文法。

item look-ahead:当前推导后面可以跟的字符串的集。
dot look-ahead:当前解析位置,后面可以跟的字符串集。

LALR(1)文法:带前瞻特性的LR(0)解析器(Look Ahead LR(0) with a look-ahead of 1 token)
LA(k)LR(j)文法:LA(k)表示右上下文(前瞻),LR(j)表示左上下文(状态机)。LALR(1)实际上是LA(1)LR(0),LALR(k)是LA(k)LR(0)。

内容总结

确定性自底向上解析器的主要任务是寻找handle,一定handle确定下来,解析方法也就确定下来了。
对自底向上解析来说,语义动作(semantic actions)在的归约(reduction)时触发的,在产生式被确定的那一刻。

优先级解析(precedence parsing)的关键在于确定优先级关系(precedence relation),或优先级表(precedence table)。

操作符文法中的优先级关系,也可以用优先级函数(precedence function)来表示,占用更少的空间。

LR解析器的重要部分是一个状态机(handle-finding automata),它可以由任意的上下文无关文法构造出来,它表示任意的非终结符接受任意字符会跳转到哪个状态(包括ε 字符)。
状态机的状态数,与语法中的非终结符数目成正比。
根据文法,我们可以先得到一个非确定性状态机,然后通过子集构造法(subset construction),转换成确定性自动机。

借助确定性状态机,可以得到LR(0)解析算法。
(1)如果当前状态不是接受状态,则读取下一个字符。
(2)如果是接受状态,则从弹出一个状态,以及相应长度的输入字符串,进行一次归约,再把归约后的非终结符压栈。

确定性状态机的行为,经常表示成两个表ACTION和GOTO,ACTION表示归约或移入字符,GOTO表示当前状态接受字符后跳转到哪个状态。
LR(0)根据当前字符的所有左上下文,来判断归约方式,相当于具有无穷长左边界的右界上下文文法 BRC(∞,0)。

LR(0)对应的确定性自动机的接受状态可能是有歧义的,包括两种:shift/reduce歧义性(shift还是reduce都可行),reduce/reduce歧义性(两种reduce方式)。

包含空串规则(ε-rules)的文法不是LR(0)的,解决方法可以采用动态解析(dynamically parse)检查当前的状态栈。

由于LR(0)的要求比较严格,所以只有很少的文法是LR(0)的。
因此,可以加入前瞻机制,来提升解析器的能力,通过前瞻一个字符得到解析器称为LR(1)解析器。
LR(1)自动机,也可以表示为两个表ACTION和GOTO。
LR(1)解析器有足够的能力处理空串规则(ε-rules)。

LR(k>1)不是简单的LR(1)扩展,需要引入两种前瞻:item look-ahead 和 dot look-ahead。
对于LR(1)而言,dot look-ahead 与 item look-ahead 是同一个集合。

LR(k)文法的性质:
(1)LR(k>1),总是转换为LR(k-1),但是LR(1)却不总是能转换成LR(0)。
(2)下推自动机可解析的语言,是LR(1)的,也称为确定性语言(deterministic languages)。
(3)任何用确定性方法可解析的语言,都是LR(1)的。
(4)LR(k)是目前能力最强大的解析器。

LR(1)的缺点是,占用了太多了内存空间。
一个简单的文法对应的自动机,可能会包含成千上万个状态。
LALR(1)是LR(0)自动机和前瞻方法的合并,状态数与LR(0)一样。

构建LALR(1)解析表的通常方法是,先构造LR(1)解析表,然后再进行状态合并,这个方法比较繁琐。
另外还有一些常见的解析表构造方法:
(1)一个简单的算法:在构造解析表的时候,避免重复的状态
(2)yacc使用的channel算法
(3)relations算法:对LR(0)状态机进行调整,找到不充分的状态(inadequate state)消除歧义。具体处理方法比较复杂:包括lookback relation和includes relation。
(4)通过文法变化,把LALR(1)转换成SLR(1)。

SLR(1)解析器的能力介于LR(0)和LALR(1)之间,但是SLR(1)解析器的大小却跟LALR(1)差不多。所以,LALR(1)更常见。


参考

Parsing Techniques

你可能感兴趣的:([Theory] Parsing Techniques 读书笔记(六):确定性自底向上解析)