Appearance
第八章 自下而上的语法分析
一、自下而上的语法分析
自下而上的语法分析:从开始,看能否找到一个规范归约,逐步向上归约,直到开始符号S。
设有文法
输入串的归约过程:
栈 | 输入串 | 归约 |
---|---|---|
bccab | ||
b | ccab | S->b |
S | ccab | |
Scca | b | A->a |
SccA | b | A->ccA |
SA | b | |
SAb | S->b | |
SAS | S->SAS | |
S |
分析树的生成(裁剪)过程:
二、几个核心概念
短语
设有文法,是开始符号,设是的一个句型,若有且,则称是句型关于的短语。
直接短语
在上面的定义中,如果直接推出,即,则称是句型关于的直接短语。
句柄
一个句型的最左直接短语称为句柄。
例
- 短语:
T*F
、E+T*F
- 直接短语:
T*F
- 句柄:
T*F
三、算符优先文法
Note
适合于表达式的分析。
不严格按照最左归约进行,不是规范归约。
以文法为例:
1. 基本概念
算符文法
如果一个文法的任何产生式都不含两个或两个以上的相连的非终结符,且不含产生式,则称该文法为算符文法。
算符之间的优先关系
对算符文法,,,定义:
- :中有或
- :中有且或
- :中有且或
算符优先文法
如果算符优先文法的任何两个终结符之间的关系至多只有<,=,>中的一个优先关系,则称该文法为算符优先文法。
Warning
优先关系表中没有多重入口,即为算符优先文法。
优先关系表
记录一个文法中所有非终结符之间的优先关系。
Note
优先关系不是数学关系:a<b未必有b>a,终结符之间未必有优先关系,优先关系不能传递。
素短语
素短语:文法某句型的一个短语是素短语,当且仅当它至少含有一个终结符,且除它自身外不再含更小的素短语。
最左素短语:在具有多个素短语的句型中处于最左边的那个素短语。
- 素短语:
T*F
- 最左素短语:
T*F
2. 构造FIRSTVT集和LASTVT集
FIRSTVT集:非终结符能推出的第一个终结符的集合
- 或,则
- ,则
LASTVT集:非终结符能推出的最后一个终结符的集合
- 或,则
- ,则
FIRSTVT | LASTVT | |
---|---|---|
E | + * ( i | + * ) i |
T | * ( i | * ) i |
F | ( i | ) i |
3. 构造优先关系表
- 横竖都是与
- 增加产生式
- ,则(即行横填<)
- ,则(即列纵填>)
i | + | * | ( | ) | # | |
---|---|---|---|---|---|---|
i | > | > | > | > | ||
+ | < | > | < | < | > | > |
* | < | > | > | < | > | > |
( | < | < | < | < | = | |
) | > | > | > | > | ||
# | < | < | < | < | = |
4. 算符优先分析过程
- 栈、输入串、动作
- 栈放
- 查表
- ,acc
栈 | 输入串 | 动作 |
---|---|---|
# | i+i*i# | #<i,移进 |
#i | +i*i# | i>+,归约,F->i |
#F | +i*i# | #<+,移进 |
#F+ | i*i# | +<i,移进 |
#F+i | *i# | i>*,归约,F->i |
#F+F | *i# | +<*,移进 |
#F+F* | i# | *<i,移进 |
#F+F*i | # | i>#,归约,F->i |
#F+F*F | # | *>#,归约,T->T*F |
#F+T | # | +>#,归约,E->E+T |
#E | # | #=#,acc |
四、LR分析法
1. LR分析法的种类
- LR(0)分析法
- SLR分析法
- 规范LR分析法
- LALR分析法
2. 几个概念
活前缀
规范句型中不含句柄之后任何一个符号的一个前缀。
如:,及其任何前缀都是的活前缀
Note
是句柄,及前任何前缀均不包含句柄之后的符号,而是的后缀,是分析栈栈顶符号串。
规范归约的特点
- 归约符号串总是在栈顶
- 句柄之后的待入栈符号串总是终结符
- 规范句型(由规范推导推出的句型)在符号栈中的符号串是规范句型的前缀
活前缀与句柄之间的关系
- 归约符号串总是在栈顶
- 句柄之后的待入栈符号串总是终结符
- 规范句型(由规范推导推出的句型)在符号栈中的符号串是规范句型的前缀
活前缀与句柄之间的关系
- 活前缀不含句柄的任何符号,
- 活前缀只含句柄的真前缀,
- 活前缀包含句柄的全部符号,
LR(0)项目
在一个产生式右部添加一个圆点,称为一个LR(0)项目。
Note
圆点左边已识别,右边期待识别。
LR(0)项目的分类
- 归约项目:形如
- 移进项目:形如,
- 待约项目:形如,
- 接受项目:形如,为开始符号
文法的拓广
在文法中增加产生式,从而使成为唯一的接受项目。
3. 构造识别所有活前缀的转换图
- 每个状态是一个LR(0)项目
- 是唯一初态
- 如果上一条规则的是,
例:
4. 构造LR(0)项目集规范族
- 有效项目:对于项目,如果有,则称对活前缀有效
- 有效项目集:对于一个活前缀有效的项目可能不止一个,对活前缀有效的项目集合称为的有效项目集
- LR(0)项目集规范族:文法的所有有效项目集组成的集合
写出上例的LR(0)项目集规范族
I0=closure{S'->.S}={S'->.S,S->.BB,B->.aB,B->.b}
I1=go(I0,S)={S'->S.}
I2=go(I0,B)={S->B.B,B->.aB,B->.b}
I3=go(I0,a)=go(I2,a)=go(I3,a)={B->a.B,B->.aB,B->.b}
I4=go(I0,b)=go(I2,b)=go(I3,b)={B->b.}
I5=go(I2,B)={S->BB.}
I6=go(I3,B)={B->aB.}
5. 构造LR(0)分析表
有多少状态就有多少行,action表头与,goto表头
- 接收项:
- 移进项:,
- 中的归约项,为第个产生式,
- ,
- 空白:错误
接上例:
a | b | # | S | B | |
---|---|---|---|---|---|
0 | s3 | s4 | |||
1 | acc | 1 | 2 | ||
2 | s3 | s4 | |||
3 | s3 | s4 | 5 | ||
4 | r3 | r3 | r3 | 6 | |
5 | r1 | r1 | r1 | ||
6 | r2 | r2 | r2 |
Warning
LR(0)分析表中没有多重入口说明是LL(1)文法
6. 构造SLR(1)分表
构造的FOLLOW集,产生式左部的FOLLOW集中的才填
接上例:
FIRST | FOLLOW | |
---|---|---|
S | a b | a b # |
B | a b | a b # |
a | b | # | S | B | |
---|---|---|---|---|---|
0 | s3 | s4 | 1 | 2 | |
1 | acc | ||||
2 | s3 | s4 | 5 | ||
3 | s3 | s4 | 6 | ||
4 | r3 | r3 | r3 | ||
5 | r1 | r1 | r1 | ||
6 | r2 | r2 | r2 |
Warning
SLR(1)分析表中没有多重入口说明是SLR(1)文法
7. 分析过程
action表与goto表
action表:定义了在状态S下,当输入字符为a时应采取的动作
- :j入状态栈,输入指针所指符号入符号栈
- :按第j个产生式归约,状态栈出栈产生式右部符号个数,左部入符号栈,goto后的状态入状态栈
- acc:成功
- 空白:出错
goto表:定义了在状态S下,面对文法符号x时状态的转换
分析步骤
- 状态栈、符号栈、输入串、动作
- 状态栈放0,符号栈放#
- :j入状态栈,当前字符入符号栈
- :根据第j个产生式归约,两个栈都出栈右部个数。左部入符号栈,入状态栈
接上例,输入串aabb的分析过程如下:
状态 | 符号 | 输入串 | 动作 |
---|---|---|---|
0 | # | aabb# | s3 |
03 | #a | aabb# | s3 |
033 | #aa | bb# | s4 |
0334 | #aab | b# | r3,B->b,goto[3,B] |
0336 | #aaB | b# | r2,B->aB,goto[3,B] |
036 | #aB | b# | r2,B->aB,goto[0,B] |
02 | #B | b# | s4 |
024 | #Bb | # | r3,B->b,goto[2,B] |
025 | #BB | # | r1,S->BB,goto[0,S] |
01 | #S | # | acc |