语法分析:自下而上分析
Posted 松子茶
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了语法分析:自下而上分析相关的知识,希望对你有一定的参考价值。
概述
介绍自下而上语法分析方法。所谓自下而上分析法就是从输入串开始,逐步进行“归约”,直至归约到文法的开始符号;或者说,从语法树的末端开始,步步向上“归约”,直到根结。
自下而上分析基本问题
归约
我们所讨论的自下而上分析法是一种“移进-归约”法。这种方法的大意是,用一个寄存符号的先进后出栈,把输入符号一个一个地移进到栈里,当栈顶形成某个产生式的一个候选式时,即把栈顶的这一部分替换成(归约为)该产生式的左部符号。
首先考虑下面的例子:
假定文法G为
(1) S→aAcBe
(2) A→b
(3) A→Ab
(4) B→d <1>
我们希望把输入串abbcde归约到S。每实现一步归约都是把栈顶的一串符号用某个产生式的左部符号来代替。后面我们权且把栈顶上的这样一串符号称为“可归约串” ,存在种种不同的方法刻画“可归约串”。对这个概念的不同定义形成了不同的自下而上分析法。在算符优先分析中,用“最左素短语”来刻画“可归约串”,在“规范归约”分析中,则用“句柄”来刻画“可归约串”。
自下而上分析的中心问题是,怎样判断栈顶的符号串的可归约性,以及,如何归约。这是算符优先分析和LR分析将讨论的问题。各种不同的自下而上分析法的一个共同特点是,边输入单词符号(移进符号栈),边归约。也就是在从左到右移进输入串的过程中,一旦发现栈顶呈现可归约串就立即进行归约。这个过程对于编译实现来说是一个十分自然的过程。
规范归约简介
令G是一个文法,S是文法的开始符号,假定abd是文法G的一个句型,如果有
则称b是句型abd相对于非终结符A的短语。特别是,如果有
则称b是句型abd相对于规则A→b的直接短语, 一个句型的最左直接短语称为该句型的句柄。
作为“短语”的两个条件均是不可缺少的。仅仅有Ab,未必意味着b就是句型abd的一个短语。因为,还需有SaAd这一条件。
稍为精确的一点说,假定a是文法G的一个句子,我们称序列
是a的一个规范归约,如果此序列满足:
- an=a
- a0 为文法的开始符,即 a0=S
- 对任何i, 0<ifn , ai−1 是从 ai 经把句柄替换为相应产生式的左部符号而得到的。
容易看到,规范归约是关于a的一个最右推导的逆过程。因此,规范归约也称最左归约。
在形式语言中,最右推导常被称为规范推导。由规范推导所得的句型称为规范句型。如果文法G是无二义的,那么,规范推导(最右推导)的逆过程必是规范归约(最左归约)。
请注意句柄的“最左”特征,这一点对于移进-归约来说是重要的。因为,句柄的“最左”性和符号栈的栈顶两者是相关的。对于规范句型来说,句柄的后面不会出现非终结符号(即,句柄的后面只能出现终结符)。基于这一点,我们可用句柄来刻画移进-归约过程的“可归约串”。因此,规范归约的实质是,在移进过程中,当发现栈顶呈现句柄时就用相应产生式的左部符号进行替换。
符号栈的使用与语法树的表示
栈是语法分析的一种基本数据结构。在解释“移进-归约”的自下而上分析过程时我们就已经提到了符号栈。一个“移进-归约”分析器使用了这样的一个符号栈和一个输入缓冲区。今后我们将用一个不属于文法符号的特殊符号‘#’作为栈底符,即在分析开始时预先把它推进栈;同时,也用这个符号作为输入串的“结束符”,即无条件地将它置在输入串之后,以示输入串的结束。
分析开始时,栈和输入串的初始情形为:
符号栈 | 输入串 |
---|---|
# | w# |
分析器的工作过程是:自左至右把输入串w的符号一一移进符号栈里,一旦发现栈顶形成一个可归约串时,就把这个串用相应的归约符号(在规范归约的情况下用相应产生规则的左部符号)代替。这种替换可能持续多次,直至栈顶不再呈现可归约串为止。然后,就继续移进符号,重复整个过程,直至最终形成如下格局:
符号栈 | 输入串 |
---|---|
#S | # |
此时,栈里只含#与最终归约符S(在规范归约的情形下S为文法开始符号),而输入串w全被吸收,仅剩下结束符。这种格局表示分析成功。如果达不到这种格局,意味着输入串w(源程序)含有语法错误。
语法分析对符号栈的使用有四类操作:“移进”、“归约”、“接受”和“出错处理”。
- “移进” 指把输入串的一个符号移进栈。
- “归约”指发现栈顶呈可归约串,并用适当的相应符号去替换这个串(这两个问题都还没有解决)。
- “接受”指宣布最终分析成功,这个操作可看作是“归约”的一种特殊形式。
- “出错处理”指发现栈顶的内容与输入串相悖,分析工作无法正常进行,此时需调用出错处理程序进行诊察和校正,并对栈顶的内容和输入符号进行调整。
对于“归约”而言请留心一个非常重要的事实,任何可归约串的出现必在栈顶,不会在栈的内部。对于规范归约而言,这个事实是明显的。由于规范归约是最右推导的逆过程,因此这种归约具有“最左”性,故可归约串必在栈顶,而不会在栈的内部。正因如此,先进后出栈在归约分析中是一种非常有用的数据结构。
如果要实际表示一棵语法分析树的话,一般来说,使用穿线表是比较方便的。这只须对每个进栈符号配上一个指示器就可以了。
当要从输入串移进一个符号a入栈时,我们就开辟一项代表端末结a的数据结构,让这项数据结构的地址(指示器值)连同a本身一起进栈。端末结的数据结构应包括这样一些内容:(1) 儿子个数:0;(2) 关于a自身的信息(如单词内部值,现在暂且不管)。
当要把栈顶的n个符号,如 X1X2…Xn 归约为 A 时,我们就开辟一项代表新结A的数据结构。这项数据结构应包含这样一些内容:(1) 儿子个数:n;(2) 指向儿结的n个指示器值;(3) 关于A自身的其它信息。归约时,把这项数据结构的地址连同A本身一起进栈。
最终,当要执行“接受”操作时,我们将发现一棵用穿线表表示的语法树业已形成,代表根结的数据结构的地址和文法的开始符号(在规范归约情况下)一起留在栈中。
用这种方法表示语法树是最直截了当的。当然,也可以用别的或许是更加高效的表示方法。
算符优先分析
算符优先文法及其优先表构造
一个文法,如果它的任一产生式的右部都不含两个相继(并列)的非终结符,即不含如下形式的产生式右部:
则我们称该文法为算符文法。
在后面的定义中,a、b代表任意终结符;P、Q、R代表任意非终结符;‘…’代表由终结符和非终结符组成的任意序列,包括空字。
假定G是一个不含e-产生式的算符文法。对于任何一对终结符a、b,我们说:
- a≖b 当且仅当文法G中含有形如 P→…ab… 或 P→…aQb… 的产生式;
- a⋖b 当且仅当G中含有形如 P→…aR… 的产生式,而 Rb… 或 RQb… ;
- a⋗b 当且仅当G中含有形如 P→…Rb… 的产生式,而 R…a 或 R…aQ 。
如果一个算符文法G中的任何终结符对(a,b)至多只满足下述三关系之一:
则称G是一个算符优先文法。
现在来研究从算符优先文法G构造优先关系表的算法。
通过检查G的每个产生式的每个候选式,可找出所有满足
a≖b
的终结符对。为了找出所有满足关系
⋖
和