需要文法转换的原因
问题1
例如:
文法G:
S→aAd∣aBe
A→c
B→b
输入:
a b c
当同一非终结符的多个候选式存在共同前缀,将导致回溯现象。
问题2
例如:
文法G:
E→E+T∣E−T∣T
T→T∗F∣T/F∣F
F→(E)∣id
输入:
id+id∗id
推导过程:
E⇒E+T⇒E+T+T⇒E+T+T+T⇒...
因为文法开始符号的候选式没有以
id开头的,所以选择第一个候选式。而因为输入的符号并没有被匹配,所以在相同的条件下依然还是要选择第一个候选式。由此导致了死循环。
注:
- 含有
A→Aα形式产生式的文法称为是直接左递归(immediate left recursive)的(一步推导)。
- 如果一个文法中有一个非终结符A使得对某个串
α存在一个推导
A⇒+Aα,那么这个文法就是左递归的。
- 经过两步或两步以上推导产生的左递归称为是间接左递归。
- 左递归文法会使递归下降分析器陷入无限循环。
消除直接左递归
例如:
A→Aα∣β(
a̸=ϵ,
β不以A开头)
推导:
A⇒Aα⇒Aαα⇒...⇒Aααα...α⇒βααα...α
所以写成正则表达式就是
r=βα∗
那么原来的文法即可转换成
A→βA′和
A′→αA′∣ϵ.
而,
A′⇒αA′⇒ααA′⇒...⇒α...αααA′⇒α...ααα,即
A′→α∗。
事实上,这种转换把左递归转换成了右递归。
例子:
E→E+T∣T
可把
+T看做
β,把
T看做
β。直接套用上面的公式,即
E→TE′
E′→+TE′∣ϵ
消除直接左递归的一般形式
A→Aα1∣...∣Aα2∣Aαn∣β1∣β2∣...∣βn
(
aj̸=ϵ,
βj不以A开头)
那么可以转换为
A→β1A′∣β2A′∣...∣βnA′
A′→α1A′∣α2A′∣...∣αnA′∣ϵ
消除左递归是要付出代价的–引进了一些非终结符和
ϵ产生式
消除间接左递归
例:
S→Aα∣b
A→Ac∣Sd∣ϵ
将S的定义带入A-产生式,得:
A→Ac∣Aad∣bd∣ϵ
再消除A-产生式得直接左递归,得:
A→bdA′∣A′
A′→cA′∣adA′∣ϵ
提取左公因子
例:
文法G:
S→aAd∣aBe
A→c
B→b
可转换为,文法G’:
S→aS′
S′→Ad∣Be
A→c
B→b
通过改写产生式来推迟决定,等读入了足够多的输入,获得足够信息后再做出正确的决定。