4.1语法分析器的功能:
语法分析是整个编译过程的核心部分,它完成的任务是:按照文法从源程序单词串(符号串)中识别各类语法成分,判断所给出的单词串是否是给定文法的正确句子,并为语义分析和代码生成做准备。
4.2 不确定的自顶向下分析
一、算法思想:
对于任一输入符号串,试用一切可能的办法从树根结点出发根据文法自上向下的为输入串建立一棵语法树。
三、对应最左推导:
以上为输入符号串建立语法树的过程,实际上也是一个建立最左推导序列的过程,显然有:SÞcAdÞcad,之所以使用最左推导,是因为我们对输入串是从左到右扫描的,只有使用最左推导,才能按扫描顺序去匹配输入串。
四、存在问题:
1.左递归问题:自顶向下分析方法,在匹配过程中,假若用到非终结符号U去匹配输入串,而U为左递归的(例如:U®U…),那么为了用它的右部匹配输入串,又要用到非终结符号U,循环往复,没有终止。若文法存在间接递归,也有相同问题发生。
2.回溯问题:对某个非终结符,当有多条规则时,需采用逐个选择的方法,若不能匹配需要回溯,代价高,效率低。
4.3 确定的自顶向下分析思想
一、算法思想:
对于任一输入符号串,从文法的识别符号出发,根据当前的输入符号,唯一的确定一个产生式,用产生式的右部的符号串替代相应的非终结符往下推导,或构造一棵语法树。若能推导出输入串或构造语法树成功则输入串是句子,否则不是。
二、举例:
(1)文法G[S]:
S->pA |qB
A->cAd|a
输入串w=pccadd
文法特点: (1)每个产生式的右部都由终结符号开始;(2)两个产生式若左部相同,则其右部以不同的终结符号开始;(3)无空产生式U->e
(2)文法G[S]:
S->Ap |Bq
A->cA | a
B->dB | b
输入串w=ccap
文法特点: (1)每个产生式的右部并非都由终结符号开始;(2)两个产生式若左部相同,则其右部以不同的终结符号或非终结符号开始,且首符号集不相交;(3)无空产生式U->e
(3)文法G[S]:
S->aA | d
A->bAS |e
输入串w=abd
文法特点: (1)有空产生式U->e;(2)两个产生式若左部相同,则其对应的首符号集不相交并且与其后继符号集也不相交;
例题(1)(2)(3)的共同特点:
1)没有左递归
2)在每一步推导中,都可以根
据输入串的当前符号唯一的确
定一个产生式去匹配。
4.3.2 几个重要集合
一、首符号集:
设有文法G=(VT,VN, S, P)是上下文无关文法,则符号串x的首符号集合定义为:
例如:有如下文法G[E]:
E->E+T| T
T->T*F| F
F->(E) | i 则有:
First(E+T)={(, i}
First(T)={(, i}
First(i*i)={i}
二、后继符号集:
三、FIRST集及FOLLOW集的构造
1.构造文法符号X的FIRST集:
(2)X∈VN,且有X->a…, 则a 加入FIRST(X);
若有X->ε,则ε加入FIRST(X);
(3)若有X->Y…,且Y∈VN ,则FIRST(Y)中非ε元素
全部加入FIRST(X);
若有X->Y1Y2Y3…YK,且Yi∈VN ,ε∈FIRST(Yj)
则FIRST(Yi)中非ε元素加入FIRST(X);
若ε∈FIRST(Xj),1≤j≤k,则ε加入FIRST(X)
2.构造符号串α的FIRST集: (α=X1X2…XN)
(1)首先FIRST(α)= FIRST(X1)\{ε};
(2) 若ε∈FIRST(Xj),则FIRST(Xi)\{ε}加入FIRST(α);
(3) 若ε∈FIRST(Xj),则ε加入FIRST(α);
例:设有文法G[E]:
E→TE’ E’→+TE’|ε T→FT’ T’→*FT’|ε F→(E)|i
求非终结符号的First集:
First(E)={(,i}
First(E’)={+,ε}
First(T)={(,i}
First(T’)={*,ε}
First(F)={(,i} First(E'T')={+,*,ε}
3.构造非终结符X的FOLLOW集
(1)对文法开始符号S, #加入FOLLOW(S);
(2)若有A->αBβ,则FIRST(β)\{ε}加入FOLLOW(B);
(3)若有A->αB, 或A->αBβ且ε∈ FIRST(β),则
FOLLOW(A)加入FOLLOW(B);
LL(1)文法:
如果一个文法满足以下条件:
1、文法不含左递归。
2、对文法中每一个非终结符A的各个产生式的候选首
符集两两不相交。
3、对文法中每一个非终结符A,若存在某个候选首
符集包含e,则
First(A)^ Follow(A)=F(空)
LL(1)中第一个L表明自左(Left)向右扫描输入串,第二个
L表明分析过程采用最左(Left)推导,括号中的1表明只需向右
看一个符号便可决定选择哪个产生式进行推导。
4.3.1非LL(1)文法转换为LL(1)文法
对某个语言来说其文法不一定是LL(1)文法,而非LL(1)文法将无法采用确定的自顶向下分析方法进行分析,但我们可以通过对文法进行等价变换,在有些情况下使其成为LL(1)文法。
一、提取左公共因子:
1.方法:若有产生式U->xy|xw|…|xz,则提取左公共因子并用EBNF表示为: U->x(y|w|…|z)
再引入另一个非终结符号V,将产生式变为:
U->xV
V->y|w|…|z
若在y,w,…,z中仍然有左公共因子,可以再次提取。注意,若有:U->xy|x,则提取后:U->x(y|e)
2.举例:
设有产生式:S→if B then S1 else S2 |if B then S1
其中,S表示两种类型的条件语句。
提取公因子,改成:S→if B then S1 ( else S2 | e)
引入非终结符号R:
S→if B then S1 R
R→else S2 |ε
文法中,if, then, else<(属于)VT
3.说明:
文法提取左公共因子后,只能使相同左部的产生式右部的First集不相交。
文法提取左公共因子后,若文法中无空产生式,且无左递归,则改写后的文法为LL(1)文法。
有些文法,不能在有限步骤内改写为无左公共因子的文法。
二、消除左递归:
左递归文法的分析程序可能进入死循环,可以证明,左递归文法不可能是LL(1)文法。
1.消除直接左递归:若有产生式U->x|y|…|z|Uv, U<VN, x,y,z,v<V*, 则改写并用EBNF表示为:
2.消除间接左递归:先将间接左递归变为直接左递归,再按消除直接左递归的方法进行。
举例:有文法G[S]:
S→Qc|c
Q→Rb|b
R→Sa|a
该文法无直接左递归,但,S=>Qc=>Rbc=>Sabc,故有间接左递归,所以文法G[S]为左递归文法。
(1)对非终结符号排序:R, Q, S
注意:对非终结符号的排序是任意的(但要保证开始符号不变),不同的排序最后所得文法得形式可能不同,但它们是等价的。
4.4 确定的自顶向下分析方法举例
一、递归子程序法
递归子程序法是比较简单直观易于构造的一种语法分析方法,其方法思想是对源程序中每个语法成分编制一个处理子程序,即对 每个非终结符号编制一个递归过程,每个子程序的功能是识别由该非终结符号推出的串 。它要求文法满足 LL(1) 文法,以便当某个非终结符号有多条产生式时,可以根据当前的输入符号唯一地确定选择某个产生式进行匹配。
文法G[E] :
E→TE’
E’→+TE’|ε
T→FT’
T’→*FT’|ε
F→(E)|i
Progrom E;
Begin
T
While sym=“+” do
Begin advance; T end
End
Progrom T;
Begin
F
While sym=“*” do
Begin advance; F end
End
Progrom F;
If sym= “i” then advance
else If sym= “(” then
Begin advance; E
If sym= “)” then advance
else error
End
else error
4.5 预测分析程序——LL(1)分析器:
预测分析程序也是一种自顶向下分析程序,预测分析要求文法是LL(1)文法,它由分析栈、分析表和分析程序三部分组成,其中分析表的构成与文法有关。下面举例说明分析器的构造过程:
设有文法G[E]:
E→E+T|T
T→T*F|F
F→(E)|i
1.判断是否LL(1)文法
(1)消除左递归:
E→TE’
E'→+TE’|ε
T→FT’
T'→*FT’|ε
F→(E)|i
(2)找出能推出ε的非终结符号:
E’, T’
(3)求非终结符号每一候选式的First集:
First(TE')={(,i} First(+TE')={+} First(ε)={ε} First(FT')={(,i}
First(*FT)={*} First(ε)={ε} First((E))={(} First(i)={i}
(4)求(含ε产生式)非终结符号的Follow集:
Follow(E)={),#}
Follow(E')={),#}
Follow(T)={+,),#}
Follow(T')={+,),#}
Follow(F)={*,+,),#}
文法是LL(1)文法。
2.构造预测分析表
定义:预测分析表与文法有关,它说明当某个非终结符号U向下推导时,面临输入符号a时,所应选用的产生式。
(2)表示:预测分析表可用一矩阵M表示,矩阵的行表示非终结符号,矩阵的列表示输入符号或#,矩阵的元素M[U,a]表示对非终结符号U ,当面临输入符号a时,它向下推导所应采取的产生式。
(3)构造方法:
例,对于上例中的文法G[E],预测分析表为:
当元素内无产生式时,表明用非终结符号U向下推导时,遇到了不该出现的输入符号。所以元素内容可以存放转向出错处理的错误信息.
举例:分析输入串i+i是否为文法G[E](上例)的句子。
首先为输入串i+i加上括号,即被分析的串变为#i+i#,分析过程如下:
4.1考虑下面文法G1:S-〉a | ∧ | (T)
T-〉T,S | S
1)消去G1的左递归
消除左递归:S-〉a| ∧ | (T)
T-〉ST’
T’-〉,S T’ |ε
a、由(1)知,改写后的文法不含左递归;
b、下面分别对各非终结符的候选求FIRST集:
FTRST(a)={a} FIRST(∧)={∧}
FIRST((T))={( }
FIRST(,ST’)={,} FIRST(ε)={ε}
对非终结符S有:FTRST(a)∩FIRST(∧)∩FIRST((T))=Φ
对非终结符T’有:FIRST(,ST’) ∩ FIRST(ε)=Φ
c、FIRST(S)={a,∧,(} FOLLOW(S)={#,,,)}
FIRST(T)={a,∧,(} FOLLOW(T)={ )}
FIRST(T’)={,,ε} FOLLOW(T’)={ )}
故: FIRST(T’)∩FOLLOW(T’)=Φ
综合以上的分析,经改写后的文法是LL(1)文法
其预测分析表为:
有文法:E->TE’
E’->ATE’|ε
T->FT’
T’->MFT’|ε
F->(E)|i
A->+ | -
M->* | /
1)、求First、Follow集,判断是否是LL(1)文法?
2)、若是构造LL(1)分析表?
3)、简述LL(1)分析器的工作原理。
解:1)、文法中各非终结符的First集和Follow集
2)、LL(1)分析表
3)、对i+i*i进行预测分析的过程表