概述
回溯的消除
在自上而下分析过程中,由于回溯需要推翻前面的分析,包括已做的一大堆语义工作,重新去进行试探,这样大大降低了语法分析器的工作效率,因此,需要消除回溯。
从 4.2.1 节中我们已经发现引起回溯的原因是,在文法中某个非终结符 A 有多个候选式,遇到用 A 去匹配当前输入符号 a 时,无法确定选用唯一的一个候选式,而只能逐一进行试探,从而引起回溯,这具体表现为下面两种情况。第一种情况是相同左部的规则,其右部左端第一个符号相同而引起回溯。例 4.1 即是这种情况。第二种情况是相同左部的规则,其中某一右部能推出 ε 串,例如,文法 G :A → Bx , B → x | ε 。其非终结符 B 有两个右部,第二个右部能推导出 ε 串且两个右部左端第一个符号不相同,但在分析符号串 W = x 时出现回溯。试探分析过程如图 4.2 所示。
面临输入符号 x 时,用文法开始符号 A 的规则(仅一条规则)向下构造语法树,见图 4.2 (a ),其左子结点为非终结符 B ,它有两个选择,先试用 B → x 向下构造语法树,见图 4.2 ( b ),输入串 x与 B 的子结点 x 匹配,输入串指针右移,输入串已结束,但语法树中 A 的右子结点 x 未得到匹配,分析失败。回溯使输入串指针退回到 x ,对 B 选用规则 B → ε ,见图 4.2 (c ),输入符号 x 得到正确匹配,分析成功。显然,选用规则 B → ε 相当于与 B 的后继符号 x 进行匹配,这里由于 B 的后继符号 x 与 B 的第一个选择的右部左端的第一个符号 x 相同,所以面临输入符号 x 时出现回溯。
综上所述,在自上而下分析过程中,为了避免回溯,对描述语言的文法有一定的要求,即要求描述语言的文法是 LL ( 1 )文法。为了建立 LL ( 1 )文法的判断条件,需引进 3 个相关集:FIRST 集、 FOLLOW 集和 SELECT 集。
(1 )设 α 是文法 G 的任一符号串,定义文法符号串 α 的首符号集合
`FIRST ( α ) = { a | α ⇒* a … 且 a∈ V T }`
若 α ⇒* ε,则规定 ε ∈FIRST ( α )。换句话说, FIRST ( α )是从 α 可推导出的所有首终结符或可能的 ε 。
(2 )设文法 G 的开始符号为 S ,对于 G 的任何非终结符 A ,定义非终结符 A 的后继符号的集合
FOLLOW ( A ) = { a | S ⇒*… Aa … 且 a ∈ V T }
若有 S ⇒*… A ,则规定 $ ∈FOLLOW (A )。换句话说 FOLLOW ( A )是 G 的所有句型中紧接在 A 之后出现的终结符或 $ 。
这里用 $ 作为输入串的结束符,例如, $ 输入串 $ 。
(3 )定义规则的选择集合 SELECT 。设 A → α 是文法 G 的任一条规则,其中 A ∈ V N ,α ∈ ( V N ∪ V T )* ,定义
SELECT ( A → α ) =FIRST ( α ) 若 α ⇒ /* ε
SELECT ( A → α ) =FIRST ( α ) { ε } ∪FOLLOW ( A )若 α ⇒* ε
现在,可以给出 LL ( 1 )文法的判断条件。
一个上下文无关文法 G 是 LL ( 1 )文法,当且仅当对 G 中每个非终结符 A 的任何两个不同的规则 A → α | β ,满足 SELECT ( A → α ) ∩SELECT ( A → β ) = Ø 。其中 α ,β 中至多只有一个能推出 ε 串。这里,LL ( 1 )中的第一个 L 表明自上而下的分析是从左到右扫描输入串,第二个 L 表明分析过程中使用最左推导,1 表示分析时每一步只需向前看一个符号即可决定所选用的规则,而且这种选择是准确无误的。
回顾前面例 4.1 中的文法
S → aAb
A → de | d
不难看出
SELECT ( A → de ) =FIRST ( de ) = { d }
SELECT ( A → d ) =FIRST ( d ) = { d }
所以SELECT ( A → de ) ∩SELECT ( A → d ) ≠ Ø
由 LL ( 1 )文法定义可知,例 4.1 文法不是 LL ( 1 )文法,因此对输入串进行自上而下分析会发生回溯。
【例 4.6 】设有文法 G [ A ]:
A → aB | d
B → bBA | ε
则
SELECT ( A → aB ) =FIRST ( aB ) = { a }
SELECT ( A → d ) =FIRST ( d ) = { d }
SELECT ( B → bBA ) =FIRST ( bBA ) = { b }
SELECT ( B → ε ) =FOLLOW ( B ) = { a , d , $ }
所以
SELECT ( A → aB ) ∩SELECT ( A → d ) = Ø
SELECT ( B → bBA ) ∩SELECT ( B → ε ) = Ø
由定义可知,G [ A ]是 LL ( 1 )文法,对任何输入串 W 可进行无回溯的分析。
【例 4.7 】设有文法 G [ S ]:
S → aAB
A → bB | dA | ε
B → a | e
则
SELECT ( S → aAB ) =FIRST ( aAB ) = { a }
SELECT ( A → bB ) =FIRST ( bB ) = { b }
SELECT ( A → dA ) =FIRST ( dA ) = { d }
SELECT ( A → ε ) =FOLLOW ( A ) = { a , e }
SELECT ( B → a ) =FIRST ( a ) = { a }
SELECT ( B → e ) =FIRST ( e ) = { e }
所以
SELECT ( A → bB ) ∩SELECT ( A → dA ) = Ø
SELECT ( A → bB ) ∩SELECT ( A → ε ) = Ø
SELECT ( A → dA ) ∩SELECT ( A → ε ) = Ø
SELECT ( B → a ) ∩SELECT ( B → e ) = Ø
由定义可知,文法 G [ S ]是 LL ( 1 )文法,对任何的输入串可进行确定的自上而下分析。
综合上面的讨论可知,对 LL ( 1 )文法,若当前非终结符 A 面临输入符号 a 时,可根据 a 属于哪一个 SELECT 集,唯一地选择一条相应规则去准确地匹配输入符号 a 。也就是说,当描述语言的文法是 LL ( 1 )文法时,可对其进行确定的自上而下的分析。
最后
以上就是着急灰狼为你收集整理的回溯的消除的全部内容,希望文章能够帮你解决回溯的消除所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复