本文中内容整理西安交通大学软件学院吴晓军老师的ppt中,仅供学习使用,请勿转载或他用
参考教材:《程序设计语言 编译原理》(第3版) 陈火旺等 国防工业出版社
编译原理第五章——自下而上分析
目录
- 一、复习:语法分析的两种方式
- 二、自下而上分析概述
- 1.🐯核心思想:移进-规约
- 2.🐶规范规约
- 3.🦁规范规约的两个问题
- 三、算符优先分析
- 1.🐸概念辨析-算符文法、算符优先文法
- 2.🐙概念辨析-算符优先分析法、直观算符优先分析法
- 3.🐬概念辨析-算符文法、算符优先文法
- 4.🐳 利用优先关系表用直观算符优先分析法分析算数表达式(不考可以跳过)
- 5.🐂构造FIRSTVT§和LASTVT§两个集合(必考!!)
- 6.🐝利用FIRSTVT§和LASTVT§两个集合构造优先关系表(必考!!)
- 7.🐇素短语
- 8.🐏优先函数(感觉不会考,至少掌握下概念吧)
- 四、LR分析法
- 1.🐡LR分析法概述
- 2.🍁LR分析过程
- 3.🐚LR(0) (基础必须掌握!!)
- 4.🎵SLR (复习一手FOLLOW集~!!)
LR分析法
1.🐡LR分析法概述
LR分析程序框架
核心是总控程序和分析表~
LR分析程序概念
- LR分析法是一种“移进—归约”的自底向上语法分析方法,其本质是规范归约,具有以下特点:
- (1) 应用面广:能够用LR分析程序识别绝大多数的程序设计语言的语法结构;
- (2) 实现效率高:虽构造方法复杂,但是实现(执行)效率高。
- (3) 查错准确:LR分析器能够及时发现语法错误并准确指出错误位置。
- LR(k)分析方法中L是指自左(Left)向右扫描输入单词串,R指分析过程是最右(Right)推导的逆过程(规范归约),k是指在决定当前分析动作时需向前察看的输入符号个数。
- 包括LR(0)、SLR(1)、LR(K)等多种,考试是随机三选一!
LR分析实质:分析栈+DFA
LR分析核心:分析表
- 分析表由ACTION表和GOTO表两部分组成。
- ACTION(s, a):表示当状态s面临输入a时的动作;
- GOTO(s,x):表示面对文法符号x的下一状态。
- ACTION(s, a)的动作种类:
- 移进s:(shift)
- 规约r:(reduction)
- 结束acc
- 报错(空格)
例子,下面的文法的构造表如下:
文法必须有编号
(1) E -> E + T
(2) E -> T
(3) T -> T * F
(4) T -> F
(5) F -> ( E )
(6) F -> i
i | + | * | ( | ) | # | E | T | F | |
---|---|---|---|---|---|---|---|---|---|
0 | s5 | s4 | 1 | 2 | 3 | ||||
1 | s6 | acc | |||||||
2 | r2 | s7 | r2 | r2 | |||||
3 | r4 | r4 | r4 | r4 | |||||
4 | s5 | s4 | 8 | 2 | 3 | ||||
5 | r6 | r6 | r6 | r6 | |||||
6 | s5 | s4 | 9 | 3 | |||||
7 | s5 | s4 | 10 | ||||||
8 | s6 | s11 | |||||||
9 | r1 | s7 | r1 | r1 | |||||
10 | r3 | r3 | r3 | r3 | |||||
11 | r5 | r5 | r5 | r5 |
LR文法
- LR分析法是针对LR文法的。
- 对于一个文法,如果能构造出一个分析表,使得每个入口都是唯一确定的,那他就是LR文法。
- LR(k)文法的k是指在决定当前分析动作时需向前察看的输入符号个数。
- LR文法绝不会有二义性,也就是说,绝不会发生移进与规约冲突和规约与规约冲突。
2.🍁LR分析过程
例:利用上述分析表,假定输入串为 i*i+i,描述LR分析器的工作过程
这里不再给出完整过程,不是重点。
状态 | 符号 | 输入串 | |
---|---|---|---|
0 | 0 | # | i*i+i# |
1 | 05 | #i | *i+i# |
2 | 03 | #F | *i+i# |
3 | … | … | … |
- 第0步到第1步:表中是s5,则读入5和i;
- 第1步到第2步:
- 表中是r6,根据第6个产生式化简,符号变成#F,状态变成06
- GOTO表对应了3,状态变成03
3.🐚LR(0)
LR(0)分析表的构造步骤
标准步骤:(了解即可)
- 确定G的LR(0)项目
- 以LR(0)项目为状态,构造一个能识别文法G的所有活前缀的NFA
- 利用子集法将NFA确定化,成为以项目集合为状态的DFA
- 根据上述DFA可直接构造出LR(0)分析表
简化步骤:(也是考试的步骤)
- LR(0)项目集规范族的构造
- LR(0)分析表的构造
LR(0)项目
- LR(0)项目简称为项目
- 定义:文法G的每一个产生式的右部添加一个圆点,称为G的一个LR(0)项目
- 项目的意义:指明在分析过程的某时刻我们看到产生式多大一部分
- 项目在计算机中的表示:(m, n)
- m代表产生式编号
- n指出圆点的位置
- 例子:对于A -> XY有三个项目,分别是A -> ⋅ · ⋅XY , A -> X ⋅ · ⋅Y , A -> XY ⋅ · ⋅
- 但是对于A -> ϵ \epsilon ϵ空字,只有一个项目A -> ⋅ · ⋅
前缀、活前缀
- 前缀指该字的任意首部
- 如:abc的前缀包括 ε , a , a b , a b c \varepsilon,a,ab,abc ε,a,ab,abc
- 活前缀:规范句型的一个前缀,该前缀不含句柄之后的任何符号。
- 活前缀包含的句柄并不完整,完整了就会直接规约了
利用CLOSURE方法构造LR(0)项目集规范族
- 拓广文法
-
C
L
O
S
U
R
E
(
I
)
CLOSURE(I)
CLOSURE(I)算法(其中
I
I
I为
G
G
G的任一项目集)
- I的任何项目都属于 C L O S U R E ( I ) CLOSURE(I) CLOSURE(I)
- 若 A → α ⋅ B β A\to \alpha \cdot B \beta A→α⋅Bβ属于 C L O S U R E ( I ) CLOSURE(I) CLOSURE(I),那么,对任何关于B的产生式 B → γ B\to \gamma B→γ,项目 B → ⋅ γ B\to \cdot \gamma B→⋅γ也属于 C L O S U R E ( I ) CLOSURE(I) CLOSURE(I)
- 重复执行上述两步骤直至 C L O S U R E ( I ) CLOSURE(I) CLOSURE(I)不再增大为止
- 构造项目集规范族的方法
- 令NFA的初态为 I I I,求其 C L O S U R E ( I ) CLOSURE(I) CLOSURE(I),得到初态项目集。即:求 C L O S U R E ( { S ′ → ⋅ S } ) CLOSURE(\{S'\to \cdot S\}) CLOSURE({S′→⋅S})
- 对所得项目集 I I I和文法 G G G的每个文法符号 X X X(包括 V T 和 V N V_T和V_N VT和VN)计算 G O ( I , X ) = C L O S U R E ( J ) GO(I, X)=CLOSURE(J) GO(I,X)=CLOSURE(J),得到新的项目集,其中: J = { 任何形如 A → α X ⋅ β 的项目 ∣ A → α ⋅ X β 属于 I } J=\{任何形如A\to \alpha X\cdot \beta的项目|A\to \alpha \cdot X \beta属于I\} J={任何形如A→αX⋅β的项目∣A→α⋅Xβ属于I}
- 重复步骤二,直至没有新的项目集出现
LR(0)分析表的构造
- 若项目 A → α ⋅ a β A\to \alpha \cdot a\beta A→α⋅aβ属于 I k I_k Ik且 G O ( I k , a ) = I j GO(I_k,a)=I_j GO(Ik,a)=Ij, a a a为终结符,则置 A C T I O N [ k , a ] ACTION[k, a] ACTION[k,a]为“把 ( j , a ) 移进栈 (j,a)移进栈 (j,a)移进栈”,简记为“ s j sj sj”
- 若项目 A → α ⋅ A\to \alpha \cdot A→α⋅属于 I k I_k Ik,那么,对任何输入符号 a a a(或者终结符#)置 A C T I O N [ k , a ] ACTION[k,a] ACTION[k,a]为"用产生式 A → α A\to \alpha A→α进行归约",简记为" r j rj rj":其中,假定 A → α A\to \alpha A→α为文法 G ’ G’ G’的第 j j j个产生式
- 若项目 S ′ → S ⋅ S'\to S\cdot S′→S⋅属于 I k I_k Ik,则置 A C T I O N [ k . # ] ACTION[k.\#] ACTION[k.#]为”接受“,简记为" a c c acc acc"
- 若 G O ( I k , A ) = I j , A GO(I_k,A)=I_j,A GO(Ik,A)=Ij,A为非终结符,则置 G O T O [ k , A ] = j GOTO[k,A]=j GOTO[k,A]=j
- 分析表中凡不能使用规则1至4填入信息的空白格均置上“出错标志”
不扯淡了直接上例子反正定义也看不懂😅😅
对于文法G:
S’ -> E
E -> a A | b B
A -> c A | d
B -> c B | d
利用CLOSURE方法构造LR(0)项目集规范族,并且构造LR(0)分析表
1.为文法编号
(0)S’ -> E
(1)E -> a A
(2)E -> b B
(3)A -> c A
(4)A -> d
(5)B -> c B
(6)B -> d
2.利用CLOSURE方法构造LR(0)项目集规范族:
先得到$ I_0$ ={ $S’ -> · E , E -> · a A , E -> · b B $ }
根据$ I_0$可以得到:
$ I_1$ = GO( $ I_0$ , E ) = {
S
’
−
>
E
⋅
S’ -> E ·
S’−>E⋅ }
$ I_2$ = GO( $ I_0$ , a ) = { $E -> a · A , A -> · c A , A -> · d $ }
$ I_3$ = GO( $ I_0$ , b ) = { $E -> b · B , B -> · c B , B -> · d $ }
$ I_1
无法进行下一步了,跳 同理根据
无法进行下一步了,跳~ 同理根据
无法进行下一步了,跳 同理根据 I_2$可以得到:
$ I_4$ = GO( $ I_2$ , A ) = {
E
−
>
a
A
⋅
E -> a A ·
E−>aA⋅ }
$ I_5$ = GO( $ I_2$ , c ) = { $A -> c · A , A -> · c A , A -> · d $ }
$ I_6$ = GO( $ I_2$ , d ) = { $A -> d · $ }
同理根据$ I_3$可以得到:
$ I_7$ = GO( $ I_3$ , B ) = {
E
−
>
b
B
⋅
E -> b B ·
E−>bB⋅ }
$ I_8$ = GO( $ I_3$ , c ) = { $B -> c · B , B -> · c B , B -> · d $ }
$ I_9$ = GO( $ I_3$ , d ) = { $B -> d · $ }
$ I_4
无法进行下一步了,跳 同理根据
无法进行下一步了,跳~ 同理根据
无法进行下一步了,跳 同理根据 I_5$可以得到:
$ I_{10}$ = GO( $ I_5$ , A ) = {
A
−
>
c
A
⋅
A -> c A ·
A−>cA⋅ },没有重复
GO( $ I_5$ , c ) = { $A -> c · A , A -> · c A , A -> · d $ } = $ I_{5}$
GO( $ I_5$ , d ) = { $A -> d · $ } = $ I_{6}$
$ I_6$无法进行下一步了,跳~
$ I_7$无法进行下一步了,跳~
$ I_8$ 分析和$ I_5$类似
$ I_{11}$ = GO( $ I_8$ , B ) = {
B
−
>
c
B
⋅
B -> c B ·
B−>cB⋅ },没有重复
GO( $ I_8$ , c ) = { $B -> c · B , B -> · c B , B -> · d $ } = $ I_{8}$
GO( $ I_8$ , d ) = { $B -> d · $ } = $ I_{9}$
$ I_9$无法进行下一步了,跳~
$ I_{10}$无法进行下一步了,跳~
$ I_{11}$无法进行下一步了,跳~
分析结束~~
3.利用LR(0)项目集规范族构造LR(0)分析表:
掏出一张空表:
a | b | c | d | # | E | A | B | |
---|---|---|---|---|---|---|---|---|
0 | ||||||||
1 | ||||||||
2 | ||||||||
3 | ||||||||
4 | ||||||||
5 | ||||||||
6 | ||||||||
7 | ||||||||
8 | ||||||||
9 | ||||||||
10 | ||||||||
11 |
- 先找acc避免遗忘, S ’ − > E ⋅ S’ -> E · S’−>E⋅ 在 I 1 I_1 I1:
a | b | c | d | # | E | A | B | |
---|---|---|---|---|---|---|---|---|
0 | ||||||||
1 | acc | |||||||
2 |
- 按顺序看
I
0
I_0
I0:
- 第一个项目 S ’ − > ⋅ E S’ -> · E S’−>⋅E,点后面是非终结符E,因为$ I_1$ = GO( $ I_0$ , E ),所以输入E前往状态 I 1 I_1 I1,所以GOTO表的第0行第E列写1;
- 第二个项目$ E -> · a A ,点后面是 a ,因为 ,点后面是a,因为 ,点后面是a,因为 I_2$ = GO( $ I_0$ , a ),所以输入a以后前往 I 2 I_2 I2,则ACTION表第0行第a列写s2。
- 第三个项目$ E -> · b B ,点后面是 b ,因为 ,点后面是b,因为 ,点后面是b,因为 I_3$ = GO( $ I_0$ , b ),所以输入b后前往 I 3 I_3 I3,则ACTION表第0行第b列写s3。
a | b | c | d | # | E | A | B | |
---|---|---|---|---|---|---|---|---|
0 | s2 | s3 | 1 | |||||
1 | acc | |||||||
2 | ||||||||
3 |
- 同理往后看
I
1
I_1
I1:
- 哈哈这一行只有一个项目~填过了,过!
- 同理往后看
I
2
I_2
I2:
- GOTO表A的位置填4
- ACTION表c的位置填s5
- ACTION表d的位置填s6
- 同理往后看
I
3
I_3
I3:
- GOTO表B的位置填7
- ACTION表c的位置填s8
- ACTION表d的位置填s9
a | b | c | d | # | E | A | B | |
---|---|---|---|---|---|---|---|---|
0 | s2 | s3 | 1 | |||||
1 | acc | |||||||
2 | s5 | s6 | 4 | |||||
3 | s8 | s9 | 7 |
- 同理往后看
I
4
I_4
I4:
- 对项目 E − > a A ⋅ E -> a A · E−>aA⋅,A可以规约,根据(1)E -> a A ,我们在ACTION表上都填上r1。
a | b | c | d | # | E | A | B | |
---|---|---|---|---|---|---|---|---|
0 | s2 | s3 | 1 | |||||
1 | acc | |||||||
2 | s5 | s6 | 4 | |||||
3 | s8 | s9 | 7 | |||||
4 | r1 | r1 | r1 | r1 | r1 |
- 同理往后看
I
5
I_5
I5:
- GOTO表A的位置填10
- ACTION表c的位置填s5
- ACTION表d的位置填s6
- 同理往后看
I
6
I_6
I6:
- (4)A -> d ,我们在ACTION表上都填上r4。
- 同理往后看
I
7
I_7
I7:
- (2)E -> b B,我们在ACTION表上都填上r2。
- 同理往后看 I 8 I_8 I8:
- GOTO表B的位置填11
- ACTION表c的位置填s8
- ACTION表d的位置填s9
- 同理往后看 I 9 I_9 I9:
- (6)B -> d ,我们在ACTION表上都填上r6。
- 同理往后看 I 10 I_{10} I10:
- (3)A -> c A ,我们在ACTION表上都填上r3。
- 同理往后看 I 11 I_{11} I11:
- (5)B -> c B,我们在ACTION表上都填上r5。
a | b | c | d | # | E | A | B | |
---|---|---|---|---|---|---|---|---|
0 | s2 | s3 | 1 | |||||
1 | acc | |||||||
2 | s5 | s6 | 4 | |||||
3 | s8 | s9 | 7 | |||||
4 | r1 | r1 | r1 | r1 | r1 | |||
5 | s5 | s6 | 10 | |||||
6 | r4 | r4 | r4 | r4 | r4 | |||
7 | r2 | r2 | r2 | r2 | r2 | |||
8 | s8 | s9 | 11 | |||||
9 | r6 | r6 | r6 | r6 | r6 | |||
10 | r3 | r3 | r3 | r3 | r3 | |||
11 | r5 | r5 | r5 | r5 | r5 |
LR(0)最显著的特征:ACTION表规约的行是相同的。
4.🎵SLR
概念
- SLR的S是simple的意思~
- 与LR(0)相比的优缺点:
- 优点:可以处理更多种类的文法,毕竟LR(0)能处理的文法实在有限。
- 缺点:稍微难构造一点,可以处理的文法更多了但又没那么多~
构造方法
- 跟LR(0)非常类似,只有一点不同,在根据项目集规范族构造分析表的时候,对于规约的操作,要向前展望,看一下FOLLOW集。
- 必须掌握FIRST集和FOLLOW集的构建!
- 上栗子!!别慌,先回忆下FOLLOW集求法,待会得用。
FOLLOW集
求FOLLOW集合的意思就是求非终结符右边所有终结符的集合。
E -> TE’
E’ -> +TE’ | ε
T -> FT’
T’ -> *FT’ | ε
F -> (E) | id
求FOLLOW集的绝家秘法!!!
- 将#放到FOLLOW(S)中,其中S是文法的开始符号。
- 从上向下扫描每一个文法式子,对于右边的每一个非终结符:
- 把所有跟在非终结符后面的终结符加入对应的FOLLOW集合(F -> (E),把)加入E的FOLLOW集合);
- 对于所有跟在非终结符后面的非终结符号(T -> FT’,直接把T’的FIRST集合中的元素(除了ε)加入F的FOLLOW集合)
- 这一步只需要执行一次,并且完全不用考虑式子的左半部分。
- 我们关注式子的右半部分,关注每一个非终结符。
- 从上向下扫描每一个文法式子,对于右边的每一个非终结符:
- 对于末尾的非终结符(E -> TE’的E’),直接把FOLLOW(E)加入FOLLOW(E’);
- 对于非末尾的非终结符(E -> TE’的T),考察FIRST(E’)是否包含ε,如果包含那么也把FOLLOW(E)加入FOLLOW(T)。
- 这一步需要执行多次,最好进行检验。
- 我们需要关注右边的每一个非终结符。
上栗子
前面完全和LR(0)一致,直到开始在表中写r开始变得不同~
a | b | c | d | # | E | A | B | |
---|---|---|---|---|---|---|---|---|
0 | s2 | s3 | 1 | |||||
1 | acc | |||||||
2 | s5 | s6 | 4 | |||||
3 | s8 | s9 | 7 |
LR(0)当初是这样写的:
- 同理往后看
I
4
I_4
I4:
- 对项目$E -> a A ·
$,A可以规约,根据(1)E -> a A ,我们在ACTION表上都填上r1。
- 对项目$E -> a A ·
所以:
a | b | c | d | # | E | A | B | |
---|---|---|---|---|---|---|---|---|
0 | s2 | s3 | 1 | |||||
1 | acc | |||||||
2 | s5 | s6 | 4 | |||||
3 | s8 | s9 | 7 | |||||
4 | r1 | r1 | r1 | r1 | r1 |
SLR的话我们这样改:
- 同理往后看
I
4
I_4
I4:
- 对项目$E -> a A ·
$,A可以规约,根据(1)E -> a A ,我们查看FOLLOW(E)集合,发现只有一个#,那么我们就只在#列填r1
- 对项目$E -> a A ·
a | b | c | d | # | E | A | B | |
---|---|---|---|---|---|---|---|---|
0 | s2 | s3 | 1 | |||||
1 | acc | |||||||
2 | s5 | s6 | 4 | |||||
3 | s8 | s9 | 7 | |||||
4 | r1 |