编译原理 Compiler Principles 第五章...

127
湖南大学信息科学与工程学院 软件工程系 杨金民 2019 编译原理 Compiler Principles 第五章 语法制导的翻译

Transcript of 编译原理 Compiler Principles 第五章...

湖南大学信息科学与工程学院

软件工程系 杨金民

2019

编译原理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)

抽象语法树的构造

基于文法的语法分析树

E.node

id3

+E T.node

id1 + id2 *id3

*T F

F

id2

T

F

id1

+

*

id3id2id1

抽象语法树

我们走到哪儿了?

给定上下文无关文法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'

弹栈

E.val { E.val = E'.syn}

E'.syn= 19

E.val = 19

+ T

EE'

E1'

总结

l LR分析中的翻译,简洁,直观,易懂——很棒!

l LL语法分析中的翻译,因为消左递归而引入的非终结符,既

带综合属性又带继承属性,巨复杂,晦涩,难懂,自然也就

很丑陋,没人喜欢。

目标不同,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;

程序例子1

c=20;while(c>10)

c=c-1;x=1

c=20L0: if (c>10) goto L1

goto L2

L1: c=c-1 goto L0

L2: x=1

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

表达式的类型

l算术表达式E;优先级:(),*/, +/-

l布尔表达式B;优先级:(),!,&&, ||

l正则表达式R;优先级:(),*, 联接,|

在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

作业

• 5.1.1, 5.1.2, 5.1.3• 5.2.3, 5.2.4• 5.3.1• 5.4.2, 5.4,3, 5.4.7

谢 谢!谢 谢