编译原理 Compiler Principles 第五章...
Transcript of 编译原理 Compiler Principles 第五章...
纵观全局
• 语言的规约1:词法单元的模式(串接结构,一维线性结构);
词法单元的模式 → 正则表达式 → DFA → 词法分析程序;
• 语言的规约2:上下文无关类的语法(嵌套结构:树形结构);
语法规则 → 上下文无关文法 → 推导 → 语法分析程序
源程序 语法分析树;
• 语法分析树是逐步建立的,有过程。能否在语法分析树的结点
上记录一些信息,并借助于它来做一些想做的事情,比如翻译
(把源程序翻译成中间代码)?
语法分析程序
对语法分析的观察分析
• 语法分析树是逐步建立的,体现在LL分析中,每展开一个非终
结符,在LR分析中,每规约一次。能否在语法分析树的结点上
记录一些信息,并借助于它来做一些想要的事情,比如翻译
(把源程序翻译成中间代码)?
• 自顶向下的语法分析:对词法流从左到右逐一扫描,来选择产
生式,形成一颗语法树;每选一次产生式,树就增大一次;
• 自底向上的语法分析:对词法流从左到右逐一扫描,来选择产
生式来规约,每规约一次,树就增大一次;
什么叫语法制导的翻译
求表达式的值id1 + id2 *id3 【4 + 3 * 5】
文法:EE + E | E * E | id
E5
id3
+E1 E4
*E2 E3
id2
id1
E1= id1E2= id2E3= id3E4= E2* E3E5= E1 + E4
对于计算器的计算结果:
对于计算机执行的指令流:
19四者的语义相同
上下文无关文法引导语言的翻译
上下文无关文法中的非终结符号代表了语言的某类结构;
l 程序设计语言的结构由更小的结构组合而成
l 一个结构的语义可以由小结构的含义综合而来;
比如:表达式x+y的类型由其x、y和运算符+决定。
l 可以由附近的结构继承而来
比如:对于变量声明:int x; x 的类型由它左边的类型决定。
观察与分析——自底向上语法分析的特性
id + id * id输入串:
EE + E E E * E E id
归约的过程就是树的形成过程,也是计算
的过程(即翻译的过程)。
* E3
+E1
id
E2
id
id * E3
+E1 E4
E2
①
② ③
④
⑤
E5
+E1 E4
⑤
观察与分析——自底向上的语法分析
id1 + id2 *id3:4+3*5 EE + E | E * E | id
E5
id3
+E1 E4
*E2 E3
id2
id1
E1.val=id1.val =4
E2.val=id2.val =3
E3.val=id3.val =5
E4.val=E2.val *E3.val=15
E5.val=E1.val *E4.val=19
①
②
③
⑤
④
归约的过程就是树的形成过程,也是计算的过程,也是翻译的过程。
归纳与总结——提升成知识和理论
id1 + id2 *id3:4+3*5 EE + E | E * E | id
E5
id3
+E1 E4
*E2 E3
id2
id1
E1.val=id1.val =4
E2.val=id2.val =3E3.val=id3.val =5
E4.val=E2.val *E3.val=15
E5.val=E1.val +E4.val=19①
②
③
⑤
④
产生式 语义规则
1)EE1 + E2 2)EE1 * E2 3)E id
E.val =E1.val +E2.valE.val =E1.val +E2.valE.val =id.val
语法制导定义(SDD):l 上下文无关文法;l 属性;l 规则;
进一步对知识和理论进行观察分析
E5
id3
+E1 E4
*E2 E3
id2
id1
E1.val=4
E2.val=3E3.val=5
E4.val=15
E5.val=19
①
②
③
⑤
④
产生式 语义规则
1)EE1 + E2 2)EE1 * E2 3)E id
E.val =E1.val +E2.valE.val =E1.val +E2.valE.val =id.val
语法制导定义(SDD):l 上下文无关文法;l 属性;l 规则;
实例
S属性的语法制导定义
定义
综合属性:(synthesized attribute)一个结点的属性值由它的子节点而来;
语法制导定义(SDD)
文法由产生式构成,语法制导定义中的定义是指:
• 定义文法的非终结符的属性;
• 产生式表达了非终结符的构成关系,一个产生式中的非终结
符的属性,它们彼此之间存在联系(即规则来刻画联系);
• SDD是上下文无关文法和属性/规则的结合;
– 属性和文法符号相关联
– 规则和产生式相关联;
观察与分析——自顶向下语法分析
T T *F | F F id
一个运算式( id1 * id2)由运算符*,和两个分量(id1 , id2)构成;
对于T' *FT1',它自然包含了一个运算式,做如下布局:左分
量在T'上, 右分量自然是F,运算符是*,结果放在T1'上。
T FT'T' *FT1' T' F id
id1 * id2* id3输入串:
T
F T'
F1* T'1
id2
id1④ ⑤
③
①
②
* T'2Fid3
⑥ ⑦
自顶向下语法分析的SDD观察分析
T T *F | F F id
T2’,意思是空运算,表示收尾了。
现在最终的结果在T2'上,要把它传回到根节点T上,于是,最右
的结点链T, T',T1', T2'都还要带有一个综合属性;
T FT'T' *FT1' T' F id
id1 * id2* id3输入串:
T
F T'
F1* T'1
id2
id1④ ⑤
③
①
②
* T'2Fid3
⑥ ⑦
自顶向下语法分析的SDD例子
id1 * id2* id3输入串:
T
F T'
F1* T'1
id2
id1④ ⑤
③
①
②
* F3
id3
T'2⑥ ⑦
synval
val
val
syn
syn
inh
inh
inh
val
val val
val
文法的非终结符的属性定义
自顶向下语法分析的SDD
语法分析树中结点的属性的值的求解过程。
id1 * id2* id3输入串:
T
F T'
F1* T'1
id2
id1
④
⑤
③
①
②
* F3
id3
T'2⑥
⑦
valval
val
val
val
val
inh
inh
inh
val
val val
val
⑩
⑨
⑧
自顶向下语法分析的SDD例子:4*2*3T
F T'
F1* T'1
id2
id1
④
⑤
③
①
②
* F3
id3
T'2⑥
⑦
synval
val
val
syn
syn
inh
inh
inh
val
val val
val
⑩
⑨
⑧
产生式 语义规则1)TFT' 2)T'*FT1' 3)T'4)Fid
T'.inh = F.val, T.val = T'.synT1'.inh = T'.inh * F.val, T’.syn= T1’.synT’.syn= T’.inhF.val =id.val
文法的非终结符的继承属性T
F T'
F1* T'1
id2
id1
④
⑤
③
①
②
* F3
id3
T'2⑥
⑦
synval
val
val
syn
syn
inh
inh
inh
val
val val
val
⑩
⑨
⑧
产生式 语义规则
2)T'*FT1' T1'.inh = T'.inh * F.val, T’.syn= T1’.syn
文法:非终结符T’的属性inh的值由T’的父结点,T’的兄弟,以及自己,这三者的属性值来计算确定 继承属性。
注释语法分析树(annotated parse tree)
T
F T'
F1* T'1
id2
id1
* F3
id3
T'2
syn=24val=4
val=4
val=24
syn=24
syn=24
inh=4
inh=8
inh=24val=2
val=2 val=3
val=3
显示出了各结点的属性的值的语法分析树
依赖图——SDD的求值顺序
T
F T'
F1* T'1
id2
id1
* F3
id3
T'2
synval
val
val
syn
syn
inh
inh
inh
val
val val
val
依赖图:语法分析树中的各结点的属性的求值顺序
依赖图的拓扑排序:id1,F,T'.inh, id2, F1, T1'.inh, ......
SDD: 文法和 目标(此例为表达式求值)
SDD
产生式 语义规则
1)SE
2)EE1 + T
3)ET
4)TT1 * F
5)TF
6)F (E)
7)F id
S.val =E.val
E.val =E1.val+T.val
E.val =T.val
T.val =T1.val*F.val
T.val =F.val
F.val =E.val
F.val =id.val
LR分析,规约时发生;只有S属性, 直观,简洁
为了LL分析,对文法消左递归
E→ E1 + T E→ T T→ T1 * F T→ F F→ (E) F→ id
E→ TE'E' → +TE' E' → εT→ FT'T'→ * F T'T'→ εF→ (E)F→ id
消左递归
引入了两个非终结符E', T'
消左递归后, 文法的SDD
产生式 语义规则
1)ETE' 2)E‘+TE1'3)E'4)TFT' 5)T'*FT1' 6)T'7)F(E)8)Fid
E'.inh = T.val, E.val = E'.synE1'.inh = E'.inh +T.val, E’.syn= E1’.synE’.syn= E’.inhT'.inh = F.val, T.val = T'.synT1'.inh = T'.inh * F.val, T’.syn= T1’.synT’.syn= T’.inhF.val =E.valF.val =id.val
E', T'是为消左递归而引入的, 既有综合属性,也有继承属性;
E,T,F,是原有的非终结符,只有综合属性
概念S属性的SDD:每个属性都是综合属性;
L属性的SDD:其属性是:综合属性,或者是继承属性的
子集:由父结点,左兄弟结点,自己的属性来确定。
产生式 语义规则
1)EE1 + E2 2)EE1 * E2 3)E id
E.val =E1.val +E2.valE.val =E1.val +E2.valE.val =id.val
产生式 语义规则
1)TFT' 2)T'*FT1' 3)T'4)Fid
T'.inh = F.val, T.val = T'.synT1'.inh = T'.inh * F.val, T’.syn= T1’.synT’.syn= T’.inhF.val =id.val
SDD的应用1——实现一个计算器
产生式 语义规则0)SE1)EE1 + E2 2)EE1 * E2 3)E id
{ print(E.val) }E.val =E1.val +E2.valE.val =E1.val +E2.valE.val =id.val
产生式 语义规则0)ST1)TFT' 2)T'*FT1' 3)T'4)Fid
{ print (T.val) }T'.inh = F.val, T.val = T'.synT1'.inh = T'.inh * F.val,T’.syn= T1’.synT’.syn= T’.inhF.val =id.val
应用2——生成抽象语法树的SDD
抽象语法树的构造
产生式 语义规则
1)E→ E1 + T 2)ET 3)TT1 * F4)TF5)F→ (E)6)F→id
E.node = new Node('+', E1.node, T.node)E.node =T.nodeE.node = new Node('*', T1.node, F.node)T.node = F.nodeF.node = E.nodeF.node = new Leaf(id, id.entry)
我们走到哪儿了?
给定上下文无关文法G,在第四章,解决了的问题:
lG是不是LL(1)文法, 是不是LR(1)文法的问题;
l文法 LL文法的预测分析表,LR文法的语法分析表 语法分
析器源程序生成工具;
语义分析,中间代码的生成,不是独立的环节,而是在语法分析
的过程中(LL分析中的展开,LR分析中的规约,)附带完成;
第五章, 在文法的产生式上加上动作,构造SDT。有了SDT,语
法分析,语义分析,中间代码生成,这三个工作的源程序就可由
语法分析器生成工具来自动得到;
复习
Syntax Directed Definition (SDD):文法 + 目标 属性,规
则
S属性:对于一个产生式,头部非终结符的属性值,由产生式体中
的符号的属性值决定,体现在规则上;
Syntax Directed Transaction Scheme (SDT):以LL(1)分析,
或LR(1)分析,基于栈的实现机制,通过设置动作来完成目标;
l S属性,继承属性,L属性;
l 注释语法分析树,抽象语法分析树;
① EE+E
② EE*E
③ E(E)
④ Eid
I0E'→EE→ E + E E→ E*EE→ (E) E→ id
I3E→ id
I1E'→EE→ E + EE→ E*E
I4E→ E + E E→ E + E E→ E*EE→ (E) E→ id
I7E→ E + E E→ E + EE→ E*E
I5E→ E*E E→ E + E E→ E*EE→ (E) E→ id
I8E→ E * E E→ E + EE→ E*E
E + E
* E
I2F→ (E) E→ E + E E→ E*EE→ (E) E→ id
I6F→ (E )E→ E + EE→ E*E I9
E→ (E)
id
id
(
(
(
id
id
*
E
)(
$Accept
+
*
+
*
+
LR分析中基于栈的SDT实现,以为表达式求值这个目标为例
ACTION:移入, 归约
规约时做翻译;
① EE+E ② EE*E ③ E(E) ④ Eid
LLR分析中基于栈的SDT实现,以id+id*id为例 (4+3*5)
E1.s=4E1id E1
+
id
E1
+E2
E1
+E2
*
id
E1
+E2
*
E3
E1
+E4
E5
翻译目标为求值
E2.s=3 E3.s=5E4.s=15
E5.s=19
① EE+E ② EE*E ③ E(E) ④ Eid
LR分析中基于栈的SDT实现:目标为生成中间代码,以id+id*id为例 (4+3*5)
t1=id1
E1id E1
+
id
E1
+E2
E1
+E2
*
id
E1
+E2
*
E3
E1
+E4
E5
翻译目标为生成中间代码
t2=id2 t3=id3t4=t2*t3
t5=t1+t4
本质:通
过栈缓存
来实现了
顺序调转
LR分析中文法的SDD
目标:求表达式的值。规约时,做翻译
产生式 语义规则
1)E→ E1 + E2 3)EE1 * E2
5)E→ (E1)6)E→id
E.val = E1.val+ E2.valE.val = E1.val * E2.valE.val = E1.valE.val = id.val
LR分析中的SDT
求表达式的值的SDT,规约时,执行动作,而且是先翻译,后规约
语义动作
1)E→ E1 + E2 { E.val = E1.val+ E2.val }2)EE1 * E2 { E.val = E1.val * E2.val }3))E→ (E1) {E.val = E1.val }4)E→id { E.val = id.val }
就LR文法, 由SDD到SDT非常简单、直观
SDD
产生式 语义规则
1)SE
2)EE1 + T
3)ET
4)TT1 * F
5)TF
6)F (E)
7)F id
S.val =E.val
E.val =E1.val+T.val
E.val =T.val
T.val =T1.val*F.val
T.val =F.val
F.val =E.val
F.val =id.val
语义动作
1)SE { print E.val }2)EE1 + T { E.val =E1.val+T.val }3)ET { E.val =T.val }4)TT1 * F { T.val =T1.val*F.val }5)TF { T.val =F.val }6)F (E) { F.val =E.val }7)F id { F.val =id.val }
后缀SDT
LR分析,规约时发生;只有S属性, 直观,简洁
为了LL分析,对文法消左递归
E→ E1 + T E→ T T→ T1 * F T→ F F→ (E) F→ id
E→ TE'E' → +TE' E' → εT→ FT'T'→ * F T'T'→ εF→ (E)F→ id
消左递归
引入了两个非终结符E', T'
消左递归后, 文法的SDD
产生式 语义规则
1)ETE' 2)E‘+TE1'3)E'4)TFT' 5)T'*FT1' 6)T'7)F(E)8)Fid
E'.inh = T.val, E.val = E'.synE1'.inh = E'.inh +T.val, E’.syn= E1’.synE’.syn= E’.inhT'.inh = F.val, T.val = T'.synT1'.inh = T'.inh * F.val, T’.syn= T1’.synT’.syn= T’.inhF.val =E.valF.val =id.val
E', T'是为消左递归而引入的, 既有综合属性,也有继承属性;
E,T,F,是原有的非终结符,只有综合属性
消左递归后,文法的SDT
E→ T { E'.inh = T.val } E' { E.val = E'.syn}E' → +T { E1'.inh = E'.inh + T.val } E' {E’.syn= E1’.syn}
E' → ε {E’.syn= E’.inh}
T→ F { T'.inh = F.val } T' { T.val = T'.syn}
T'→ * F{ T1'.inh = T'.inh * F.val } T1' {T’.syn= T1’.syn}
T'→ ε {T’.syn= T’.inh }
F→ (E) {F.val= E.val}
F→ id { F.val= E.val }
这个SDT是基于LL分析,而构思出来的。怎么构思?看下文分解
LL语法分析实现翻译的过程同一案例id+id*id(4+3*5)
E
id
+
T E'
*
T1
F2
F T'
id ε F1 T1'
id
E1'
ε
T2'
ε
每棵树(子树)的
最右边的结点链
路是综合之路。
即处理累积到最
右的叶节点。
从左到右:先继
承,后综合
③
①
②④
⑤
⑥
⑦
⑧
⑨
⑩ 12
13
1415
16
17
18
11
观察:LL语法分析实现翻译的特点
E
id
+
T E'
*
T1
F2
F T'
id ε F1 T1'
id
E1'
ε
T2'
ε
E', T'是为消左递归而
引入的两个非终结符,
既有综合属性,也有
继承属性;
E,T,F,是原有的非终
结符,只有综合属性
③
①
②④
⑤
⑥
⑦
⑧
⑨
⑩ 12
13
1415
16
17
18
11
LL分析中基于栈的SDT实现:将SDT倒着入栈。同一案例id+id*id(4+3*5
E.synE
E→ T { E'.inh = T.val } E' { E.val = E'.syn}
E.syn { E.val = E'.syn}
E’ 和 E'.inhE'.syn
{E'.inh = T.val}
TT.val
展开
T'id ε
E
TF
id* F
F
id
+ T1
E'
T1'E1'ε
T2'ε
按照SDT倒着入栈
T→ F { T'.inh = F.val } T' { T.val = T'.syn}
展开展开时,综合属性保留
id ε
E
T E'F T'
T
E.val { E.val = E'.syn}
E’ 和 E'.inhE'.syn
{E'.inh = T.val}T.val
{ T.val = T'.syn}
T'和T'.inhT'.syn
{ T'.inh = F.val}
FF.val
E.val { E.val = E'.syn}
E’ 和 E'.inhE'.syn
{E'.inh = T.val}T.val
F→ id {F.val= E.val}
展开
id ε
E
T E'F T'
{ T.val = T'.syn}
T'和T'.inhT'.syn
{ T'.inh = F.val}
FF.val
E.val { E.val = E'.syn}
E’ 和 E'.inhE'.syn
{E'.inh = T.val}T.val
{ F.val = id.val}id.val
{ T.val = T'.syn}
T'和T'.inhT'.syn
{ T'.inh = F.val}F.val
E.val { E.val = E'.syn}
E’ 和 E'.inhE'.syn
{E'.inh = T.val}T.val
弹栈
观察:
栈顶不为非终结符时:
1)匹配输入串;
2)执行栈顶的操作;
3)弹栈;
直到栈顶为非终结符
{ F.val = id.val}id.val=4
{ T.val = T'.syn}
T'和T'.inhT'.syn
{ T'.inh = F.val}F.val
E.val { E.val = E'.syn}
E’ 和 E'.inhE'.syn
{E'.inh = T.val}T.val
{ T.val = T'.syn}
T'和T'.inhT'.syn
{ T'.inh = F.val}F.val = 4
E.val { E.val = E'.syn}
E’ 和 E'.inhE'.syn
{E'.inh = T.val}T.val
继续弹栈
观察:
栈顶不为非终结符时:
1)匹配输入串;
2)执行栈顶的操作;
3)弹栈;
直到栈顶为为非终结符
{ T.val = T'.syn}
T'和T'.inhT'.syn
{ T'.inh = F.val}F.val= 4
E.val { E.val = E'.syn}
E’ 和 E'.inhE'.syn
{E'.inh = T.val}T.val
{ T.val = T'.syn}
T'和T'.inh= 4T'.syn
E.val { E.val = E'.syn}
E’ 和 E'.inhE'.syn
{E'.inh = T.val}T.val
观察
观察:
栈顶为非终结符
须展开:T'→ ε { T.val = T'.syn}
T'和T'.inh= 4T'.syn
E.val { E.val = E'.syn}
E’ 和 E'.inhE'.syn
{E'.inh = T.val}T.val
展开
{ T’.syn = T'.inh}
展开
id ε
E
T E'F T'
{ T.val = T'.syn}
T'和T'.inh= 4T'.syn
E.val { E.val = E'.syn}
E’ 和 E'.inhE'.syn
{E'.inh = T.val}T.val
{ T.val = T'.syn}T'.syn
E.val { E.val = E'.syn}
E’ 和 E'.inhE'.syn
{E'.inh = T.val}T.val
T'.inh
弹栈
{ T’.syn = T'.inh}
{ T.val = T'.syn}T'.syn
E.val { E.val = E'.syn}
E’ 和 E'.inhE'.syn
{E'.inh = T.val}T.val
T'.inh=4
{ T.val = T'.syn}T'.syn = 4
E.val { E.val = E'.syn}
E’ 和 E'.inhE'.syn
{E'.inh = T.val}T.val
观察:
栈顶不为非终结符,
执行栈顶的操作;
然后弹栈;
直到栈顶为为非终结
符
继续弹栈(1)
{ T.val = T'.syn}T'.syn = 4
E.val { E.val = E'.syn}
E’ 和 E'.inhE'.syn
{E'.inh = T.val}T.val
E.val { E.val = E'.syn}
E’ 和 E'.inhE'.syn
{E'.inh = T.val}T.val = 4
观察:
栈顶不为非终结符,
执行栈顶的操作;
然后弹栈;
直到栈顶为为非终结
符
继续弹栈(2)
E.val { E.val = E'.syn}
E’ 和E’.inhE'.syn
{E'.inh = T.val}T.val = 4
E.val { E.val = E'.syn}
E’ 和E’.inh = 4E'.syn
观察:
弹栈之后,现在栈顶
为非终结符,因此接
下来是展开操作
id ε
E
T E'F T'
展开
E' → +T { E1'.inh = E'.inh + T.val } E1' {E’.syn= E1’.syn}
有问题!!!
当在后面执行该操作时,E'.inh在栈中已经不存在了
+ T
EE'
E1'
E.val { E.val = E'.syn}
E1’和E1’.inh
E'.syn {E’.syn= E1’.syn}
E1'.syn
T
{E1'.inh = E'.inh + T.val}T.val
展开
E.val { E.val = E'.syn}
E’ 和E’.inh = 4E'.syn
+
E' → +T { E1'.inh = E'.inh + T.val } E1' {E'.syn= E1'.syn} 在操作上存在问题
弹栈展开
E.val { E.val = E'.syn}
E1’和E1’.inh
E'.syn {E’.syn= E1’.syn}
E1'.syn
T
{E1'.inh = E'.inh + T.val}T.val
E.val { E.val = E'.syn}
E1’和E1’.inh
E'.syn {E’.syn= E1’.syn}
E1'.syn
{E1'.inh = E'.inh + T.val}T.val
E.val { E.val = E'.syn}
E1’和E1’.inh
E'.syn {E’.syn= E1’.syn}
E1'.syn
{E1'.inh = E'.inh + T.val}T.val = 15
E' → +T { E1'.inh = E'.inh + T.val } E1' {E'.syn= E1'.syn} 应修改为
E' → { E1'.inh= E'.inh } +T { E1'.inh = E1'.inh + T.val } E1' {E’.syn= E1’.syn}
E.val { E.val = E'.syn}
E1’和E1’.inh
E'.syn {E’.syn= E1’.syn}
E1'.syn
T
{E1'.inh = E1'.inh + T.val}
T.val
展开
E.val { E.val = E'.syn}
E’ 和E’.inh = 4E'.syn
+{E1'.inh= E'.inh }
弹栈,然后匹配
E.val { E.val = E'.syn}
E1’和E1’.inh
E'.syn {E’.syn= E1’.syn}
E1'.syn
T
{E1'.inh = E1'.inh + T.val}
T.val
+{E1'.inh= E'.inh }
E.val { E.val = E'.syn}
E1’和E1’.inh = 4
E'.syn {E’.syn= E1’.syn}
E1'.syn
T
{E1'.inh = E1'.inh + T.val}
T.val
+
E.val { E.val = E'.syn}
E1’和E1’.inh = 4
E'.syn {E’.syn= E1’.syn}
E1'.syn
T
{E1'.inh = E1'.inh + T.val}
T.val
总结——基于LL分析的SDT动作特点
E' → { E1'.inh= E'.inh } +T { E1'.inh = E1'.inh + T.val } E1' {E’.syn= E1’.syn}
只能使用A的继承属性,修改左边的X,Y,Z的继承属性值
A →{ } X{ }Y{ }Z{ }
只能使用X的综合属性,修改左边的Y,Z的继承属性值
只能使用Y的综合属性,修改左边的Z的继承属性值
只能使用Z的综合属性,修改A的综合属性值
栈顶为非终结符,要展开
弹栈展开
E.val { E.val = E'.syn}
E1’和E1’.inh
E'.syn {E’.syn= E1’.syn}
E1'.syn
T
{E1'.inh = E'.inh + T.val}
T.val
E.val { E.val = E'.syn}
E1’和E1’.inh = 4
E'.syn {E’.syn= E1’.syn}
E1'.syn
{E1'.inh = E'.inh + T.val}T.val
E.val { E.val = E'.syn}
E1’和E1’.inh = 4
E'.syn {E’.syn= E1’.syn}
E1'.syn
{E1'.inh = E'.inh + T.val}T.val = 15
弹栈
弹栈
E.val { E.val = E'.syn}
E1’和E1’.inh = 4
E'.syn {E’.syn= E1’.syn}
E1'.syn
{E1'.inh = E'.inh + T.val}T.val = 15
E.val { E.val = E'.syn}
E1’和E1’.inh =19
E'.syn {E’.syn= E1’.syn}
E1'.syn
id* F
F
id
+ TE'
T'E1'ε
T'ε
栈顶为非终结符,要展开
E.val { E.val = E'.syn}
E1’和E1’.inh =19
E'.syn {E’.syn= E1’.syn}
E1'.syn
id* F
F
id
+ TE'
T'E1'ε
T'ε
E.val { E.val = E'.syn}
E'.syn {E’.syn= E1’.syn}
E1'.syn
{E1’.syn= E1’.inh}
E1'.inh = 19
栈顶不为非终结符,弹栈
E.val { E.val = E'.syn}
E'.syn {E’.syn= E1’.syn}
E1'.syn = 19
E.val { E.val = E'.syn}
E'.syn = 19
+ T
EE'
E1'
目标不同,SDD不同:LR分析中的SDT
求中间代码时的SDT,规约时,做翻译。而且是先翻译,后规约
语义动作
1) E→ E1 + E2 { E.addr = new temp(); genCode( E.addr '=' E1.addr '+' E2.addr ); }2) EE1 * E2 { E.addr = new temp(); genCode( E.addr '=' E1.addr '*' E2.addr); }3) E→ (E1) {E.addr = E1.addr }4) E→id { E.addr = new temp(); genCode( E.addr '=' id.addr; }
总结
l SDD是对文法,针对特定目标而来的。不同的目标,定义的
属性不同,规则也不同;
l 属性是指对着非终结符来的,规则是对着产生式来的;
l 文法,它可能不是LL的,因此就谈不上用LL分析来实现;
l 同理,文法可能不是LR的,因此就谈不上用LR分析来实现;
l 确定了SDD,然后就是用LL分析还是LR分析?SDT是一种
实施操作方案;
课程特点
课堂,仅只是取一个例子来点开视野,阐释特征、特点,策略
试验呢,则能见到整体,全貌。组合概念,课堂中没有提。
例如词法分析:keyword, variable, number, 数值/逻辑运算符,标点符号等等合到一起,构成一个综合完整的DFA。
语法分析也一样,课堂只是以表达式为例来阐释状态穷举。试验则要考虑语句,如赋值语句,申明语句,控制语句等,还有逻辑表达式,这些组合到一起形成一个很大的DFA。
试验一定要套知识点,套原则,如果没结合上,就等于0。
产生式 语义规则TBC
Bint BfloatC[num]C1
C
C.inh_t = B.t C.inh_w = B.wT.t = C.t, T.w = C.wB.t = integer, B.w=4B.t = float, B.w=8C1.inh_t = C.inh_tC1.inh_w = C.inh_wC.t = array(num, C1.t)C.t= C.inh_tC.w =C.inh_w
t
T
B C
C1int
inh
C2
[ 2 ]
[ 3 ]
syn
syninh
inh
syn
syn
下列文法不是LR的,因此就谈不上LR分析来实现, 只能是LL分析来实现
例, int [2][3] 类型表达式为 array(2, array(3,integer)
LL分析中,SDD可行,但是在实施操作中遇到了问题
产生式 语义规则
TBC
Bint Bfloat
C[num]C1
C
C.inh_t = B.t C.inh_w = B.wT.t = C.t, T.w = C.w
B.t = integer, B.w = 4B.t = float, B.w = 8
C1.inh_t = C.inh_tC1.inh_w = C.inh_wC.t = array(num, C1.t)
C.t = C.inh_tC.w =C.inh_w
问题:2在求C的综合属性t时用到,但此时已经不在栈里了
t
T
B C
C1int
inh
C2
[ 2 ]
[ 3 ]
syn
syninh
inh
syn
syn
对LL分析中遇到的上述问题,其解决办法
对于C[num]C1,中的num,其特点:只有规约(即求C的综合属性)时用到,并不须要下传。 处理办法是最右端加一个非终结符S,它只有继承属性,其产生式为S,无动作。
1)TBC2)Bint 3)Bfloat4)C[num]C1
5)C
1)TBC2)Bint3)Bfloat4)C[num]C1S5)C S
对LL分析中遇到的问题的解决办法——在产生式中新加一个非终结符
1)TB{C.inh_t = B.t; C.inh_w = B.w;} C { T.t = C.t; T.w = C.w; }
2)Bint {B.t= integer; B.w = 4; }
3)Bfloat {B.t= float; B.w = 8; }
4)C{ C1.inh_t = C.inh_t; C1.inh_w = C.inh_w; } [num {S.inh= num; } ] C1 { C.t = array(S.inh, C1.t); C.w =S.inh* C1.w } S
5) C {C.t = C.inh_t; C.w = C.inh_w; } 6)S
当S变成栈顶时,要弹出它,然后用它的产生式的右部倒着压入栈
中,现在S,而且这个产生式中没有动作。即S直接出栈。
同一内容,其LL文法与LR文法是不一样的
例如,int [2][3] 的类型表达式为array(2, array(3,integer))
1)TBC 2)Bint 3)Bfloat 4)C C1[num]5)C [num]
1)TBC2)Bint 3)Bfloat4)C[num]C1
5)C
LL文法 LR文法
注意:LR文法中,允许左递归,不允许出现C 之类的产生式; LL文法中,不允许左递归,允许C
LR分析中的语法分析树
例如,int [2][3] 的类型表达式为array(2, array(3,integer))
T
B
int C
[ 2 ]
C
[ 3 ]
1)TBC 2)Bint 3)Bfloat 4)C C1[num]5)C [num]
观察:LR分析中,在规约出C时,B在栈中
LR文法
在LR分析中的 SDT
例如,int [2][3] 的类型表达式为array(2, array(3,integer))
1) TBC { T.t = B.t; T.w = B.w; while(int i=C.Stack ->pop() ) { B.t = array(i, B.t); T.w = T.w* i; } delete C.Stack; AddType(id, T.t, T.w); }2) Bint { B.t = integer; B.w = 4 } 3) Bfloat { B.t = float; B.w = 8 } 4) C C1[num] { C.Stack = C1.Stack; C.Stack ->push(num); }5) C [num] { C.Stack = new stack(); C.Stack ->push(num); }
在LR分析中的 SDT
例如,int [2][3] 的类型表达式为array(2, array(3,integer))
1) TBC { T.t= B.t; T.w= B.w; while(int i=s.pop()) { B.t = array(num, B.t); T.w=T.w* i; } delete s; AddType(id, T.t, T.w); } }
2) Bint { B.t = integer; B.w = 4 }
3) Bfloat { B.t = float; B.w = 8 }
4) C C1[num] { s.push(num); }
5) C [num] { s = new stack(); s.push(num); }
s是一个全局变量,该方案可行吗?
LL分析中,展开/弹栈/执行代码/匹配的具体实现
C{ C1.inh_t = C.inh_t; C1.inh_w = C.inh_w; } [num {S.inh= num; } ] C1 { C.t = array(S.inh, C1.t); C.w =S.inh* C1.w } S
当前输入符为a;
C.syn
{ C1.inh_t = C.inh_t; C1.inh_w = C.inh_w;}
S和S.inh = 4
]
{C.t = array(S.inh, C1.t); C.w =S.inh* C1.w}
C1.syn
{S.inh= num;}
num.val
C1和C1.inh
[
栈中元素的数据结构——分为四个类别
class node { int type ; int id; void * content);
type: 代码;非终结符和继承属性;非终结符的综合属性; 终结符
每段代码有标识符id;
非终结符也有标识符id;
终结符也有标识符id; C.syn
{ C1.inh_t = C.inh_t; C1.inh_w = C.inh_w;}
S和S.inh = 4
]
{C.t = array(S.inh, C1.t); C.w =S.inh* C1.w}
C1.syn
{S.inh= num;}
num.val
C1和C1.inh
[
栈顶元素为代码结点的处理——执行
switch (cur_element. type) { case 'CODE': switch(cur_element. id) { case 20: break;
例:{'C', 20, null}
elment[pos -5].inh.t = node.inh.t;elment[pos -5].inh.w = node.inh.w;pop( );
C.syn
{ C1.inh_t = C.inh_t; C1.inh_w = C.inh_w;}
S和S.inh = 4
]
{C.t = array(S.inh, C1.t); C.w =S.inh* C1.w}
C1.syn
{S.inh= num;}
num.val
C1和C1.inh
[
栈顶元素为非终结符的处理——展开
switch (cur_element. type) { case 'EXTEND': switch(cur_element. id) { case 'C': cur_node = pop(); if (a==$) 按 C 展开 else 按 C[num] C展开; break;
C.syn S和S.inh = 4
{C.t = array(S.inh, C1.t); C.w =S.inh* C1.w}
C1.syn C1和C1.inh
push(new node(‘CODE’, code_id ));push(new node(’EXT', 'C', cur_node));push(new node('CSYM', ']' ));push(new node(‘CODE’, 21));push(new node('CSYM', 'num' )); ......
栈顶元素为非终结符综合属性的处理——下沉,至代码元素或非终结符元素
switch (cur_element. type) { case ' SYN' : while (cur_element. type == 'SYN') cur_element = cur_element. next; break;
C.syn S和S.inh = 4
{C.t = array(S.inh, C1.t); C.w =S.inh* C1.w}
C1.syn
elment[pos -2].syn.t = array(elment[pos -1].inh, elment[pos +1].syn.t); elment[pos -2].syn.w = elment[pos -1].inh * elment[pos +1].syn.w);pop( ); pop();
栈顶元素为终结符的处理——匹配,或对其综合属性赋值
switch (cur_element. type) { case 'CONST_SYMBOL':
if (cur_element.id = 'ID' ) cur_element. addr = position(a);else if (cur_element.id = 'NUM' ) cur_element. val = a;else if(a != cur_element.symbol ) 报错pop( );
C.syn S和S.inh = 4
]
{C.t = array(S.inh, C1.t); C.w =S.inh* C1.w}
C1.syn
{S.inh= num;}
num.val
C1和C1.inh
[
语法制导翻译方案SDT
语法制导翻译方案(Syntax directed traslation Scheme)是
在上下文无关文法的产生式体中嵌入程序片断(语义动作),
表达联系的发生时刻;它与分析方法(LL,LR)相关联;
SDT的最直观实现方法:
建立语法分析树;
从左到右、深度优先地执行这些动作;
可用SDT来实现SDD:
基本文法是LR的,SDD是S属性的
基本文法是LL的,SDD是L属性的
LR分析中的SDT例子
SDD
产生式 语义规则
1)SE
2)EE1 + T
3)ET
4)TT1 * F
5)TF
6)F (E)
7)F id
S.val =E.val
E.val =E1.val+T.val
E.val =T.val
T.val =T1.val*F.val
T.val =F.val
F.val =E.val
F.val =id.val
语义动作
1)SE { print E.val }2)EE1 + T { E.val =E1.val+T.val }3)ET { E.val =T.val }4)TT1 * F { T.val =T1.val*F.val }5)TF { T.val =F.val }6)F (E) { F.val =E.val }7)F id { F.val =id.val }
后缀SDT
LR分析,规约时发生;只有S属性, 直观,简洁
LR分析中的SDT实例——实现计算器
发现:实现S属性的SDD
语义动作在每次规约时执行。并不须要先建立语法树,再执行
scheme。
E
id3
+E1 T1
id1 + id2 *id3
*T2 F2
F1
id2
T
F
id1
语义动作
1)SE { print E.val }2)EE1 + T { E.val =E1.val+T.val }3)ET { E.val =T.val }4)TT1 * F { T.val =T1.val*F.val }5)TF { T.val =F.val }6)F (E) { F.val =E.val }7)F id { F.val =id.val }
语法分析树
SDT中的语义动作在产生式中的位置
产生式 语义规则1)TFT' 2)T'*FT1' 3)T'4)Fid
T'.inh = F.val, T.val = T'.synT1'.inh = T'.inh * F.val,T’.syn= T1’.synT’.syn= T’.inhF.val =id.val
SDT:还表达了执行的时期
SDD:仅只表达了逻辑关系
1)TF { T'.inh = T.val } T' { T.val = T'.syn}2)T'*F { T1'.inh = T'.inh * F.val } T1' {T’.syn= T1’.syn}3)T' { T’.syn= T’.inh }4)Fid { F.val =id.val }
在LL分析中,进栈和弹栈规则 继承属性的值传递动作可能要做位置调整
1)TF { T'.inh = T.val } T' { T.val = T'.syn}2)T'*F { T1'.inh = T'.inh * F.val } T1' {T’.syn= T1’.syn}3)T' { T’.syn= T’.inh }4)Fid { F.val =id.val }
2)T'{ T1'.inh = T'.inh} * F { T1'.inh = T1'.inh * F.val } T1' {T’.syn= T1’.syn}
SDT中的语义动作在产生式中的位置
• 对于产生式:BX{a}Y
• LR分析时,a在X出现在栈顶时执行
• LL分析时,在试图展开Y或者在输入中检测到Y时执行a
不是所有的SDT都可以在分析过程中实现
例如,E { print('+') } E1 + T,
E T
在LR分析中,就不行。因为在起始时刻,E1 都还未规约出来,
E1后面的'+'就更不知道是否存在;
消左递归时S属性在SDT中的处理
对 EE | β消左递归:
E βE'
E' E' |
例如:对EE + T | T,消左递归:
ETE' E' +TE' |
语义动作
EE1 + T { E.val =E1.val + T.val }ET { E.val =T.val }
语义动作1)ET { E'.inh = T.val } E' { E.val = E'.syn}2)E'+T { E1'.inh = E'.inh + T.val } E1' {E’.syn= E1’.syn}3)E' {E’.syn= E’.inh}
消左递归时S属性SDT的处理
E
+E1 T1
T
E
T E'
T1+ E'1
④
⑤
③
①
②
synval
val
syn
inh
inhval
1)ET { E'.inh = T.val } E' { E.val = E'.syn}2)E'+T { E1'.inh = E'.inh + T.val } E1' {E’.syn= E1’.syn}3)E' {E’.syn= E’.inh}
EE1 + T { E.val =E1.val + T.val }ET { E.val =T.val }
含左递归,适合LR分析
消除左递归,适合LL分析
消左递归时S属性在SDT处理中的通用化
A
A1 Y
X
A
X R
Y R1
④
⑤
③
①
②
ss
a
s
i
i
A X { R.i = f(X.s) } R {A.a = R.s}R Y { R1.i = g(R.i, Y.s) } R1 { R.s = R1.s }R ε { R.s = R.i }
AA1Y { A.a = g(A1.a, Y.s) }AX { A.a = f(X.s) }
含左递归,适合LR分析
消除左递归,适合LL分析
s
消左递归时SDT的转换(2)
• 如果动作不涉及属性值,则将动作当作是终结符进行处理
例如,原始的产生式
– E E1+T { print(‘+’) }
– E T
• 转换后得到:
– E T E'
– E' + T {print (‘+’)} E'
– E' ε
SDT在语法分析过程中的实现
• 两类SDT:实现S属性的SDD(后缀SDT),实现L属性的SDD;
• 两类语法分析:LR分析, LL分析;
S属性的SDD LL分析
L属性的SDD LR分析
L属性包含了S属性,因此只要解决L属性,即解决了所有。
SDT中的消左递归的例子
E→ E1 + T
E→ T
T→ T1 * F
T→ F
F→ (E)
F→ id
E→ TE'E' → +TE'
E' → ε
T→ FT'
T'→ * F T'
T'→ ε
F→ (E)
F→ id
消左递归
增加了两个非终结符E',T'
消左递归后SDT的变化
E→ E1 + T { E.val =E1.val + T.val }E→ T { E.val =T.val }T→ T1 * F { T.val =T1.val * F.val }T→ F { T.val =F.val }F→ (E) { F.val =E.val }F→ id { F.val =id.val }
E→ T { E'.inh = T.val } E' { E.val = E'.syn}E' → +T { E1'.inh = E'.inh + T.val } E' {E’.syn= E1’.syn}E' → ε {E’.syn= E’.inh}T→ F { T'.inh = F.val } T' { T.val = T'.syn}T'→ * F{ T1'.inh = T'.inh * F.val } T1' {T’.syn= T1’.syn}T'→ ε {T’.syn= T’.inh}F→ (E) {F.val= E.val}F→ id {F.val= E.val}
两种语法分析的过程对比
E
id
+T E'
*
T
F
F T'
id ε F T'
id
E1'ε
T'ε
自顶向下分析(LL分析)
语法分析树(8次规约)
E
id
+E T
id1 + id2 *id3
*T F
F
id
T
F
id
自底向上分析(LR分析)语法分析树(11次展开)
在语法分析的过程中,完成语义分析和中间代码生成两项工作
三地址中间代码表:
row_id tag code goto src_row_id1 L1: i = j + k
2
3
nextInstr
语法分析中通过栈缓存来实现了顺序调换,使得中间代码的生成具
有只增不插的特点。
LL分析中实现控制语句翻译的框架——例1
产生式:S while(B) S1
B
S1
L1
L2
S.nextL1: if ( B ) goto L2 goto B.falseL2: S1.code goto L1
S.next:
S.code=L1 : || B.code || L2: ||S1.code || goto L1 || S.next:
继承属性:S.nextB.false=S.next;B.true = newLabel();
综合属性:S.code;B.code;
LL分析中实现控制语句翻译的SDT——例1
产生式:S while (B) S1
while ( { begin = newLabel(); B.true=
newLabel(); B.false = S.next;S1.next= begin; Y. label = B.true; Z.Label= begin;
AddLabel( begin ':'); } B )
{AddLabel( Y.Label ':'); } Y S1 { gen(' goto' Z.Label); } ZY ; Z
产生式:S while ( B ) Y S1 Z
c=20L0: if (c>10) goto L1
goto L2
L1: c=c-1 goto L0
L2: x=1
LL分析中实现控制语句翻译的SDT——例2
产生式:S if (B) S1 else S2
S.code=B.code ||L1: || S1.code || goto S.next|| L2: || S2.code|| S.next:
B
S1L1
L2
S.nextS2
if ( B ) goto L1 goto L2
L1: S1.code goto S.nextL2: S2.codeS.next:
继承属性:S.nextB.false=newLabel();B.true =newLabel();
综合属性:S.code;B.code;
程序例子2
c=20;if (a>b)
d=x+y;else
d=x*y x=1
c=20 if(a>b) goto L3
goto L4
L3: d=x+y goto L5
L4: d=x*yL5: x=1
LL分析中实现控制语句翻译的SDT——例2
产生式:S if (B) S1 else S2
if ( { B.true= newLabel(); B.false =
newLabel();S1.next= S.next; S2.next= S.next; Y. label = B.true; Z.Label= B.false;
Z.nextLabel =S.next; W. label = S.next; }
B) {AddLabel( Y.Label ':'); } Y S1 else
{ gen(' goto' Z.nextLabel); AddLabel( Z.Label ':'); } Z S2
AddLabel( W.Label ':'); }Y ; Z ; W
产生式:S if ( B) Y S1 else Z S2 W
c=20 if(a>b) goto L3
goto L4
L3: d=x+y goto L5
L4: d=x*yL5: x=1
在LL分析中,布尔表达式的翻译
c=20;if (a>b) d=x+y; x=1
c=20 if(a>b) goto L3
goto L5
L3: d=x+yL5: x=1
产生式:S if (B)S1
S.code=B.code ||L3: || S1.code || L5:
三个非终结符:S,B,S1
继承属性:S.next
B.false=S.next;B.true =newLabel();
S1.next=S.next;
在LL分析中,布尔表达式的翻译
c=20;if (a>b) d=x+y;else
d=x*y x=1
c=20 if(a>b) goto L3
goto L4
L3: d=x+y goto L5
L4: d=x*yL5: x=1
产生式:S if (B)S1 else S2
S.code=B.code ||L1: || S1.code || goto S.next|| L2: || S2.code|| S.next:
四个非终结符:S,B,S1, S2
继承属性:S.next
B.false=newLabel();B.true =newLabel();
S1.next=S.next;S2.next=S.next;
在LL分析中,布尔表达式的翻译
c=20;while (a>b) b=x+y; x=1
c=20L0: if(a>b) goto L3
goto L4
L3: b =x+y goto L5
L4: x=1
产生式:Swhile (B)S1
S.code=L1: || B.code || L3: ||S1.code || goto S1.next|| S.next:
三个非终结符:S,B,S1
继承属性:begin= newLabel();S.next
B.false=S.next;B.true =newLabel();
S1.next=begin;
翻译布尔表达式B的SDD
产生式 语义规则
BE1 rel.op E2 B.code =E1.code || E2.code
|| gen('if' E1.addr rel.op E2.addr 'goto' B.true)
|| gen('goto' B.false)
在LL分析中,布尔表达式的翻译
• if (x > 200 && x!= y) x = 0;
将其视作:if (B1 && B2) x = 0;
三地址码如下:
if x > 200 goto L2
goto L3
L2: if x != y goto L4
goto L3
L4: x=0
L3:
BB1 && B2
B1
B2
继承属性:
B1.true =newLabel(); B1.false = B.false;B2.true =B.true; B2.false = B.false;
翻译布尔表达式的SDD
产生式 语义规则
BB1 && B2 B1.true = newlabel( );
B1.false = B.false;
B2.true = B.true;
B2.false = B.false;
B.code =B1.code || label (B1.true) || B2.code
注意:该文法不是LL文法,因产生式含左递归。
SDD仅只表达了逻辑关系,不是SDT。
在LL分析中,布尔表达式的翻译
• if (x > 200 || x!= y) x = 0;
将其视作:if (B1 || B2) x = 0;
三地址码如下:
if x > 200 goto L4
goto L5
L5: if x != y goto L4
goto L3
L4: x=0
L3:
BB1 || B2
B1
B2
继承属性:
B1.true =B.true; B1.false = newLabel();
B2.true =B.true; B2.false = B.false;
在LL分析中,翻译布尔表达式的SDD
产生式 语义规则
BB1 && B2 B1.true = B.true;
B1.false = newlabel( );
B2.true = B.true;
B2.false = B.false;
B.code =B1.code || label (B1.false) || B2.code
注意:该文法不是LL文法,因产生式含左递归。
SDD仅只表达了逻辑关系,不是SDT。
在LL分析中,布尔表达式的翻译例子
• if (x<100 || x > 200 && x!= y) x = 0; 优先级:先&&, 后 ||
if x < 100 goto L2
goto L3
L3: if x >200 goto L4
goto L1
L4: if x != y goto L2
goto L1
L2: x=0
L1:
S.next = L1; B.true =newLabel() = L2; B.false = S.next = L1;
B1.true =B.true = L2; B1.false =newLabel() = L3;B2.true =B.true = L2; B2.false = B.false = L1;
B2.1.true =newLabel() = L4; B2.1.false = B2.false = L1; B2.2.true = B2.true = L2; B2.2.false = B2.false = L1;
三地址码如下:
LL语法分析中程序文法的表达
P S ① S if (B) S T T else S | ③ S id = E ④ S while(B) S ⑤ S T id⑥ S {L} LSL L
E E+E | E*E | (E) | id B B && B | B || B | (B) | E > E | id | true | false
程序if语句
赋值语句while语句变量定义语句语句序列
当前输入符为 } 或者$, 选择L
程序例子
c=0;while(c>10) {
c=c-1;if (a>b) then {
d=x+y; } else { d=x*y; }
}x=1
c=0L0: if (c>10) goto L1
goto S(while).nextL1: c=c-1 if(a>b) goto L3
goto L4
L3: d=x+y goto S(if).nextL4: d=x*y goto S(if).nextS(if).next: goto L0
S(while).next: x=1
LL语法分析树例子
{ c=0; while(c>10) {
c=c-1; if (a>b)
d=x+y; else d=x*y;
} x=1}
S L
c=c-1
if ( B ) S else S
d=x+y d=x*y
S L
c = 0 L
x = 1Swhile (B) S
S
S L
Lc > 10
S{ L }
{ L }
LL分析中实现语句翻译的SDT——例子3
产生式:P S
P { S.next= newLabel(); } S
产生式:L S L1
{ if (当前输入符=='if' || 'while' ) S.next= newLabel(); L1.next= L.next; } S L1
产生式:L
不做任何事情, 本来是要给综合属性赋值
产生式:S {L}
P { { L.next = S.next;; } S }
I4S→ id = E
I0P→SS→ {S} S→ if(B) SS→ while(B) S S→ id = E
I1P→S
S
if
id
I3S→if( B ) S S→ {S}S→ if(B) SS→ while(B) S S→ id = E I6
S→if( B ) S
{
if
I8S→ SS
SS
I2S→ {S} S→ SS S→ if(B) SS→ while(B) S S→ id = E
I5S→ {S} S→ SS S→ if(B) SS→ while(B) S S→ id = E
I7S→ {S}}
S
{
DFA的优势——LR语法分析实用的原因
LR分析中实现控制语句翻译的SDT
产生式:S while(B) S1 B
S1
L1
L2
S.next
LL分析中,
定义了继承属性:
S.next
B.true
B.false
S.code=L1 : || B.code || L2: ||S1.code || goto L1 || S.next:
LR分析中,
则定义综合属性:
S.nextList;
B.falseList;
B.trueList;
实现同一目标:生成中间代码
goto分两种:前向,后向
c=20;while(c>10 || a>b)
c=c-1;x=1
c=20L0: if (c>10) goto L1
if (a>b) goto L1
goto L2
L1: c=c-1 goto L0
L2: x=1
前向
后向
综合属性:S.nextList;B.falseList;B.trueList
一旦变得已知,就要记录下来,用于回填
对L0, 在后面要用它,因此要记录下来
对前向goto,使用S.nextList,B.falseList,B.trueList来记录要回填的行
c=20;while(c>10 || a>b)
c=c-1;x=1
L0: if (c>10) goto L1
if (a>b) goto L1
goto L2
L1:
B被规约出来,得到B.falseList = {4}; B.trueList = {2,3}接下来就要生成S1的代码了,此刻,L1 为nextInstr= 5,要记下来,用于回填B.trueList中所指的行。
中间代码表:
Rid code1 c=202 if (c>10) goto X3 if (a>b) goto X4 goto X5nextInstr
产生式:S while(B) S1
LR分析中,综合属性的含义
c=20;while(c>10 || a>b)
c=c-1;x=1
c=20L0: if (c>10) goto L1
if (a>b) goto L1
goto L2
L1: c=c-1 goto L0
L2: x=1
综合属性:B.trueList
综合属性:B.falseList;
综合属性:S.nextList = B.falseList;
BB1 || B2
B.trueList = B1.trueList B2.trueList
B.falseList = B2.falseList
LR分析中,一个语句的next变得确定的时刻
c=0; if(c>10) {
c=c-1; if (b>c) {
b=x+y; if (a>b) { a=x*y;
} }
} x=1
在S规约出来之后,看当前输入符,如果不是’}’,意味着该语句后接另一语句,即SSS。此时S.next 变得确定,就是nextInstr;如果是'}',则说明是S是子句的末尾句,它的.next还不确定 。
c=0 if (c>10) goto L1 goto L0L1: c=c-1 if(b>c) goto L3 goto L2L3: b=x+y if(a>b) goto L5 goto L4L3: a=x*yL0: L2: L4: x=1
LR分析中,语句与语句之间的关系
c=0; if(c>10) {
c=c-1; if (b>c) {
b=x+y; if (a>b) { a=x*y;
} }
} x=1
父子关系:Sif (B) S1 { S.nextlist = B.falselist + S1.nextlist; }兄弟关系:SS1{ backpatch(S1.nextlist,nextInstr); } S2 {S.nextlist = S2.nextlist; }
c=0 if (c>10) goto L1 goto L0L1: c=c-1 if(b>c) goto L3 goto L2L3: b=x+y if(a>b) goto L5 goto L4L3: a=x*yL0: L2: L4: x=1
LR分析中实现控制语句的翻译SDT——例1
产生式:S while (B) S1
M { M.instr = nextinstr };
Swhile (M1 B) M2 S1 { backpatch(B.truelist, M2.instr);
backpatch(S1.nextlist, M1.instr);
gen('goto' M1.instr);
S.nextlist = B.falselist; }
产生式:S while (M1 B) M2 S1
c=0L0: if (c>10) goto L1 if (a>b) goto L1 goto L5L1: c=c-1 goto L0L5: x=1
LR分析中实现控制语句的翻译SDT——例2
产生式:S if (B) S1 else S2
if ( a>b ) goto L1 if ( c>10 ) goto L1 goto L2 L1: d= x+y goto S.nextL2: d= x*y S.next:
M { M.instr = nextinstr }; N { N.nextlist = makelist(nextinstr); gen('goto _'); N.instr = nextinstr;}
Sif (B) M S1 else N S2
{ backpatch(B.truelist, M.instr);
backpatch(B.falselist, N.instr);
temp= merge(S1.nextlist, N.nextlist);
S.nextlist = merge(temp, S2.nextlist); }
产生式:S if (B) M S1 else N S2
LR分析中实现布尔表达式的回填翻译SDT
BE1 rel E2 { B.truelist = makelist(nextinstr); B.falselist = makelist(nextinstr + 1);
gen('if' E1.addr rel.op E2.addr 'goto _');
gen('goto _'); }
LR分析中实现布尔表达式的回填翻译SDT
BB1 && { B2.instr = nextinstr; } B2 { Backpatch(B1.truelist, B2.instr);
B.truelist = B2.truelist;
B.falselist = merge(B1.falselist, B2.falselist); }
BB1 || { B2.instr = nextinstr; } B2 { Backpatch(B1.falselist, B2.instr);
B.falselist = B2.falselist;
B.truelist = merge(B1.truelist, B2.truelist); }
LR分析中实现语句翻译的SDT——例子3
产生式:Sid = E
Sid = E; { S.nextlist =null; }
产生式:S S1 S2
SS1 { backpatch(S1.nextlist, nextinstr); } S2 { S.nextlist = S2.nextlist; }
产生式:S {S1}
S{S1} { S.nextlist =S1.nextlist ; }
我们走到哪儿了?
给定上下文无关文法G,在第四章,解决了的问题:
lG是不是LL(1)文法, 是不是LR(1)文法的问题;
l文法 LL文法的预测分析表,LR文法的语法分析表 语法分
析器源程序生成工具;
语义分析,中间代码的生成,不是独立的环节,而是在语法分析
的过程(LL分析中的展开,LR分析中的规约,)中附带完成;
第五章, 在文法的产生式上加上动作,构造SDT。有了SDT,语
法分析,语义分析,中间代码生成,这三个工作的源程序就可由
语法分析器生成工具来自动得到;
第五章 语法制导的翻译
语法制导翻译方案SDT
语法制导翻译
语法制导定义SDD
继承属性综合属性
文法SDD
属性计算
SDDSDT
L属性的SDT
语法制导翻译应用
依赖图 计算顺序
可高效实现的SDD
S属性定义
L属性定义
抽象语法树构造
语义分析和中间代码生成
中间代码表示
类型检查和翻译
中间代码生成
DAG图
三地址码
静态单赋值
表达式翻译
控制流
翻译
过程翻译
回填
S属性的SDT