编译原理 递归下降分析 的应用

递归下降分析只适合于 每个子表达式的第一个终结符号能够为产生式的选择提供足够完备的信息 的情形。

意思就是 从第一个终结符号就能完全确定 采用哪个产生式。

比如

E->E+T | E-T | T

T->T*F | T/F |  F

F->id | num |  (E)

分析(1 + 5  ) * 9    例1  首先 应该是 E => E' * T  然后解析 E' 这个 1+5

或者( 1 + 5 * 9 )    例2 首先应该是 E=>(E) 。(这里是 E=>T=>F=>(E))

执行解析时 遇到第一个终结符号 ( 那么 首先 应该选择 应用的是哪个呢?所以这里就不能够应用递归下降分析。

因为拿到一个( 无法确定是用  E=>(E) 还是 E => E' * T


问题

 为什么不能确认先用哪个语法呢? 遇到(肯定先用 E=>(E) 吗? 

因为这里就整个语法而言,应该是将整个看成一个整体的。所以对于 (1 + 5  ) * 9  不能先看 (1+5) 再看*9 这是从人的上帝视角去看,你已经完全熟悉这个字符串表示的意思了。


假如有一个终结符和非终结符组成的 字符串 gama FIRST(gama)是从gama可以 推导 出的  任意字符串中开头终结符组成的集合。

比如

gama=T*F。

那么gama能推导出所有 类似于  expr * expr的所有字符串。由于F最终是 F->id | num |  (E)

那么就能够得到 FIRST(T*F) ={ id , num , ( } 这是必定的。

如果X 有两个产生式  X->gama1 X->gama2 .并且FIRST(gama1) 交 FIRST(gama2) 于 终结符 I

那么当读取到终结符I时。递归下降分析就不能确定到底是使用这两个中的哪一个。

FOLLOW(A) 表示可能在某些句型中紧跟在A右边终结符号的集合。注意是紧跟在A后面。而不是属于A

比如 S-> AbB 那么 FOLLOW(A)中就包含了b 

具体参看龙书虎书


在设计文法的时候要注意的两个问题

二义性和左递归

二义性是指一个字符串有两个语法树结构 比如 1-3+2 理解上可以看作 (1 -3 )+2=0 也可以看作1-(3+2)=-4 .这样的方法需要通过规则来消除。

左递归是指推导时陷入死循环

比如有A->A alpha 那么 产生式体中的A 又可以推出 A->A alpha

导致可以产生 A->A alpha  A->A alpha alpha   A->A alpha alpha alpha .........无限解析。

我认为这是理论上的问题。实际代码中是不能写出这样的代码导致无限循环的,正是因为有二义性所以不能写出来,因为自顶向下是需要通过一个前看符号来决定采用哪个表达式。所以这个前看符号必定是FOLLOW(A)集合的元素。只能理解上写成

void expr()

{

    expr();

    parse_alpha();

}

http://bbs.chinaunix.net/thread-2079882-1-1.html



以下部分转载自 http://www.cnblogs.com/beMaster/p/5071264.html

LL(1)分析法

LL(1)分析法又叫预测分析法,是一种不带回溯的非递归自顶向下的分析法。

LL(1)是不带回溯的非递归的分析法是因为,它每次都只有一个可用的产生式,所以是不带回溯和非递归的,当无法处理输入符号时,即出错。

第一个L表示是从左到右扫描输入串,第二个L表示推导过程中使用最左推导,(1)表明只需要向右看一个符号,就可以决定如何推导的(即知道用哪个产生式进行推导)。

 什么是LL(1)分析法

LL(1)分析法的原理是这样的,它的基本思想是根据输入串的当前输入符号来唯一确定选用哪个产生式来进行推导。

比如当前的文法符号是A,面临输入串的首个符号是a, 存在若干个产生式,AX1|X2|...|XkA→X1|X2|...|Xk,如果aFIRST(Xi)a∈FIRST(Xi),那么肯定就是用AXiA→Xi这个产生式来进行推导。

又或者当前的文法符号是A,面临的输入串的首个符号是a,存在产生式AXA→X,若 ϵFIRST(X)ϵ∈FIRST(X), 且aFOLLOW(A)a∈FOLLOW(A),那么肯定是用产生式A=>ϵA=>ϵ进行推导。即当然文法符号是没用的。

 

所以LL(1)文法要满足下面的条件,若存在AX1|X2A→X1|X2

(1)FIRST(X1)FIRST(X2)=ϕFIRST(X1)⋂FIRST(X2)=ϕ 。即如果对于文法符号A,有两个产生式的FIRSTFIRST交集不为空,那么就是二义的,就不是LL(1)文法

(2)若ϵFIRST(X2),FIRST(X1)FOLLOW(X2)=ϕϵ∈FIRST(X2),则有FIRST(X1)⋂FOLLOW(X2)=ϕ,同样的,这样也是二义的。

 

 对LL(1)文法构造LL(1)分析表

根据上面的思想,我们可以预处理出一张LL(1)分析表,对于任意的文法符号S,面临输入符号a,该用哪个产生式。

首先,处理出非终结符号的FIRSTFOLLOWFIRST集和FOLLOW集合

然后根据3条规则来构造LL(1)分析表(这里默认该文法是LL(1)文法)。

①对文法G[S]G[S]的每个产生式AαA→α执行②,③两步

②对每个终结符aFIRST(α)a∈FIRST(α),把AαA→α加入到表格中的[A,a] 这个格子。即当文法符号A面临输入符号a时,应该使用产生式AαA→α

③若ϵFIRST(α)ϵ∈FIRST(α),则对所有的终结符bFOLLOW(A)b∈FOLLOW(A),将AϵA→ϵ加入到[A,b]这个格子。即当文法符号A面临输入符号b时,文法符号A无法推导出终结符号b,但是它的FOLLOW集包含终结符号b,所以用A=>ϵA=>ϵAA替换掉。从而让AAFOLLOWFOLLOW集来生成终结符号bb

④将所有无定义的[A,a]标记为出错。

 

为什么左递归文法不是LL(1)文法

形如A->Ab|c的文法,就是左递归文法,可以看出FIRST(A)=FIRST(c)FIRST(A)=FIRST(c),所以左递归文法不是LL(1)文法。

即对左递归构造的LL(1)分析表是有二义性的。






猜你喜欢

转载自blog.csdn.net/groundhappy/article/details/79347609