语法分析-自上而下分析
基本思想
它从文法的开始符号出发,反复使用各种产生式,寻找"匹配"的推导。
主旨: 从文法开始符号出发,自上而下地为输入串建立一颗语法树,或者为输入串寻找一个最左推导。
回溯与左递归
当某个非终结符有多个产生式候选时,可能带来如下问题:
回溯: 分析过程中,当一个非终结符用某一个候选匹配成功时,这种匹配可能是暂时的。出错时,不得不“回溯”。
左递归: 如果存在非终结符P
含有左递归的文法将使自上而下的分析陷入无限循环。
LL(1)文法
构建不带回溯的自上而下分析算法
消除文法的左递归性
- 直接左递归的小消除
假定关于非终结符P的规则为
P→P α \alpha α | β \beta β,其中 β \beta β不以P开头。
我们可以把P的规则等价地改写为如下的非直接左递归形式:
P→ β \beta βP’
P’→ α \alpha αP’| ε \varepsilon ε
一般而言,假定P关于的全部产生式是
P→P α \alpha α1 | P α \alpha α2 | … | P α \alpha α m| β \beta β1 | β \beta β2|…| β \beta βn
其中,每个 α \alpha α都不等于 ε \varepsilon ε,每个 β \beta β都不以P开头
那么,消除P的直接左递归性就是把这些规则改写成:
P→ β \beta β1P’ | β \beta β2P’ | … | β \beta βnP’
P’→ α \alpha α1P’ | α \alpha α2P’|… | α \alpha αmP’ | ε \varepsilon ε
一个文法消除左递归的条件:
不含以
ε
\varepsilon
ε为右部的产生式
不含回路。
- 消除左递归的算法
1.把文法G的所有非终结符按任一种顺序排列成P1,P2,…,Pn;按此顺序执行;
2.FOR i:=1 TO n DO
BEGIN
FOR j:=1 TO i-1 DO
把形如Pi→Pj γ \gamma γ的规则改写成
Pi→ δ \delta δ1 δ \delta δ| δ \delta δ2 δ \delta δ|…| δ \delta δk γ \gamma γ ;
(其中Pj→ δ \delta δ1| δ \delta δ2|…| δ \delta δk是关于Pj的所有规则)
消除关于Pi规则的直接左递归性
END
3.化简由2所得的文法。去除那些从开始符号出发永远无法到达的非终结符的产生规则。
克服回溯
产生回溯的原因: 推导时,若产生式存在多个候选式,选择哪个进行推导存在不确定性。
对文法的任何非终结符,当要它去匹配输入串时,能够根据它所面临的输入符号准确地指派它的一个候选去执行任务,并且此候选的工作结果应是确信无疑的。
1. FRIST集
令G是一个不含左递归的文法,对G的所有非终结符的每个候选
α
\alpha
α定义它的终结首符集FIRST(
α
\alpha
α)为:
若 ,则规定
ε
\varepsilon
ε
∈
\in
∈FIRST(
α
\alpha
α)。
如果非终结符A的所有候选首符集两两不相交,即A的任何两个不同候选
α
\alpha
αi和
α
\alpha
αj
FIRST(
α
\alpha
αi)∩FIRST(
α
\alpha
αj)=
Φ
\Phi
Φ
当要求A匹配输入串时,A就能根据它所面临的第一个输入符号a,准确地指派某一个候选前去执行任务。这个候选就是那个终结首符集含a的
α
\alpha
α。
2. 提取公共左因子
假定关于A的规则是
A→
δ
\delta
δ
β
\beta
β1 |
δ
\delta
δ
β
\beta
β2 | …|
δ
\delta
δ
β
\beta
βn|
γ
\gamma
γ1 |
γ
\gamma
γ2 | … |
γ
\gamma
γm (其中,每个
γ
\gamma
γ不以
δ
\delta
δ开头)
那么,可以把这些规则改写成
A→
δ
\delta
δA’ |
γ
\gamma
γ1 |
γ
\gamma
γ2 | … |
γ
\gamma
γm
A’→
β
\beta
β1 |
β
\beta
β2 | … |
β
\beta
βn
经过反复提取左因子,就能够把每个非终结符(包括新引进者)的所有候选首符集变成为两两不相交。
3. FOLLOW集
假定S是文法G的开始符号,对于G的任何非终结符A,我们定义
特别是,若 ,则规定#
∈
\in
∈FOLLOW(A)
4. 构造不带回溯的自上而下分析的文法条件
- 文法不含左递归,
- 对于文法中每一个非终结符A的各个产生式的候选首符集两两不相交。即,若
A→ α \alpha α1| α \alpha α2|…| α \alpha αn
则 FIRST( α \alpha αi)∩FIRST( α \alpha αj)= Φ \Phi Φ (i ≠ \not= =j) - 对文法中的每个非终结符A,若它存在某个候选首符集包含
ε
\varepsilon
ε,则
FIRST( α \alpha αi)∩FOLLOW(A)= Φ \Phi Φ i=1,2,…,n
如果一个文法G满足以上条件,则称该文法G为LL(1)文法。
5. 构造FIRST( α \alpha α)
对每一文法符号X
∈
\in
∈VT∪VN构造FIRST(X)
连续使用下面的规则,直至每个集合FIRST不再增大为止:
- 若X ∈ \in ∈VT,则FIRST(X)={X}。
- 若X ∈ \in ∈VN,且有产生式X→a…,则把a加入到FIRST(X)中;若X→ ε \varepsilon ε也是一条产生式,则把 ε \varepsilon ε也加到FIRST(X)中。
- 若X→Y…是一个产生式且Y
∈
\in
∈VN,则把FIRST(Y)中的所有非
ε
\varepsilon
ε元素都加到FIRST(X)中;
若X→Y1Y2…Yk是一个产生式,Y1,…,Yi-1都是非终结符,而且,对于任何j,1 ≤ \leq ≤j ≤ \leq ≤i-1,FIRST(Yj)都含有 ε \varepsilon ε,则把FIRST(Yi)中的所有非 ε \varepsilon ε-元素都加到FIRST(X)中;特别是,若所有的FIRST(Yj)均含有 ε \varepsilon ε,j=1,2,…,k,则把 ε \varepsilon ε加到FIRST(X)中。
6. 构造FOLLOW(A)
对于文法G的每个非终结符A构造FOLLOW(A)的办法是,连续使用下面的规则,直至每个FOLLOW不再增大为止:
- 对于文法的开始符号S,置 # 于FOLLOW(S)中;
- 若A→ α \alpha αB β \beta β是一个产生式,则把FIRST( β \beta β)\{ ε \varepsilon ε}加至FOLLOW(B)中;
- 若A → \rightarrow → α \alpha αB是一个产生式,或A → \rightarrow → α \alpha αB β \beta β是一个产生式而(即 ε \varepsilon εFIRST( β \beta β)),则把FOLLOW(A)加至FOLLOW(B)中。
示例
预测分析程序
分析表M[A,a]的构造
一个文法G地预测分析表不含多重定义出口,当且仅当该文法为LL(1)文法。
1.构造FIRST( α \alpha α),构造FOLLOW(A)
2.构造分析表M[A,a]
- 对文法G的每个产生式A→ α \alpha α执行第2步和第3步;
- 对每个终结符a ∈ \in ∈FIRST( α \alpha α),把A→ α \alpha α加至M[A,a]中;
- 若 ε \varepsilon ε ∈ \in ∈FIRST( α \alpha α),则对任何b ∈ \in ∈FOLLOW(A)把A→ α \alpha α加至M[A,b]中。
- 把所有无定义的M[A,a]标上“出错标志”。
总控程序