语法分析
元素
- LL(1)分析
- First 集合
- Follow 集合
- 文法 G = ( V N , V T , P , S ) G=(V_N, V_T, P, S) G=(VN,VT,P,S),其中 V N V_N VN是非终结符, V T V_T VT是终结符, P P P是产生式, S S S是起始符号
- 产生式的后缀 u u u(自取,表示产生式箭头后的部分)
- 预测集合 P S ( A → α ) PS(A\rightarrow \alpha) PS(A→α),其中 A → α A\rightarrow \alpha A→α是一个产生式
- 预测分析表 M M M
- 下推栈和余留字符串
- 递归下降LL(1)分析程序
- 左递归的文法(直接左递归,间接左递归)
- 无回路的文法
- 左公因子
符号表示
-
S
S
S为一个字符集合,那么
S
∗
S^*
S∗表示这个集合中的所能组合成的所有句子,包括
ε
\varepsilon
ε
例子:{“ab”, “c”}* = {ε, “ab”, “c”, “abab”, “abc”, “cab”, “cc”, “ababab”, “ababc”, “abcab”, “abcc”, “cabab”, “cabc”, “ccab”, “ccc”, …}
关系
-
给定一个文法 G G G和一个集合 X G X_G XG,其中 X G ⊂ { V N ∪ V T } ∗ X_G \subset \{V_N \cup V_T\}^* XG⊂{VN∪VT}∗,求这个集合 X G X_G XG的first集合
- 先求
{
V
N
∪
V
T
}
\{V_N \cup V_T\}
{VN∪VT}的first集合
-
对于 G G G中的任何一个终结符 a a a, f i r s t ( a ) = { a } first(a)=\{a\} first(a)={a},包括 f i r s t ( ε ) = { ε } first(\varepsilon)=\{\varepsilon\} first(ε)={ε};对于 G G G中任何一个非终结符 A A A, f i r s t ( A ) = ∅ first(A)=\varnothing first(A)=∅
-
求 G G G的所有产生式的后缀 u u u的first集合
举例,如产生式后缀 D a B DaB DaB,假设 f i r s t ( D ) = d , ε first(D)={d, \varepsilon} first(D)=d,ε, f i r s t ( B ) = b first(B)={b} first(B)=b- 对于任意一个 u u u, f i r s t ( u ) = ∅ first(u)=\varnothing first(u)=∅
- 遍历 u u u的所有字符
- 如果遇到的是一个非终结符
A
A
A,
- 那么遍历它的first集合,将其终结符加入 f i r s t ( u ) first(u) first(u)中(包括 v a r e p s i l o n varepsilon varepsilon)
- 如果 ε ∈ f i r s t ( A ) \varepsilon \in first(A) ε∈first(A),那么继续查看下一个字符
- 否则将 f i r s t ( u ) first(u) first(u)中的 v a r e p s i l o n varepsilon varepsilon删掉,直接退出
- 如果遇到的是一个终结符
a
a
a
- 将 a a a加入 f i r s t ( u ) first(u) first(u),将 f i r s t ( u ) first(u) first(u)中的 v a r e p s i l o n varepsilon varepsilon删掉,退出
以 D a B DaB DaB为例, D D D的所有终结符 d d d加入 f i r s t ( u ) first(u) first(u), D D D有 ε \varepsilon ε元素,那么查看下一个,下一个是终结符 a a a,将 a a a加入 f i r s t ( u ) first(u) first(u),退出,所以 f i r s t ( u ) = { d , a } first(u)=\{d,a\} first(u)={d,a}
-
将 G G G的所有产生式的后缀 u u u的first集合赋给其对应的非终结符
-
回到2,进行循环,直到集合中所有 u u u的first集合相对于上一轮都不再变动
-
- X G X_G XG中字符串的first集合可以以1.1.2中的方法计算出来,所有的字符串的集合累积到一起就是 X G X_G XG的first集合
- 先求
{
V
N
∪
V
T
}
\{V_N \cup V_T\}
{VN∪VT}的first集合
-
给定一个文法 G G G,对所有属于 V N V_N VN的非终结符 A A A,求 F o l l o w ( A ) Follow(A) Follow(A)
-
给定一个文法 G G G和其中的一个产生式 A → α A\rightarrow \alpha A→α求这个产生式的预测集合
- 如果 ε ∉ F i r s t ( α ) \varepsilon \notin First(\alpha) ε∈/First(α),那么 P S ( A → α ) = F i r s t ( α ) PS(A\rightarrow \alpha)=First(\alpha) PS(A→α)=First(α)
- 如果 ε ∈ F i r s t ( α ) \varepsilon \in First(\alpha) ε∈First(α),那么 P S ( A → α ) = ( F i r s t ( α ) − { ε } ) ∪ F o l l o w ( A ) PS(A\rightarrow \alpha) = (First(\alpha)-\{\varepsilon \})\cup Follow(A) PS(A→α)=(First(α)−{ε})∪Follow(A)
-
给定一个文法 G G G,判断该文法是否是LL(1)的
文法 G G G是LL(1)的,当且仅当对于 G G G中任何两个相同左部的不同产生式 A → α A\rightarrow \alpha A→α和 A → β A\rightarrow \beta A→β,都满足 P S ( A → α ) ∩ P S ( A → β ) = ∅ PS(A\rightarrow \alpha)\cap PS(A\rightarrow \beta)=\varnothing PS(A→α)∩PS(A→β)=∅ -
给定一个文法 G = ( V N , V T , P , S ) G=(V_N,V_T,P,S) G=(VN,VT,P,S),求它的预测分析表 M M M
- 搭建表的框架,表的每一行都对应
G
G
G的一个非终结符,表的每一列对应
G
G
G的所有终结符加上#符号
- 往表内填写内容,检查文法的每一个产生式 A → α A\rightarrow \alpha A→α,若它的预测集合 P S ( A → α ) PS(A\rightarrow \alpha) PS(A→α)中包含 a ∈ V T ∪ { # } a\in V_T\cup \{\#\} a∈VT∪{#},则将 A → α A\rightarrow \alpha A→α加入 M [ A , a ] M[A, a] M[A,a](即表 M M M中 A A A, a a a对应的位置)
- 搭建表的框架,表的每一行都对应
G
G
G的一个非终结符,表的每一列对应
G
G
G的所有终结符加上#符号
-
给定一个文法 G G G与它的预测分析表,求它的LL(1)分析过程
- 创建两个栈:下推栈和余留字符串,并将#号分别推入两个栈中
- 将初始符号 S S S推入下推栈,将输入的符号串推入余留字符串(注:右边的字符先入栈)
- 检查下推栈栈顶
- 如果栈顶是终结符,那么比对下推栈和余留字符串的栈顶是否匹配,若匹配就将两个栈顶都弹出,不匹配就进行错误处理。
- 如果栈顶是非终结符,则以该非终结符和余留字符串的栈顶作为坐标到预测分析表中查找,如果对应位置是一个产生式,那么将下推栈栈顶出栈,并将该产生式的后缀入栈(注:右边的字符先入栈);如果对应位置为空,那么报错
- 回到3进行循环,直到两栈栈顶同时为#,分析结束
-
给定一个文法 G G G,写出它的递归下降LL(1)分析程序
- 先求出 G G G中所有非终结符的预测集合
- 对于
G
G
G中的每一个非终结符
A
A
A,
- 找到 A A A的产生式集合 A → u 1 ∣ u 2 ∣ . . . ∣ u n A\rightarrow u_1|u_2|...|u_n A→u1∣u2∣...∣un
- 写出它的一个函数
void ParseA()
,其结构为void ParseA(){ switch (lookahead){ case PS(A->u1): ... break; case PS(A->u2): ... break; ... case PS(A->un): ... break; default: printf("syntax error\n"); exit(0); } } // 这里lookahead是一个全局变量,存放扫描的终结符
- 对于每一个case,遍历其产生式后缀从左到右的符号
- 如果是一个终结符
a
a
a,那么写上一句
MatchToken(a);
- 如果是一个非终结符
A
A
A,那么写上一句
ParseA();
- 如果是一个终结符
a
a
a,那么写上一句
- 给出
MatchToken
的逻辑void MatchToken(int expected){ if (lookahead != expected){ printf("syntax error\n"); exit(0); } else lookahead = getToken(); }
-
给定一个含有直接左递归的产生式,将其消除左递归
假设这个产生式为
P → P α 1 ∣ P α 2 ∣ . . . ∣ P α m ∣ β 1 ∣ β 2 ∣ . . . ∣ β n P\rightarrow P\alpha_1|P\alpha2|...|P\alpha_m|\beta_1|\beta_2|...|\beta_n P→Pα1∣Pα2∣...∣Pαm∣β1∣β2∣...∣βn
其中 α i ≠ ε \alpha_i\neq \varepsilon αi=ε, β j \beta_j βj不以 P P P开头- 增加一个非终结符 Q Q Q
- 将产生式改为
P → β 1 Q ∣ β 2 Q ∣ . . . ∣ β n Q Q → α 1 Q ∣ α 2 Q ∣ . . . ∣ α m Q ∣ ε \begin{align*} &P\rightarrow \beta_1Q|\beta_2Q|...|\beta_nQ\\ &Q\rightarrow \alpha_1Q|\alpha_2Q|...|\alpha_mQ|\varepsilon \end{align*} P→β1Q∣β2Q∣...∣βnQQ→α1Q∣α2Q∣...∣αmQ∣ε
-
给定一个无回路,无 ε \varepsilon ε产生式的文法,将其消除左递归(包括两种左递归)
(一般题目给定的应该就是无回路也无 ε \varepsilon ε产生式的文法)- 以某种顺序(随便的顺序)将文法非终结符排列成 A 1 , A 2 , . . . A n A_1, A_2,...A_n A1,A2,...An
- 进行消除
- 化简从2中得到的产生式集
-
给定一个产生式,提取其左公因子
假设该产生式为
P → α β 1 ∣ α β 2 ∣ . . . ∣ α β m ∣ γ 1 ∣ γ 2 ∣ . . . ∣ γ n P\rightarrow \alpha \beta_1|\alpha \beta_2|...|\alpha \beta_m|\gamma_1|\gamma_2|...|\gamma_n P→αβ1∣αβ2∣...∣αβm∣γ1∣γ2∣...∣γn- 增加一个非终结符 Q Q Q
- 改写产生式为
P → α Q ∣ γ 1 ∣ γ 2 ∣ . . . ∣ γ n Q → β 1 ∣ β 2 ∣ . . . ∣ β m \begin{align*} &P\rightarrow \alpha Q|\gamma_1|\gamma_2|...|\gamma_n\\ &Q\rightarrow \beta_1|\beta_2|...|\beta_m \end{align*} P→αQ∣γ1∣γ2∣...∣γnQ→β1∣β2∣...∣βm