LR分析表的构造
活前缀
- 活前缀:是指规范句型的一个前缀,这种前缀不含句柄之后的任何符号。即,对于规范句型 α β δ \alpha \beta \delta αβδ, β \beta β为句柄,如果 α β = u 1 u 2 … u r \alpha \beta = u_1u_2\dots u_r αβ=u1u2…ur,则符号串 u 1 u 2 … u i ( 1 ≤ i ≤ r ) u_1u_2\dots u_i(1 \leq i \leq r) u1u2…ui(1≤i≤r)是 α β δ \alpha \beta \delta αβδ的活前缀。( δ \delta δ必为终结符串)
- 规范规约过程中,保证分析栈中总是活前缀,就说明分析采取的移进/归约动作是正确的。
构造识别活前缀的DFA
文法的拓广
将文法 G ( S ) G(S) G(S)拓广为 G ′ ( S ′ ) G'(S') G′(S′)
- 构造文法 G ′ G' G′,它包含了整个 G G G,并引进不出现在 G G G中的非终结符 S ′ S' S′、以及产生式 S ′ → S S' \rightarrow S S′→S, S ′ S' S′是 G ′ G' G′的开始符号
- 称 G ′ G' G′是 G G G的拓广文法
LR(0)项目
- LR(0)项目:
- 在每个产生式的右部添加一个圆点
- 表示我们在分析过程中看到了产生式多大部分
-
A
→
X
Y
Z
A \rightarrow XYZ
A→XYZ有四个项目:
A
→
⋅
X
Y
Z
A \rightarrow \cdot XYZ
A→⋅XYZ、
A
→
X
⋅
Y
Z
A \rightarrow X\cdot YZ
A→X⋅YZ、
A
→
X
Y
⋅
Z
A \rightarrow XY\cdot Z
A→XY⋅Z、
A
→
X
Y
Z
⋅
A \rightarrow XYZ \cdot
A→XYZ⋅
- A → α ⋅ A \rightarrow \alpha \cdot A→α⋅称为“归约项目”
- 归约项目 S ′ → α ⋅ S' \rightarrow \alpha \cdot S′→α⋅称为“接受项目”
- A → α ⋅ a β ( a ∈ V T ) A \rightarrow \alpha \cdot a \beta(a \in V_T) A→α⋅aβ(a∈VT)称为“移进项目”
- A → α ⋅ B β ( B ∈ V N ) A \rightarrow \alpha \cdot B \beta(B \in V_N) A→α⋅Bβ(B∈VN)称为“待约项目”
构造识别文法所有活前缀的DFA
- 构造识别文法所有活前缀的NFA
- 若状态 i i i为 X → X 1 … X i − 1 ⋅ X i … X n X \rightarrow X_1 \dots X_{i - 1} \cdot X_i\dots X_n X→X1…Xi−1⋅Xi…Xn,状态 j j j为 X → X 1 … X i − 1 X i ⋅ X i + 1 … X n X \rightarrow X_1 \dots X_{i-1} X_i \cdot X_{i + 1} \dots X_n X→X1…Xi−1Xi⋅Xi+1…Xn,则从状态 i i i画一条标志为 X i X_i Xi的有向边到状态 j j j
- 若状态 i i i为 X → α ⋅ A β X \rightarrow \alpha \cdot A \beta X→α⋅Aβ, A A A为非终结符,则从状态 i i i画一条 ϵ \epsilon ϵ边到所有状态 A → ⋅ γ A \rightarrow \cdot \gamma A→⋅γ
- 把识别文法所有活前缀的NFA确定化
实例:
先生成NFA
再将NFA转化为DFA
- LR(0)项目集规范族:构成识别一个文法活前缀的DFA的项目集(状态)的全体称为文法的LR(0)项目集规范族
通过计算项目集规范族构造识别活前缀的DFA
有效项目
- 项目
A
→
β
1
⋅
β
2
A \rightarrow \beta_1 \cdot \beta_2
A→β1⋅β2对活前缀
α
β
1
\alpha \beta_1
αβ1是有效的,其条件是存在规范推导:
S ′ ⇒ ∗ R α A ω ⇒ R α β 1 β 2 ω S' \xRightarrow{*}_R\alpha A \omega \Rightarrow_R \alpha \beta_1\beta_2\omega S′∗RαAω⇒Rαβ1β2ω - 在任何时候,分析栈中的活前缀 X 1 X 2 … X m X_1X_2\dots X_m X1X2…Xm的有效项目集正式从识别活前缀的DFA的初态出发,读出 X 1 X 2 … X m X_1X_2\dots X_m X1X2…Xm后到达的那个项目集(状态)
有效项目的性质
- 若项目 A → α ⋅ B β A \rightarrow \alpha \cdot B\beta A→α⋅Bβ对活前缀 η = δ α \eta = \delta \alpha η=δα是有效的且 B → γ B \rightarrow \gamma B→γ是一个产生式,则项目 B → ⋅ γ B \rightarrow \cdot \gamma B→⋅γ对 η = δ α \eta = \delta \alpha η=δα也是有效的
LR(0)项目集规范族的构造
项目集的闭包CLOSURE
假定 I I I是文法 G ′ G' G′的任一项目集,定义和构造 I I I的闭包CLOSURE( I I I)如下:
- I I I的任何项目都属于CLOSURE( I I I)
- 若 A → α ⋅ B β A \rightarrow \alpha \cdot B \beta A→α⋅Bβ属于CLOSURE( I I I),那么,对任何关于 A A A的产生式 B → γ B \rightarrow \gamma B→γ,项目 B → ⋅ γ B \rightarrow \cdot \gamma B→⋅γ也属于CLOSURE( I I I)
- 重复执行上述两步骤直至CLOSURE( I I I)不再增大为止。
状态转换函数
- 为了识别活前缀,我们定义一个状态转换函数,GO是一个状态转换函数。
I
I
I是一个项目集,
X
X
X是一个文法符号。函数值GO(
I
,
X
I,X
I,X)定义为:
GO( I , X I,X I,X) = CLOSURE( J J J)
其中 J J J = {任何形如 A → α X ⋅ β A \rightarrow \alpha X \cdot \beta A→αX⋅β的项目| A → α ⋅ X β A \rightarrow \alpha \cdot X \beta A→α⋅Xβ属于 I I I}。 - 直观上说,若 I I I是对某个活前缀 γ \gamma γ有效的项目集,那么,GO( I , X I,X I,X)便是对 γ X \gamma X γX有效的项目集。
示例
文法
G
(
S
′
)
G(S')
G(S′):
S
′
→
E
S' \rightarrow E
S′→E
E
→
a
A
∣
b
B
E \rightarrow aA|bB
E→aA∣bB
A
→
c
A
∣
d
A \rightarrow cA|d
A→cA∣d
B
→
c
B
∣
d
B \rightarrow cB|d
B→cB∣d
I
0
=
{
S
′
→
⋅
E
,
E
→
⋅
a
A
,
E
→
⋅
b
B
}
I_0 = \{S' \rightarrow \cdot E,E \rightarrow \cdot aA,E \rightarrow \cdot bB\}
I0={S′→⋅E,E→⋅aA,E→⋅bB}
GO(
I
0
,
E
I_0,E
I0,E) = CLOSURE(
{
S
′
→
⋅
E
}
\{S' \rightarrow \cdot E\}
{S′→⋅E}) =
I
1
I_1
I1
GO(
I
0
,
a
I_0,a
I0,a) = CLOSURE(
{
E
→
a
⋅
A
}
\{E \rightarrow a\cdot A\}
{E→a⋅A}) =
{
E
→
a
⋅
A
,
A
→
⋅
c
A
,
A
→
⋅
d
}
\{E \rightarrow a \cdot A, A \rightarrow \cdot cA, A \rightarrow \cdot d\}
{E→a⋅A,A→⋅cA,A→⋅d} =
I
2
I_2
I2
GO(
I
0
,
b
I_0,b
I0,b) = CLOSURE(
{
E
→
b
⋅
B
}
\{E \rightarrow b\cdot B\}
{E→b⋅B} =
{
E
→
b
⋅
B
,
B
→
⋅
c
B
,
B
→
⋅
d
}
\{E \rightarrow b \cdot B, B \rightarrow \cdot cB, B \rightarrow \cdot d\}
{E→b⋅B,B→⋅cB,B→⋅d} =
I
3
I_3
I3
LR(0)项目集规范族的构造算法示例
大致流程:先从
S
′
→
⋅
E
S' \rightarrow \cdot E
S′→⋅E开始,求闭包,然后根据GO转移。然后对每一个转移后的状态,求闭包,根据GO转移。以此类推!
构造LR(0)分析表的算法
LR(0)分析表的构造
假若一个文法 G G G的拓广文法 G ′ G' G′的活前缀识别自动机中的每个状态(项目集)不存在下述情况:
- 既含移进项目又含归约项目
- 含有多个归约项目
则称 G G G是一个LR(0)文法
构造LR(0)分析表的算法
- 令每个项目集 I k I_k Ik的下标 k k k作为分析器的状态,包含项目 S ′ → ⋅ S S' \rightarrow \cdot S S′→⋅S的集合 I k I_k Ik的下标 k k k为分析器的初态。
- 构造LR(0)分析表的ACTION和GOTO子表。因为文字描述比较复杂和繁琐,因此不再罗列,而是直接给出实例
示例
文法
G
(
S
′
)
G(S')
G(S′):
S
′
→
E
S' \rightarrow E
S′→E
E
→
a
A
∣
b
B
E \rightarrow aA|bB
E→aA∣bB
A
→
c
A
∣
d
A \rightarrow cA|d
A→cA∣d
B
→
c
B
∣
d
B \rightarrow cB|d
B→cB∣d
识别活前缀的DFA见前图
ACTION | GOTO | |||||||
---|---|---|---|---|---|---|---|---|
状态 | a | b | c | d | # | E | A | B |
0 | s2 | s3 | 1 | |||||
1 | acc | |||||||
2 | s4 | s10 | 6 | |||||
3 | s5 | s11 | 7 | |||||
4 | s4 | s10 | 8 | |||||
5 | s5 | s11 | 9 | |||||
6 | r1 | r1 | r1 | r1 | r1 | |||
7 | r2 | r2 | r2 | r2 | r2 | |||
8 | r3 | r3 | r3 | r3 | r3 | |||
9 | r5 | r5 | r5 | r5 | r5 | |||
10 | r4 | r4 | r4 | r4 | r4 | |||
11 | r6 | r6 | r6 | r6 | r6 |