非确定的自上而下分析法的思想:
左递归: 文法左递归,是指文法中某个非终结符A存在推导A ⇒ +Aα。
分析:自上而下分析法施行最左推导,每次替换当前句型的最左非终结符,当试图用非终结符A去匹配输入串时,结果使当前句型的最左非终结符仍为A。即在没有任何输入符号的情况下,又重新要求A去进行新的匹配,于是造成无穷循环。因此需要消除文法左递归。
消除左递归:
引进一个新的非终结符,将含左递归的规则改成右递归:
过程中注意空串
采用扩充BNF表示法改写含直接左递归的规则:
回溯: 在文法中某个非终结符A有多个候选式,遇到用 A 去匹配当前输入符号a时,无法确定选用唯一的一个候选式,而只能逐一进行试探,从而引起回溯,具体表现为下面两种情况:
消除回溯: 要求描述语言的文法是LL(1)文法。
LL(1)文法:
Left to right,left to most。
LL(1)中第一个“L”表明自上而下的分析是从左到右扫描输入串,第二个“L”表明分析过程中使用最左推导,“1”表明分析时每一步只需向前看一个符号即可决定所选用的准确无误的规则。
首先明确3个相关集:
LL(1)文法的判断条件: 对于每个非终结符的任何两个不同的规则,满足二者的SELECT集相交为空。
当一个文法不是LL(1)文法时,对输入串进行自上而下的分析就会发生回溯。因此,首先要消除左递归并将其转换为LL(1)文法。对LL(1)文法,若当前非终结符A面临输入符号a时,可根据a属于哪一个SELECT集,唯一地选择一条相应规则去准确匹配输入符号a。
非LL(1)文法到LL(1)文法的转变:
对一些非LL(1)文法而言,可通过消除左递归和反复提取公共左因子对文法进行等价变换,将其改造为LL(1)文法。
一个例子:
而一些公共左因子是隐式的,所以可以用一些规则进行替换后得到显式的左公因子,之后再进行消除。
一个例子:
但是,也并非所有的非LL(1)文法都能被成功改写为LL(1)文法。
一个例子:
递归下降分析法简单、直观、易于构造分析程序,但文法要求高,另外递归调用多,影响分析器的效率。
这里说明一下,选用候选式入栈的时候,实际上就相当于用右部替换栈中的左部。
预测分析表的构造:
总控程序对于不同的LL(1)文法相同,预测分析表对不同LL(1)文法不同。
错误处理:
(1)栈顶终结符与当前输入不匹配
(2)栈顶为非终结符,与当前输入在预测分析表中的对应值为空
“移进-归约”原理
基本思想:用一个寄存文法符号的先进后出栈,将输入符号一个一个地按从左到右扫描顺序移入栈中,边移入边分析,当栈顶符号串形成某条规则右部时就进行一次归约,即用该规则左部非终结符替换相应规则规则右部符号串,栈顶被归约的这一串符号为可归约串。重复这一过程直到整个输入串分析完毕。最终若栈中剩下句子右界符 “$” 和文法的开始符号,则所分析的输入符号串是文法的正确句子,否则报告错误。
关键问题:定义并识别“可归约串”
定义可归约串 { 规 范 归 约 分 析 法 − − − 用 “ 句 柄 ” 刻 画 可 归 约 串 算 符 优 先 分 析 法 − − − 用 “ 最 左 素 短 语 ” 刻 画 可 归 约 串 \left\{\begin{aligned}规范归约分析法---用“句柄”刻画可归约串\\算符优先分析法---用“最左素短语”刻画可归约串\end{aligned}\right. {规范归约分析法−−−用“句柄”刻画可归约串算符优先分析法−−−用“最左素短语”刻画可归约串
根据识别可归约串的不同方法,形成不同的自下而上分析方法,简单优先分析法和LR分析法都是规范归约分析法,但二者识别句柄的方法不同:
识别可归约串 { 简 单 优 先 分 析 法 : 根 据 文 法 符 号 之 间 的 优 先 关 系 确 定 栈 顶 符 号 串 是 否 形 成 句 柄 L R 分 析 法 : 根 据 历 史 、 现 实 、 展 望 的 信 息 确 定 栈 顶 符 号 串 是 否 形 成 句 柄 \left\{\begin{aligned}简单优先分析法:根据文法符号之间的优先关系确定栈顶符号串是否形成句柄\\LR分析法:根据历史、现实、展望 的信息确定栈顶符号串是否形成句柄\end{aligned}\right. {简单优先分析法:根据文法符号之间的优先关系确定栈顶符号串是否形成句柄LR分析法:根据历史、现实、展望的信息确定栈顶符号串是否形成句柄
要明确算符优先文法,我们首先要明确什么是优先关系,什么是算符文法。
算符文法:
简单来说,即任一规则右部都不存在两个非终结符相邻的情况
算符优先文法:
一个例子:
算符优先关系表:
简单来说,FIRSTVT(A)集就是 A 右部从左向右遇到的第一个终结符,LASTVT(A)就是A右部从左向右遇到的最后一个终结符
构造算法如下:
一个例子:
优先关系表中,左侧列为左边的算符,上方的一行为右侧的算符。
素短语: 至少包含一个终结符,并且除自身外,不再包含其他终结符。
最左素短语: 句型最左边的素短语为最左素短语。
识别最左素短语的方法:
算符优先分析算法:
算符优先分析法的局限性:
自下而上规范归约
“L”指从左到右扫描输入符号串,“R”指构造最右推导的逆过程
LR(k)表示需要向前查看k个输入符号的LR分析法,一般k=0或k=1,当省略(k)时,表示k=1。
关键:如何确定分析栈栈顶的符号串是否已形成句柄
基本思想:在规范归约分析过程中,
(1)历史:根据分析栈中记录的已移进和归约出的整个符号串
(2)展望:根据使用的规则推测未来可能遇到的输入符号
(3)现在:现实读入的输入符号
由上述3个方面的信息来确定分析栈栈顶的符号串是否构成句柄。
分析表的结构:
ACTION对应终结符、$,GOTO对应非终结符
在分析的任意时刻,分析栈中已“移进-归约”的全部文法符号与剩余的输入符号串合起来就是文法的一个规范句型。
表格驱动,对文法限制少,大多数无二义性的上下文无关文法描述的语言都可以用LR分析法进行有效的分析,即便对于非LR的上下文无关文法,常见的程序设计语言构造都可以避免使用这样的文法。
分析速度快,采用无回溯的“移进-归约”分析,和其他更原始的“移进-归约”方法一样高效,并能准确及时地指出输入串的语法错误和出错位置
{ L R ( 0 ) S L R ( I ) L R ( 1 ) L A L R ( 1 ) \left\{\begin{aligned}LR(0)\\SLR(I)\\LR(1)\\LALR(1)\end{aligned}\right. ⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧LR(0)SLR(I)LR(1)LALR(1)
LR(0)分析法,就是在分析的每一步,只需根据当前栈顶状态而不必向前查看输入符号就能确定应采取的分析动作。
文法规范句型的活前缀:
(1)字符串的前缀是指字符串的任意首部
(2)规范句型活前缀是指规范句型的前缀。
活前缀可以是一个或若干个规范句型的前缀。
LR(0)项目:
拓广文法:
构造识别文法活前缀的DFA:
**冲突:**移进-归约冲突、归约-归约冲突
simple LR分析法,简单的LR分析法
向前查看一个输入符号
基本思想:
SLR(1)分析表中每一个状态,只有在遇到FOLLOW集中的元素时才会对归约状态采取归约动作,而LR(0)分析法中不论遇到什么输入符号,都会对归约状态采取归约动作
冲突: 如下就是一个移进-归约冲突
等价LR(1)项目:
规范LR(1)项集族:
对LR(1)合并同心集
冲突:会产生归约-归约冲突,但是不会产生移进-归约冲突
利用优选级、结合性,利用LR消除二义性