词法分析、语法分析、语义分析、中间代码生成、代码优化、目标代码生成。
词法分析:对源程序字符串扫描分解,识别出单词符号。(拆分字符串)
语法分析:根据语言的语法规则对符号序列进行语法分析,识别出语法短语,判断语法是否正确。(识别短语,判断正确)
语义分析:对语法分析的结果分析语义错误,收集类型信息。(语义,类型)
中间代码生成:把源程序变成结构简单、含义明确、易生成目标代码的形式。
代码优化:对中间代码或目标代码进行变换改造等优化处理,提高效率。
目标代码生成:将语义分析结果或中间代码变成目标代码。(一般是汇编等)
汇编器
编译方式先对源代码进行全面分析和优化后,生成一份高效的机器无关中间代码,再由后端转化为具体机器指令(目标代码),运行时无需源代码和解释器,直接执行机器码。
解释方式则在每个阶段(词法、语法、语义)都实时边读边处理、即时执行,灵活但效率较低。
代码优化
核心思想为“自底向上”归约,通过状态栈识别活前缀,依据ACTION表和GOTO表执行移进、归约或接受。
“L”指从左到右扫描输入串;“R”代表构造最右推导的逆过程,即规范归约,确保分析过程的准确性与高效性。
句柄
回溯
正规文法 / 右线性文法。
文法中两个产生式存在相同的右部。(同一字符串可通过不同【推导/归约】【生成不同语法树/产生不同语义】)
归约为停机问题 -> 构造一个文法,如果它二义,就对应某个机器停机,否则对应无限循环。既然停机不可判,别的东西也不可能判。不可能100%正确且终止。
r=(a∣b)∗a(a∣b)∗
所求正规集是“至少含一个 a 的所有 a,b 串”。正规式要求串中出现 a 且前后可为任意 a,b 串。
Q={0,1,2},q0=0,F={2},δ 如下:
stateDiagram-v2
direction LR
q0: 0
q1: 1
q2: 2 (终态)
q0 --> q0: a,b
q0 --> q1: a
q1 --> q2: a,b
q2 --> q2: a,b
- δ(0,a)={0,1},δ(0,b)={0}
- δ(1,a)={2},δ(1,b)={2}
- δ(2,a)={2},δ(2,b)={2}
起点 0 循环匹配 (a∣b)∗;读入 a 转到 1;1 再读一个字符到 2,2 循环匹配右侧 (a∣b)∗。
初始 A=ε-closure({0})={0},逐个未标记状态对 a、b 求 move 后的 ε-闭包:
| 状态集合 | DFA 状态 | 经 a 到达 | 经 b 到达 | 含终态 2 |
|---|
| {0} | A | {0,1}→B | {0}→A | 否 |
| {0,1} | B | {0,1,2}→C | {0,2}→D | 否 |
| {0,1,2} | C | {0,1,2}→C | {0,2}→D | 是 |
| {0,2} | D | {0,1,2}→C | {0,2}→D | 是 |
DFA 转移图:
stateDiagram-v2
direction LR
A: A (起始)
B: B
C: C (终态)
D: D (终态)
A --> B: a
A --> A: b
B --> C: a
B --> D: b
C --> C: a
C --> D: b
D --> C: a
D --> D: b
DFA 转移表:
| DFA 状态 | a | b |
|---|
| →A | B | A |
| B | C | D |
| ∗C | C | D |
| ∗D | C | D |
终态集 FDFA={C,D}。
初始划分 Π0={{A,B},{C,D}}(非终态、终态)。
考察 {A,B}:经 a,A→B∈{A,B},B→C∈{C,D} → 不等价,分裂为 {A}、{B}。
考察 {C,D}:经 a,C→C∈{C,D},D→C∈{C,D};经 b,C→D∈{C,D},D→D∈{C,D} → 等价,不可分裂。
最终划分 Π={{A},{B},{C,D}}。将 C,D 合并为状态 C。
最简 DFA(3 个状态):
stateDiagram-v2
direction LR
A: A (起始)
B: B
C: C (终态)
A --> B: a
A --> A: b
B --> C: a
B --> C: b
C --> C: a
C --> C: b
| DFA 状态 | a | b |
|---|
| →A | B | A |
| B | C | C |
| ∗C | C | C |
状态 A 表示”尚未读到 a“,B 表示”刚读到第一个 a“,C 表示”已完成至少一个 a“。该 DFA 等价于正规式 (a∣b)∗a(a∣b)∗,状态数 3 为最少。
(1) 写出该正规集对应的正规式;
(2) 根据正规式构造 NFA;
(3) 将 NFA 确定化为 DFA;
(4) 将 DFA 最小化,得到最简 DFA。
- 写出对应正规式
思路:字符串长度至少为2,倒数第二个字符固定为a,其余位置字符任意。正规式为:(a∣b)∗a(a∣b)
- 构造非确定有限自动机 (NFA)
思路:按正规式结构拆解,(a∣b)∗用带自环的状态表示,经匹配a的转移后,再经匹配任意字符的转移到达终止状态,构建初始状态图。
r=(a∣b)∗a(a∣b)
Q={0,1,2},q0=0,F={2},δ 如下:
stateDiagram-v2
direction LR
q0: 0
q1: 1
q2: 2 (终态)
q0 --> q0: a,b
q0 --> q1: a
q1 --> q2: a,b
- δ(0,a)={0,1},δ(0,b)={0}
- δ(1,a)={2},δ(1,b)={2}
- δ(2,⋅)=∅
起点 0 可任意循环匹配 (a∣b)∗;一旦读入 a 转到 1(这一位即”倒数第二个字符为 a”),再读一个字符到终态 2。
初始 A=ε-closure({0})={0},逐个未标记状态对 a、b 求 move 后的 ε-闭包:
| 状态集合 | DFA 状态 | 经 a 到达 | 经 b 到达 | 含终态 2 |
|---|
| {0} | A | {0,1}→ 新 B | {0}→A | 否 |
| {0,1} | B | {0,1,2}→ 新 C | {0,2}→ 新 D | 否 |
| {0,1,2} | C | {0,1,2}→C | {0,2}→D | 是 |
| {0,2} | D | {0,1,2}→C | {0}→A | 是 |
DFA 转移图:
stateDiagram-v2
direction LR
A: A (起始)
B: B
C: C (终态)
D: D (终态)
A --> B: a
A --> A: b
B --> C: a
B --> D: b
C --> C: a
C --> D: b
D --> C: a
D --> A: b
DFA 转移表:
| DFA 状态 | a | b |
|---|
| →A | B | A |
| B | C | D |
| ∗C | C | D |
| ∗D | C | A |
终态集 FDFA={C,D}。
初始划分 Π0={{A,B},{C,D}}(非终态、终态)。
考察 {A,B}:经 a,A→B∈{A,B},B→C∈{C,D} → 不等价,分裂为 {A}、{B}。
考察 {C,D}:经 b,C→D∈{C,D},D→A∈{A} → 不等价,分裂为 {C}、{D}。
最终划分 Π={{A},{B},{C},{D}},不可再分,DFA 已是最简(4 个状态,无冗余)。
stateDiagram-v2
direction LR
note1: 最简 DFA 与上节 DFA 一致,状态不可合并
A: A (起始)
B: B
C: C (终态)
D: D (终态)
A --> B: a
A --> A: b
B --> C: a
B --> D: b
C --> C: a
C --> D: b
D --> C: a
D --> A: b
从文法开始符号(S)出发,逐个产生式展开直到匹配输入串的终结符符号(LL(1)文法通过FIRST/FOLLOW集预先预测,消去左递归和公因子后避免回溯)。
(1)改写文法使其适合自顶向下分析,写出改写结果;
(2)分别计算改写后文法的右部文法符号串的 FIRST 集和 非终结符的FOLLOW集;
(3)判断该文法是否为LL(1),若是,构造预测分析表;若不是,说明原因。
总结:LL(1)分析的关键在于预处理文法(消左递归、提公因子),并确保任意非终结符的SELECT集互不相交。
提取左公因子(S→aSBc 与 S→a 公因子为 a):
S→aS′S′→SBc∣ε
消除直接左递归(B→Bb∣d,引入 B′):
B→dB′B′→bB′∣ε
改写后文法 G′:
(1)(2)(3)(4)(5)(6) S→aS′ S′→SBc S′→ε B→dB′ B′→bB′ B′→ε
FIRST 集(自底向上):
| 符号 | FIRST | 依据 |
|---|
| B′ | {b,ε} | B′→bB′ 给 b;B′→ε |
| B | {d} | B→dB′,d 为首终结符 |
| S | {a} | S→aS′ |
| S′ | {a,ε} | S′→SBc,FIRST(S)={a};S′→ε |
右部串的 FIRST:
| 产生式右部 | FIRST |
|---|
| aS′ | {a} |
| SBc | {a} |
| ε | {ε} |
| dB′ | {d} |
| bB′ | {b} |
FOLLOW 集(初始 #∈FOLLOW(S),反复传播至稳定):
- S′→SBc:FIRST(Bc)={d}(B 非空),故 d∈FOLLOW(S);B 后跟 c,c∈FOLLOW(B)。
- S→aS′:S′ 在末尾,FOLLOW(S)⊆FOLLOW(S′)。
- B→dB′:B′ 在末尾,FOLLOW(B)⊆FOLLOW(B′)。
- B′→bB′:B′ 在末尾,自反无新信息。
迭代后稳定:
| 非终结符 | FOLLOW |
|---|
| S | {#,d} |
| S′ | {#,d} |
| B | {c} |
| B′ | {c} |
SELECT 集:
| 产生式 | FIRST 含 ε? | SELECT |
|---|
| S→aS′ | 否 | {a} |
| S′→SBc | 否 | {a} |
| S′→ε | 是 | FOLLOW(S′)={#,d} |
| B→dB′ | 否 | {d} |
| B′→bB′ | 否 | {b} |
| B′→ε | 是 | FOLLOW(B′)={c} |
LL(1) 判别(同左部 SELECT 集相交):
- S′:{a}∩{#,d}=∅ ✓
- B′:{b}∩{c}=∅ ✓
- S、B 各一个产生式,无冲突 ✓
该文法是 LL(1) 文法。
预测分析表 M[A,a](VT={a,b,c,d,#}):
| 非终结符 | a | b | c | d | # |
|---|
| S | S→aS′ | | | | |
| S′ | S′→SBc | | S′→ε | S′→ε | S′→ε |
说明:S′→ε 的 SELECT 集为 {#,d},故仅在 d、# 列填;c 列为空,修正表如下。
| 非终结符 | a | b | c | d | # |
|---|
| S | S→aS′ | | | | |
| S′ | S′→SBc | | | S′→ε | S′→ε |
| B | | | | B→dB′ | |
| B′ | | B′→bB′ | B′→ε | | |
分析过程流图(以输入 adbcbc# 为例,展示归约式分析过程):
flowchart TD
A["栈: #S<br/输入: adbcbc#"] --> B["查 M[S,a]=S→aS'"]
B --> C["栈: #S'a<br/输入: dbcbc#"]
C --> D["匹配 a, S'移除"]
D --> E["栈: #S'<br/输入: dbcbc#<br/d∈SELECT(S'→ε)后接 S→SBc"]
E --> F["栈: #cBS<br/输入: dbcbc#"]
F --> G["B 需 d: M[B,d]=B→dB'"]
G --> H["移进 d, 归约链完成"]
H --> I["接受 adbcbc"]
句柄:最左直接短语。
素短语:句型中具有句法独立性且不可再分的最小短语结构。(去短语中找,并且要满足两条规则:1)包含终结符 2)除了他自身不能包含素短语)
E→E+T∣T;T→T∗F∣F;F→F↑P∣P;P→(E)∣I
(1)给出句型 F↑P+T∗(E+T) 的短语、直接短语、句柄、素短语、最左素短语。
(2)计算每个非终结符的 FIRSTVT 和 LASTVT 集,并据此构造算符优先关系表。
(3)对输入串 i↑i+i∗i 执行算符优先分析,写出分析过程(包括栈、输入串、动作)。
语法树(最右推导 E⇒E+T⇒E+T∗F⇒E+T∗(E)⇒E+T∗(E+T)⇒F↑P+T∗(E+T) 的逆过程):
flowchart TD
E0["E"] --> E1["E"]
E0 --> PLUS1["+"]
E0 --> T1["T"]
E1 --> F1["F"]
E1 --> UP["↑"]
E1 --> P0["P"]
T1 --> T2["T"]
T1 --> STAR["*"]
T1 --> F2["F"]
T2 --> F3["F→P→i"]
F2 --> P1["P"]
P1 --> LP["("]
P1 --> E2["E"]
P1 --> RP[")"]
E2 --> E3["E"]
E2 --> PLUS2["+"]
E2 --> T3["T"]
E3 --> T4["T→F→P→i"]
T3 --> T5["T→F→P→i"]
叶子自左向右:F, ↑, P, +, T, ∗, (, E, +, T, )。
短语集合(每棵子树叶节点串):
| 短语 | 来自子树 |
|---|
| F | 子叶 F(父 F→F↑P 的左子) |
| P | 子叶 P(↑ 右子) |
| F↑P | F→F↑P |
| 第一个 T | 叶 T 自身 |
| 括号内 E、T | 子叶 |
| E+T | E→E+T(括号内) |
| (E+T) | P→(E) |
| T∗(E+T) | T→T∗F |
| F↑P+T∗(E+T) | 根 E 整棵树 |
直接短语(子树高度为 1,父节点一步推出该叶子串):
| 直接短语 | 单步归约依据 |
|---|
| F | 叶 F,其父直接派生 |
| P | 叶 P |
| E+T | E→E+T 单步 |
| (E+T) | P→(E) 单步 |
注:F↑P 需 F→F↑P 后叶子 P 再由 P→i 派生,高度 > 1,不是直接短语;T∗(E+T) 同理。
句柄 = 最左直接短语:最左叶子是 F,对应的直接短语即 F。
素短语(含至少一个终结符,且不含其他素短语的短语):
- F↑P:含 ↑,内部 F、P 不含终结符 → 素短语 ✓
- E+T:含 +,内部 E、T 不含终结符 → 素短语 ✓
- (E+T):含子短语 E+T(已含终结符)→ 不素
- T∗(E+T)、整句:含子素短语 → 不素
素短语集合:{F↑P, E+T}
最左素短语:最左的素短语 → F↑P(位置 1–3)。
结果汇总:
| 项 | 结果 |
|---|
| 短语 | F, P, F↑P, T, E+T, (E+T), T∗(E+T), F↑P+T∗(E+T) |
| 直接短语 | F, P, E+T, (E+T) |
| 句柄 | F |
| 素短语 | F↑P, E+T |
| 最左素短语 | F↑P |
FIRSTVT 集(规则:A→a⋯ 或 A→Ba⋯ 给 a;A→B⋯ 继承 FIRSTVT(B)):
| 非终结符 | FIRSTVT | 依据 |
|---|
| P | {(, i} | P→(⋯,P→i |
| F | {↑, (, i} | F→F↑P 给 ↑;F→P 继承 FIRSTVT(P) |
| T | {∗, ↑, (, i} | T→T∗F 给 ∗;T→F 继承 FIRSTVT(F) |
| E | {+, ∗, ↑, (, i} | E→E+T 给 +;E→T 继承 FIRSTVT(T) |
LASTVT 集(规则:A→⋯a 或 A→⋯aB 给 a;A→⋯B 继承 LASTVT(B)):
| 非终结符 | LASTVT | 依据 |
|---|
| P | {), i} | P→(⋯) 给 );P→i |
| F | {↑, ), i} | F→F↑P 给 ↑;F→P 继承 LASTVT(P) |
| T | {∗, ↑, ), i} | T→T∗F 给 ∗;T→F 继承 LASTVT(F) |
| E | {+, ∗, ↑, ), i} | E→E+T 给 +;E→T 继承 LASTVT(T) |
≐ 关系(产生式右部相邻终结符):
- P→(E) → (≐)
⋖ 关系(A→⋯aB⋯,b∈FIRSTVT(B) → a⋖b):
| 产生式 | a | B | b∈FIRSTVT(B) | 关系 |
|---|
| E→E+T | + | T | {∗,↑,(,i} | +⋖∗, ↑, (, i |
| T→T∗F | ∗ | F | {↑,(,i} | ∗⋖↑, (, i |
| F→F↑P | ↑ | P | {(,i} | ↑⋖(, i |
| P→(E) | ( | E | {+, ∗,↑,(,i} | (⋖+, ∗,↑,(,i |
| 句括号 | # | E | {+, ∗,↑,(,i} | #⋖+, ∗,↑,(,i |
⋗ 关系(A→⋯Bb⋯,a∈LASTVT(B) → a⋗b):
| 产生式 | B | b | a∈LASTVT(B) | 关系 |
|---|
| E→E+T | E | + | {+, ∗,↑,),i} | +, ∗,↑,),i⋗+ |
| T→T∗F | T | ∗ | {∗, ↑,),i} | ∗, ↑,),i⋗∗ |
| F→F↑P | F | ↑ | {↑, ),i} | ↑,),i⋗↑(↑⋗↑ 表右结合) |
| P→(E) | E | ) | {+, ∗,↑,),i} | +, ∗,↑,),i⋗) |
| 句括号 | E | # | {+, ∗,↑,),i} | +, ∗,↑,),i⋗# |
算符优先关系表:
| + | ∗ | ↑ | ( | ) | i | # |
|---|
| + | ⋗ | ⋖ | ⋖ | ⋖ | ⋗ | ⋖ | ⋗ |
| ∗ | ⋗ | ⋗ | ⋖ | ⋖ | ⋗ | ⋖ | ⋗ |
| ↑ | ⋗ | ⋗ | ⋗ | ⋖ | ⋗ | ⋖ | ⋗ |
| ( | ⋖ | ⋖ | ⋖ | ⋖ | ≐ | ⋖ | |
| ) | ⋗ | ⋗ | ⋗ | | ⋗ | | ⋗ |
| i | ⋗ | ⋗ | ⋗ | | ⋗ | | ⋗ |
| # | ⋖ | ⋖ | ⋖ | ⋖ | | ⋖ | ≐ |
说明:↑⋗↑ 体现幂运算右结合。
栈底 #,输入 i↑i+i∗i#。比较栈顶终结符 a 与当前输入 b 的优先关系:⋗ 触发归约(找最左素短语),⋖ 或 ≐ 移进。归约结果统一记为非终结符 N(不关心具体名)。
| 步骤 | 符号栈 | 当前输入串 | 关系(栈顶终结符 vs 输入) | 动作 |
|---|
| 1 | # | i↑i+i∗i# | #⋖i | 移进 i |
| 2 | #i | ↑i+i∗i# | i⋗↑ | 归约 i→N |
| 3 | #N | ↑i+i∗i# | #⋖↑ | 移进 ↑ |
| 4 | #N↑ | i+i∗i# | ↑⋖i | 移进 i |
| 5 | #N↑i | +i∗i# | i⋗+ | 归约 i→N |
| 6 | #N↑N | +i∗i# | ↑⋗+ | 归约 N↑N→N |
| 7 | #N | +i∗i# | #⋖+ | 移进 + |
| 8 | #N+ | i∗i# | +⋖i | 移进 i |
| 9 | #N+i | ∗i# | i⋗∗ | 归约 i→N |
| 10 | #N+N | ∗i# | +⋖∗ | 移进 ∗ |
| 11 | #N+N∗ | i# | ∗⋖i | 移进 i |
| 12 | #N+N∗i | # | i⋗# | 归约 i→N |
| 13 | #N+N∗N | # | ∗⋗# | 归约 N∗N→N |
| 14 | #N+N | # | +⋗# | 归约 N+N→N |
| 15 | #N | # | #≐# | 接受 |
分析过程示意:
flowchart TD
S1["移进 i"] --> S2["i≺↑ 归约 i→N"]
S2 --> S3["移进 ↑"]
S3 --> S4["移进 i"]
S4 --> S5["i≻+ 归约 i→N"]
S5 --> S6["↑≻+ 归约 N↑N→N"]
S6 --> S7["移进 +"]
S7 --> S8["移进 i"]
S8 --> S9["i≻* 归约 i→N"]
S9 --> S10["+≺* 移进 *"]
S10 --> S11["移进 i"]
S11 --> S12["i≻# 归约 i→N"]
S12 --> S13["*≻# 归约 N*N→N"]
S13 --> S14["+≻# 归约 N+N→N"]
S14 --> S15["#=# 接受"]
相同点:
两类分析器均通过扫描输入串、维护栈和输入指针(或状态),结合文法规则(或表)逐步推进,依次识别终结符句柄(handle)以规约。
不同点:
- 驱动方式:LR使用自底向上DFA(LR(0)/LR(1)/LALR等),优先关系使用LL(1)预测表或预测函数,驱动策略不同(LR依赖goto表,优先依赖预测表)。
- 识别过程:LR识别单个句柄,优先关系可识别多个/单个(LL中先看FIRST集)。
- 文法支持:LR支持左递归,优先关系不支持。
- 构造复杂度:LR表构造更复杂,优先关系更简单。
- S′→S;
- S→E;
- E→E+T;
- E→T;
- T→T∗F;
- T→F;
- F→(E);
- F→i;
(1) 画出识别该文法所有活前缀的 LR(1) 项目集规范族 (DFA)。
(2) 构造 LR(1) 分析表(要求给出 ACTION 和 GOTO 表)。
(3) 给出输入串 i+i∗i 的分析过程(要求列出栈、输入、动作)。
本文法的 LR(1) 项目核心(同心部分)与材料 6.10 节 SLR(1) 的 DFA 结构相同,但每个归约项目携带状态相关的向前看符号,而非全局 FOLLOW 集。为便于作图,下面先给出与 SLR(1) 同心的 LR(0) 骨架 DFA,再在 (2) 的分析表中以 LR(1) 向前看符号决定归约栏。
LR(1) 项目形如 [A→α⋅β, a],闭包:若 [A→α⋅Bβ, a]∈I,加入 [B→⋅γ, b],b∈FIRST(βa)。
核心项目集(圆点结构与 SLR 的 I0–I11 同心,列出关键状态及向前看符号):
| 状态 | LR(1) 项目集(向前看符号标于末尾) |
|---|
| I0 | [S′→⋅S,#];[S→⋅E,#];[E→⋅E+T,#]、[E→⋅E+T,+];[E→⋅T,#]、[E→⋅T,+];[T→⋅T∗F,#]、[.,+]、[.,∗];[T→⋅F,#]、[.,+]、[.,∗];[F→⋅(E),#]、[.,+]、[.,∗];[F→⋅i,#]、[.,+]、[.,∗] |
| I1 | [S′→S⋅,#](接受) |
| I2 | [S→E⋅,#];[E→E⋅+T,#]、[E→E⋅+T,+] |
| I3 | [E→T⋅,#]、[E→T⋅,+];[T→T⋅∗F,#]、[.,+]、[.,∗] |
| I4 | [T→F⋅,#]、[.,+]、[.,∗] |
| I5 | [F→(⋅E),#]、[.,+]、[.,∗](闭包后同 I0 结构,但带向前看 {),+,∗}) |
| I6 | [F→i⋅,#]、[.,+]、[.,∗](归约 r7) |
| I7 | [E→E+⋅T,#]、[.,+](闭包后 T,F,(,i 带 {#,+,∗}) |
| I8 | [T→T∗⋅F,#]、[.,+]、[.,∗](闭包后 F,(,i 带 {#,+,∗}) |
| I9 | [F→(E⋅),#]、[.,+]、[.,∗];[E→E⋅+T,)]、[E→E⋅+T,+] |
| I10 | [E→T⋅,)]、[.,+];[T→T⋅∗F,)]、[.,+]、[.,∗] |
| I11 | [T→F⋅,)]、[.,+]、[.,∗] |
I5,I7,I8 经 ( , i 等 GOTO 后会产生与上述状态 同心 但向前看符号不同的新状态。整体结构与 SLR(1) 的 DFA 同心。
DFA 转移图(同心骨架,标注圆点后读入的符号):
stateDiagram-v2
direction LR
I0: I0
I1: I1 (acc)
I2: I2
I3: I3
I4: I4
I5: I5
I6: I6 (r7)
I7: I7
I8: I8
I9: I9
I10: I10
I11: I11
I0 --> I1: S
I0 --> I2: E
I0 --> I3: T
I0 --> I4: F
I0 --> I5: (
I0 --> I6: i
I2 --> I7: +
I3 --> I8: *
I5 --> I9: E
I5 --> I10: T
I5 --> I11: F
I5 --> I5: (
I5 --> I6: i
I7 --> I10: T
I7 --> I11: F
I7 --> I5: (
I7 --> I6: i
I8 --> I11: F
I8 --> I5: (
I8 --> I6: i
I9 --> I7: +
I10 --> I8: *
注:I5,I7,I8 各自经 ( 和 i 的 GOTO 指向同心状态(与 I5,I6 同心但局部向前看符号不同)。上图为同心骨架示意。
由 LR(1) 项目集族填表:归约仅在该状态存在 [A→α⋅, a] 且当前输入为 a 时执行。
| 状态 | i | + | ∗ | ( | ) | # | S | E | T | F |
|---|
| 0 | S6 | | | S5 | | | 1 | 2 | 3 | 4 |
| 1 | | | | | | acc | | | | |
| 2 | | S7 | | | | r1 | | | | |
| 3 | | r3 | S8 | | | r3 | | | | |
| 4 | | r5 | r5 | | | r5 | | | | |
| 5 | S6 | | | S5 | | | | 9 | 10 | 11 |
| 6 | | r7 | r7 | | | r7 | | | | |
| 7 | S6 | | | S5 | | | | | 10 | 11 |
| 8 | S6 | | | S5 | | | | | | 11 |
| 9 | | S7 | | | S11′ | | | | | |
| 10 | | r3 | S8 | | r3 | | | | | |
| 11 | | r5 | r5 | | r5 | | | | | |
说明:
- 状态 2 含 [S→E⋅,#] ⟹ 仅 # 列归约 r1;含 [E→E⋅+T] ⟹ + 移进。LR(1) 精确到状态,无冲突。
- 状态 9 的 ) 项应为归约 r6(由 F→(E)⋅ 在括号上下文中以 ) 为向前看符号触发),表示为 r6(修正下表)。
- 状态 4、11 等归约 r5(T→F)。
- 状态 6 归约 r7(F→i)。
- GOTO 列:状态 0 行 S=1,E=2,T=3,F=4;状态 5 行 E=9,T=10,F=11;状态 7 行 T=10,F=11;状态 8 行 F=11。
修正后的 LR(1) 分析表:
| 状态 | i | + | ∗ | ( | ) | # | S | E | T | F |
|---|
| 0 | S6 | | | S5 | | | 1 | 2 | 3 | 4 |
| 1 | | | | | | acc | | | | |
| 2 | | S7 | | | | r1 | | | | |
| 3 | | r3 | S8 | | | r3 | | | | |
| 4 | | r5 | r5 | | | r5 | | | | |
| 5 | S6 | | | S5 | | | | 9 | 10 | 11 |
| 6 | | r7 | r7 | | | r7 | | | | |
| 7 | S6 | | | S5 | | | | | 10 | 11 |
| 8 | S6 | | | S5 | | | | | | 11 |
| 9 | | S7 | | | r6 | | | | | |
| 10 | | r3 | S8 | | r3 | | | | | |
| 11 | | r5 | r5 | | r5 | | | | | |
产生式编号:r1:S→E,r2:E→E+T,r3:E→T,r4:T→T∗F,r5:T→F,r6:F→(E),r7:F→i。
状态 14(对应 E→E+⋅T 经 T 后)含 [E→E+T⋅,#],# 归约 r2,∗ 移进 — 与状态 9 同心但向前看不同。表中状态 9 对应括号内 E 已归约的场景()归约 r6、∗? 实际 I9 不含 ∗ 移进)。上表已据同心 DFA 简化。
利用 LR(1) 分析表(与材料 6.9 节 SLR(1) 分析过程动作相同,因本文法对应部分动作一致):
| 步骤 | 状态栈 | 符号栈 | 输入串 | ACTION | GOTO |
|---|
| (1) | 0 | # | i+i∗i# | S6 | |
| (2) | 06 | #i | +i∗i# | r7 | 4 |
| (3) | 04 | #F | +i∗i# | r5 | 3 |
| (4) | 03 | #T | +i∗i# | r3 | 2 |
| (5) | 02 | #E | +i∗i# | S7 | |
| (6) | 027 | #E+ | i∗i# | S6 | |
| (7) | 0276 | #E+i | ∗i# | r7 | 11 |
| (8) | 027(11) | #E+F | ∗i# | r5 | 10 |
| (9) | 027(10) | #E+T | ∗i# | S8 | |
| (10) | 027(10)8 | #E+T∗ | i# | S6 | |
| (11) | 027(10)86 | #E+T∗i | # | r7 | 11 |
| (12) | 027(10)8(11) | #E+T∗F | # | r4 | 10 |
| (13) | 027(10) | #E+T | # | r2 | 2 |
| (14) | 02 | #E | # | r1 | 1 |
| (15) | 01 | #S | # | acc | |
关键步骤解析:
- (2) r7:状态 6 含 [F→i⋅,{+,∗,#}],输入 +∈{+,∗,#} ⟹ 归约 F→i。弹出 1 个状态(6)和 1 个符号(i),栈顶状态 0,左部 F 查 GOTO[0,F]=4 ⟹ 压 F 和 4。
- (3) r5:状态 4 含 [T→F⋅,{#,+,∗}] ⟹ 归约 T→F,GOTO[0,T]=3。
- (4) r3:状态 3 含 [E→T⋅,{#,+}],输入 +∈{#,+} ⟹ 归约 E→T,GOTO[0,E]=2。
- (5) S7:状态 2 含 [E→E⋅+T],输入 + ⟹ 移进到 I7。
- (13) r2:状态(同心 I9 对应的 E+T 归约态)含 [E→E+T⋅,#],输入 # ⟹ 归约 E→E+T(弹出 3 个状态和 +T 三符号),栈顶状态 0,GOTO[0,E]=2。
- (14) r1:状态 2 含 [S→E⋅,#],输入 # ⟹ 归约 S→E,GOTO[0,S]=1。
- (15) acc:状态 1 含 [S′→S⋅,#],输入 # ⟹ 接受。
LR(1) 比 SLR(1) 更精细:归约向前看符号是 项目自身携带的状态相关向前看集合 ,而非全局 FOLLOW 集,能区分“括号内归约(向前看含 ))”与“顶层归约(向前看含 #)”。输入串 i+i∗i 被成功分析,是该 LR(1) 文法的句子。
分析过程流图:
flowchart TD
A["状态0, 输入 i"] --> B["S6: 移进 i"]
B --> C["状态6, 输入 +, r7: F→i"]
C --> D["状态4, 输入 +, r5: T→F"]
D --> E["状态3, 输入 +, r3: E→T"]
E --> F["状态2, 输入 +, S7: 移进 +"]
F --> G["状态7, 输入 i, S6: 移进 i"]
G --> H["状态6, 输入 *, r7: F→i"]
H --> I["状态11, 输入 *, r5: T→F"]
I --> J["状态10, 输入 *, S8: 移进 *"]
J --> K["状态8, 输入 i, S6: 移进 i"]
K --> L["状态6, 输入 #, r7: F→i"]
L --> M["状态11, 输入 #, r4: T→T*F"]
M --> N["状态10, 输入 #, r2: E→E+T"]
N --> O["状态2, 输入 #, r1: S→E"]
O --> P["状态1, 输入 #, acc 接受"]