基本方法:对任何输入串,试图从文法的开始符号出发, 自上而下地为输入串建立一棵语法树,或者说为输入串寻找一个最左推导。
过程本质:是一种试探过程,是反复使用不同产生式谋求匹配输入串的过程如何选择哪个产生式进行推导,某文法符号对应当前输入符号时,有唯一的产生式进行替换并向下推导。
设G=(V_T,V_N,S,P) α∈V*
FIRST(α)=\{a|α\overset\Rightarrow aβ,a∈VT\},若α\overset\Rightarrow ε,则 ε∈FIRST(α)
FIRST(α) 是 α 的所有可能推导的首遇终结符号或 ε,是选择产生式的依据。
S → Ap|Bq A → cA|a B →dB|b
FIRST(Ap) ={ a,c },Ap\Rightarrow ap Ap\Rightarrow cAp
FIRST(Bq) ={ b,d},Bq \Rightarrow bq Bq\Rightarrow dBq
因为 S 的两个候选式 FIRST(Ap)∩ FIRST(Bq)=φ,所以当 S 与面临的输入符号 i 匹配时,可能出现几种选择?
A∈V_N,FOLLOW(A)={ a|S\overset*\Rightarrow…Aa…,a∈V_T },若S\overset *\Rightarrow…A,则\#∈FOLLOW(A)
#(有些书上用$):输入串的结束符,也可看作是句子的括号 #S#。
FOLLOW(A)表示了句型中可能紧跟在A后面的终结符号。
S → aA|d A → bAS|ε
S\Rightarrow aA,\#\in FOLLOW(A)
S\Rightarrow aA \Rightarrow abAS \Rightarrow abAaA,a \in FOLLOW(A)
S \Rightarrow aA \Rightarrow abAS \Rightarrow abAd, d \in FOLLOW(A)
因为 A 的两个候选式FIRST(bAS)∩FOLLOW(A)=φ,所以当A与面临的输入符号 i 匹配时,可能出现几种选择?
设G=(V_T,V_N,S,P) α∈V^* ,FIRST(α)=\{a|α\overset *\Rightarrow aβ,a∈V_T\}
若\alpha \overset*\nRightarrow \epsilon,则SELECT(A→α)= FIRST(α)
若\alpha \overset*\Rightarrow \epsilon,则SELECT(A \rightarrow\alpha) = (FIRST(\alpha)-\{\epsilon\}) \cup FOLLOW(A),这里的意思是,如果 \alpha 能推出 \epsilon ,则 A 后面紧跟着的终结符也可以由 A\rightarrow\alpha 产生,或者 \alpha 前的终结符也可以由 A\rightarrow \alpha 产生。
SELECT集合不允许有空串。即非终结符 A 面临某个输入符号时,选择产生式的依据。
S → aA|d A → bAS|ε
FOLLOW(A)=\{a,d,\#\}
SELECT(A →bAS)=FIRST(bAS)=\{b\}
SELECT(A →ε)=(FIRST(ε)-ε) ∪FOLLOW(A)=\{a,d,\#\}
S → aA|d A → bAS|K K → c|ε
FOLLOW(A)=\{a,d,\#\} FIRST(K)=\{c, ε\}
SELECT(A →bAS)=FIRST(bAS)=\{b\}
SELECT(A →K)=(FIRST(K)-ε) ∪FOLLOW(A)=\{c,a,d,\#\}
一个上下文无关文法是 LL(1) 文法的充分必要条件是,对每个非终结符的两个不同的产生式,A→α,A→β,满足:SELECT(A→α)∩SELECT(A→β)= φ
S → aA|d A → bAS|ε
求所有SELECT集合:
SELECT(S→aA)=FIRST(aA)=\{a\}
SELECT(S →d)=FIRST(d)=\{d\}
SELECT(A →bAS)=FIRST(bAS)=\{b\}
SELECT(A →ε)
n =(FIRST(ε)-ε) ∪FOLLOW(A)=\{a,d,\#\}
求每个非终结符不同产生式SELECT的交集:
SELECT(S→aA)∩SELECT(S →d)=φ
SELECT(A →bAS)∩SELECT(A →ε)=φ
所以,该文法是LL(1)文法。
含义:第一个 L 表示从左向右扫描输入符号串;第二个 L 表示生成最左推导;1 表示读入一个符号可确定下一步推导。
LL(1)文法能够对输入串进行有效的、无回溯的自上而下分析。
规则:
对于文法G,当面临的输入符号为a,要用非终结符A进行匹配时,假设 A 的所有产生式为 A→α_1| α_2 |…| α_n
其实上述的规则就是 SELECT 集合的定义,所以其实就是看输入符号属于哪个 SELECT 集,就选择相对应的产生式。
一个上下文无关文法是 LL(1) 文法的充分必要条件是,对每个非终结符的两个不同的产生式,A→α,A→β,满足:SELECT(A→α)∩SELECT(A→β)= φ
重复以下计算,直到FIRST(X)不再增大为止:
文法G为:
S →Ap|Bq A →a|cA B →dB|ε
FIRST(A) = \{a,c\}
FIRST(B) = \{d,ε\}
FIRST(S) = FIRST(A) – \{ε\} \cup FIRST(B) – \{ε\} \cup FIRST(q) = \{a,c,d,q\}
加入 FIRST(q) 是因为 B\rightarrow ε

反复重复步骤,直到集合不再增大。
问:如果S不能推导得到A呢?
G:
E→TE’
E’→+TE’|ε
T→FT’
T’→*FT’|ε
F→(E)|i
\# \in FOLLOW(E)
对每个非终结符查看其在产生式右边的出现:(注意!!!)
FOLLOW(E) = \set {),\#}
FOLLOW(E’) = FOLLOW(E) = \set {),\#}(步骤三)
FOLLOW(T) = FIRST(E’) – \setε ∪FOLLOW(E)(步骤二+步骤三)
FOLLOW(T’)=FOLLOW(T)=\{+,),\#\}
FOLLOW(F)=FIRST(T’)-\{ε\}∪FOLLOW(T)=\{*,+,),\#\}

不确定性导致回溯的原因:
对于所有形如 A→αβ1|αβ2|…|αβn|γ的规则,其中,α为左因子,γ不以α开头,改写为:
A→αA’|γ 其中A’为新增加的非终结符A’→β1|β2|…|βn
例如:
S → xAy A → ab|a
提左因子后变换为:
S → xAy
A → aA’
A’ → b|ε
注意事项:
直接左递归定义:若P → Pα|β,且α、β ∈V*
改写为等价的右递归,形如:P → Pα|β ,α非ε,β不以P开始。
改写为:P→βP’(P’为新增加的非终结符)P’→αP’|ε
改写前产生式可产生短语 :P\Rightarrow Pα\Rightarrow βα
改写后产生式可产生短语:P\Rightarrow βP’ \Rightarrow βαP’ \Rightarrow βα
若有多个左递归的产生式如:P→Pα_1| Pα_2 |…| Pα_m |β_1| β_2 |…|β_n
消除左递归后变为:
P→β_1P’ |β_2 P’|…|β_nP’
P’ → α_1P’ | α_2 P’|…| α_mP’| ε
消除左递归要求文法:
1.无回路(A \overset * \Rightarrow A)
2.无空产生式(A → ε)
间接左递归定义: 若P\overset + \Rightarrow Pα \ \ \ \ \ α∈V^*
例如:
S → Aa A → Sb|b
S \Rightarrow Aa \Rightarrow Sba ,即S\overset+\Rightarrow Sb
用 S 的产生式右部替换 A 右部的 S 得:A → Aab|b,变成A的产生式含有直接左递归。
用LL(1)文法构造不带回溯的自上而下的分析程序,一个分析程序对应一组递归过程,每个非终结符对应一个子递归。子过程的功能:
对相应非终结符产生式右部进行语法分析。分析程序从开始符号所对应的过程开始运行。
举例:
消除左递归后的表达式文法G为:
E →TE’
E’→+TE’|ε
T →FT’
T’→*FT’|ε
F →(E)|i
可以证明,G是一个LL(1)文法。
从开始符号 E 开始对其右部进行分析:
E(){
//由于E右部为非终结符,所有非终结符对应一个子递归。
T; //递归进入另外一个函数
E';//递归进入另外一个函数
}对E’ 进行分析:
E’(){
if (c==‘+’)//c:当前所面临的输入符号
{
p++;//把输入指针p下移一位
T;
E’;
}
//其它 非+字符 自动匹配ε
}对 T 进行构造:
T(){
F;
T';
}对T’ 进行构造:
T'{
if(c == '*'){
p++;
F;
T';
}
}对 F: F →(E)|i进行构造:
F{
if(c == '(') {
p++;
E;
if(c == ')')p++;
else Error;//注意这里如果不是')' 则无法匹配,发生错误。
}else if(c == 'i') p++;
else Error//F面临非'('和'i'时,无法匹配。
}优点:
缺点:
1) 递归算法的实现效率低
2) 处理能力相对有限(LL(1))
实现LL(1)分析的另一种有效方法,称为预测分析法,使用一张二维分析表(预测分析表)和一个分析栈(文法符号栈)联合进行控制来实现自上而下分析技术。
预测分析表实际上是一个矩阵M[A,a],其有两种取值,如果当A面临a时存在可选用的候选式,则为该产生式,否则为空值(表示A面临a时无法匹配,出现语法错误),例如下图所示:

分析栈用于存放分析过程中的文法符号,分析栈初始化时:栈底压入一个‘#’,再压入开始符 S。预测分析器模型如下图所示,总控制程序从输入缓冲区得到输入符号,与栈顶符号一起在预测分析表中查找选用的产生式序列,并根据不同情况修改栈,最终得到一个产生式序列:

总控程序执行时可能动作:
对于任何(X,a) ,X是栈顶符号 a 是面临输入符号,则:
下面给出输入串w=i*i+i的预测分析过程:
栈 输入缓冲区 所用产生式
0 #E i+i*i# E → TE'
1 #E'T i+i*i# T → FT'
2 #E'T'F i+i*i# F → i
3 #E'T'i i+i*i# i出栈,a下移
4 #E'T' +i*i# T' → ε
5 #E' +i*i# E' → +TE'
6 #E'T+ +i*i# +出栈,a下移
7 #E'T i*i# T → FT'
8 #E'T'F i*i# F → i
9 #E'T'i i*i# i出栈,a下移
10 #E'T' *i# T' → *FT'
11 #E‘T'F* *i# *出栈,a下移
12 #E'T'F i# F → i
13 #E'T'i i# i出栈,a下移
14 #E'T' # T' → ε
15 #E' # E' → ε
16 # # 分析成功结束设有文法G,预测分析表构造过程:
计算所有候选式α的首符集:FIRST(α)
计算所有非终结符A的后继符集:FOLLOW(A)
计算所有产生式的 SELECT(A→α) 集合,构造预测分析表 M
预测分析表的构造算法:
(1)对文法G的每个产生式 A→α,执行(2)
(2)对每个终结符或“#”记为a,若a∈SELECT(A→α),把 A→α 填入 M[A,a]
(3)把所有无定义的 M[A,a]标上“出错标志”
1) 编写文法,消除二义性;
2) 消除左递归、提取左因子;
3) 求 FIRST 集合、 FOLLOW 集合和SELECT集合