- 消除左递归
- 消除回溯
- FIRST集合
列写文法的FIRST集合 - FOLLOW集合
列写文法的FOLLOW集合 - LL(1)文法
判断是否是LL(1)文法 - LL(1)分析法
根据FIRST集合写LL(1)分析树
写分析子程序
写预测分析表
4.1 语法分析器的功能
任务:在词法分析器识别出单词符号串的基础上,分析并判定语法结构是否符合语法规则
- 自上而下分析法
归约,算符优先算法,LR分析法 - 自下而上分析法
推导(第5章内容)
4.2 自上而下分析面临的问题
自上而下分析:
对任何输入串,试图用一切可能的办法,从文法开始符号(根结)出发,自上而下地为输入串建立一棵语法树
⋆
\star
⋆ 实质上是一种不断试错的过程
- 回溯
当新发展的子树无法满足字符串时,需要退掉子树,看是否还有其他候选 - 左递归
类似 P ⇒ + P α P\xRightarrow{+}P\alpha P+Pα的结构将使得分析陷入死循环
简单说,当 P P P的其他子树无法满足字符串时,则 P P P会选择 P ⇒ + P α P\xRightarrow{+}P\alpha P+Pα子树,但该子树的开头仍是 P P P,问题得不到根本解决,于是下一个 P P P又选择 P ⇒ + P α P\xRightarrow{+}P\alpha P+Pα,开始死循环 - 选配成功是暂时的,如用 α ∗ ∗ β \alpha**\beta α∗∗β去匹配 α ∗ i β \alpha*i\beta α∗iβ,需要复杂的回溯解决该问题
- 无法知道出错的确切位置
⋆ \star ⋆ 上下文无关文法:2型文法
⋆ \star ⋆ 有限自动机:3型文法
4.3 LL(1)分析法
自上而下的分析,试错过程占大头,LL(1)分析法就是要每次发展子树都明确应该发展哪个
- 问题留给本层
- 问题是留给子还是留给兄(留给兄,该子树发展 ε \varepsilon ε)(子兄选择不冲突FIRST和FOLLOW)
- 问题留给下一层子树
- 留给哪个子树(左提公共因子)(FIRST)
- 是否会绕一圈再抛回给自己(消除直接/间接左递归)
4.3.1 左递归的消除
- 消除直接左递归:
P → P α ∣ β P\rightarrow P\alpha|\beta P→Pα∣β
替换为:
P → β P ′ P ′ → α P ′ ∣ ε \begin{matrix}P\rightarrow\beta P'\\P'\rightarrow\alpha P'|\varepsilon\end{matrix} P→βP′P′→αP′∣ε - 消除间接左递归:
- 间接左递归变直接左递归
- 消除直接左递归
例:
间接左递归语言: S → Q c ∣ c Q → R b ∣ b R → S a ∣ a \begin{matrix}S\rightarrow Qc|c\\Q\rightarrow Rb|b\\R\rightarrow Sa|a\end{matrix} S→Qc∣cQ→Rb∣bR→Sa∣a
存在: S ⇒ Q c ⇒ R b c ⇒ S a b c S\Rightarrow Qc\Rightarrow Rbc\Rightarrow Sabc S⇒Qc⇒Rbc⇒Sabc(间接回溯)
修改为: S → S a b c ∣ a b c ∣ b c ∣ c S\rightarrow Sabc|abc|bc|c S→Sabc∣abc∣bc∣c
消除直接左递归: S → a b c S ′ ∣ b c S ′ ∣ c S ′ S ′ → a b c S ′ ∣ ε \begin{matrix}S\rightarrow abcS'|bcS'|cS'\\S'\rightarrow abcS'|\varepsilon\end{matrix} S→abcS′∣bcS′∣cS′S′→abcS′∣ε
4.3.2 消除回溯、提左因子
目的:使得分析器能够根据面临输入符号准确指派执行任务(使得能根据待匹配字符去发展子树)
-
F
I
R
S
T
(
α
)
FIRST(\alpha)
FIRST(α)
F I R S T ( α ) = { a ∣ α ⇒ ∗ a ⋯ , a ∈ V T } FIRST(\alpha)=\{a|\alpha\xRightarrow{*}a\cdots,a\in V_{T}\} FIRST(α)={a∣α∗a⋯,a∈VT}
⋆ \star ⋆ 若 α ⇒ ∗ ε \alpha\xRightarrow{*}\varepsilon α∗ε,则 ε ∈ F I R S T ( α ) \varepsilon\in FIRST(\alpha) ε∈FIRST(α)- 消除回溯的条件
F I R S T ( α i ) ∩ F I R S T ( α j ) = ϕ FIRST(\alpha_i)\cap FIRST(\alpha_j)=\phi FIRST(αi)∩FIRST(αj)=ϕ
- 消除回溯的条件
- 提取公共左因子
例:
回溯语言: A → δ β 1 ∣ δ β 2 ∣ ⋯ ∣ δ β n ∣ γ 1 ∣ γ 2 ∣ ⋯ γ m A\rightarrow\delta\beta_1|\delta\beta_2|\cdots|\delta\beta_n|\gamma_1|\gamma_2|\cdots\gamma_m A→δβ1∣δβ2∣⋯∣δβn∣γ1∣γ2∣⋯γm
提左因子: A → δ A ′ ∣ γ 1 ∣ γ 2 ∣ ⋯ ∣ γ m A ′ → β 1 ∣ β 2 ⋯ ∣ β n \begin{matrix}A\rightarrow\delta A'|\gamma_1|\gamma_2|\cdots|\gamma_m\\A'\rightarrow\beta_1|\beta_2\cdots|\beta_n\end{matrix} A→δA′∣γ1∣γ2∣⋯∣γmA′→β1∣β2⋯∣βn
4.3.3 LL(1)分析条件
-
F
O
L
L
O
W
(
A
)
FOLLOW(A)
FOLLOW(A)
F O L L O W ( A ) = { a ∣ S ⇒ ∗ ⋯ A a ⋯ , a ∈ V T } FOLLOW(A)=\{a|S\xRightarrow{*}\cdots Aa\cdots,a\in V_T\} FOLLOW(A)={a∣S∗⋯Aa⋯,a∈VT}
⋆ \star ⋆ 若 S ⇒ ∗ ⋯ A S\xRightarrow{*}\cdots A S∗⋯A,则 # ∈ F O L L O W ( A ) \#\in FOLLOW(A) #∈FOLLOW(A) - 不带回溯的自上而下分析的文法(LL(1)文法)
构造条件- 不含左递归(出问题时不能把问题抛给子树中的自己)
- 若 A → α 1 ∣ α 2 ∣ ⋯ ∣ α n A\rightarrow\alpha_1|\alpha_2|\cdots|\alpha_n A→α1∣α2∣⋯∣αn,则 F I R S T ( α i ) ∩ F I R S T ( α j ) = ϕ FIRST(\alpha_i)\cap FIRST(\alpha_j)=\phi FIRST(αi)∩FIRST(αj)=ϕ(匹配上时只有一条子树可走)
- 若非终结符
A
A
A的某个候选首符集包含
ε
\varepsilon
ε,则
F
I
R
S
T
(
A
)
∩
F
O
L
L
O
W
(
A
)
=
ϕ
FIRST(A)\cap FOLLOW(A)=\phi
FIRST(A)∩FOLLOW(A)=ϕ(必须明确给子还是给兄弟解决)
策略 - 若 a ∈ F I R S T ( α i ) a\in FIRST(\alpha_i) a∈FIRST(αi),则指派 α i \alpha_i αi去执行任务
- 若
a
a
a不属于任何一个候选首符集,则:
- 若 ε \varepsilon ε属于 F I R S T ( α i ) FIRST(\alpha_i) FIRST(αi)且 a ∈ F O L L O W ( A ) a\in FOLLOW(A) a∈FOLLOW(A),则让 A A A与 ϵ \epsilon ϵ自动匹配
- 否则, a a a出现是一种语法错误
4.4 递归下降分析程序构造
简单说就是按照上面的构造明确如何按照句子自上而下发展LL(1)语法分析树
另外引入了一个扩充巴克斯范式
- 递归下降分析器
例:
存在 E ′ → T E ′ ∣ ε E'\rightarrow TE'|\varepsilon E′→TE′∣ε- E ′ E' E′在匹配字符串的时候查询 F I R S T ( T ) FIRST(T) FIRST(T)和 F I R S T ( ε ) FIRST(\varepsilon) FIRST(ε),发现字符串待匹配首字母在 F I R S T ( T ) FIRST(T) FIRST(T)中,选择定义 E ′ → T E ′ E'\rightarrow TE' E′→TE′
- 调用函数
T
T
T对字符串进行匹配
- T T T的终结符与字符串相互抵消
- T T T根据 F I R S T FIRST FIRST调用其定义(及定义其的非终结符)对字符串进行匹配
- 扩充的巴斯克范式
巴克斯范式:- → \rightarrow →:定义为
-
∣
|
∣:或
([[2.3 程序语言的语法描述]])
扩充: - 用花括号
{
α
}
\{\alpha\}
{α}表示闭包运算
α
∗
\alpha^*
α∗
([[2.3 程序语言的语法描述]]) - 用 { α } n 0 \{\alpha\}^0_n {α}n0表示任意重复 0 0 0次至 n n n次, { α } 0 0 = α 0 = ε \{\alpha\}_0^0=\alpha^0=\varepsilon {α}00=α0=ε
- 用方括号
[
α
]
[\alpha]
[α]表示
{
α
}
1
0
\{\alpha\}_1^0
{α}10,即表示
α
\alpha
α的出现可有可无(等价于
α
∣
ε
\alpha|\varepsilon
α∣ε)
例:
实数: d e c i m a l → [ s i g n ] i n t e g e r . { d i g i t } [ e x p o n e n t ] e x p o n e n t → E [ s i g n ] i n t e r g e r i n t e r g e r → d i g i t { d i g i t } s i g n → + ∣ − \begin{matrix}decimal\rightarrow[sign]integer.\{digit\}[exponent]\\exponent\rightarrow E[sign]interger\\interger\rightarrow digit\{digit\}\\sign\rightarrow +|-\end{matrix} decimal→[sign]integer.{digit}[exponent]exponent→E[sign]intergerinterger→digit{digit}sign→+∣−
第一行定义浮点数整体
第二行定义科学计数法部分
第三行定义整数/小数的纯数字串部分
第四行定义符号部分
4.5 预测分析程序
本质上就是4.4的延伸
- 分析表
结构:- 横坐标:待匹配的符号类型
- 纵坐标:待定义的非终结符
- 表内容:非终结符的定义/ERROR
- 栈
符号栈:用于存放定义得来的待抵消的非终结符/终结符字符串 - 预测分析程序
4.5.1 预测分析程序工作过程
- 符号栈顶为终结符
- 符号栈顶终结符与字符串首进行抵消
- 符号栈顶为非终结符
以字符串首字母为横坐标,以符号栈顶非终结符为纵坐标,查询预测分析表- 内容为定义式
弹出非终结符,从右向左读取定义,并压入符号栈 - 内容为空
ERROR,匹配失败
- 内容为定义式
- 符号栈顶为#,输入串为#
匹配成功
4.5.2 预测分析表的构造
本质上是根据定义的
F
I
R
S
T
FIRST
FIRST来确定位置,如果
E
E
E的某一定义
P
P
P的
F
I
R
S
T
FIRST
FIRST中有终结符
α
\alpha
α,则将分析表中
(
α
,
E
)
(\alpha,E)
(α,E)位置设置为
P
P
P
具体操作:
- 若 X ∈ V T X\in V_T X∈VT,则 F I R S T ( X ) = { X } FIRST(X)=\{X\} FIRST(X)={X}
- 若 X ∈ V N X\in V_N X∈VN,且有产生式 X → a ⋯ X\rightarrow a\cdots X→a⋯,则把 a a a加入到 F I R S T ( X ) FIRST(X) FIRST(X)中;若 X → ε X\rightarrow\varepsilon X→ε也是一条产生式,则将 ε \varepsilon ε也加到 F I R S T ( X ) FIRST(X) FIRST(X)中
- 若
X
→
Y
⋯
X\rightarrow Y\cdots
X→Y⋯是一个产生式且
Y
∈
V
N
Y\in V_N
Y∈VN,则把
F
I
R
S
T
(
Y
)
FIRST(Y)
FIRST(Y)中所有非
ε
\varepsilon
ε-元素都加到
F
I
R
S
T
(
X
)
FIRST(X)
FIRST(X)中;若
X
→
Y
1
Y
2
⋯
Y
k
X\rightarrow Y_1Y_2\cdots Y_k
X→Y1Y2⋯Yk是一个产生式,
Y
1
,
⋯
,
Y
i
−
1
Y_1,\cdots,Y_{i-1}
Y1,⋯,Yi−1都是非终结符且
F
I
R
S
T
FIRST
FIRST中含有
ε
\varepsilon
ε,则将
F
I
R
S
T
(
Y
i
)
FIRST(Y_i)
FIRST(Yi)中的元素加入
F
I
R
S
T
(
X
)
FIRST(X)
FIRST(X)中;若
Y
1
,
⋯
,
Y
k
Y_1,\cdots,Y_{k}
Y1,⋯,Yk都是非终结符且
F
I
R
S
T
FIRST
FIRST中含有
ε
\varepsilon
ε,则将
ε
\varepsilon
ε加入
F
I
R
S
T
(
X
)
FIRST(X)
FIRST(X)中
重复上述操作至集合不再发生变化
递归查找各个非终结符的产生式也行
⋆ \star ⋆ 如果已知文法是无二义的,则无需查看 F O L L O W FOLLOW FOLLOW集合
⋆ \star ⋆ 如果文法 G G G是左递归或二义的,则 M M M至少含有一个多重入口
4.6 LL(1)分析中的错误处理
略