第
Download
1 / 119

第 8 章 语法制导翻译和中间代码生成 - PowerPoint PPT Presentation


  • 288 Views
  • Uploaded on

第 8 章 语法制导翻译和中间代码生成. 教学目的: [1] 掌握语法制导翻译基本原理。 [2] 了解自上而下分析制导翻译基本思想和实现方法。 [3] 掌握几种常用的中间代码:四元式、三元式、逆波兰表示。 [4] 掌握简单表达式的中间代码生成。. 教学重点: 语法制导翻译基本思想、中间代码的形式、布尔表达式的翻译与控制结构的翻译;布尔表达式与控制结构的语义过程。. 学时分配: 8 学时. 本章内容. 8.1 属性文法. 8.2 语法制导翻译概论. 8.3 中间代码的形式. 8.4 简单赋值语句的翻译. 8.5 布尔表达式的翻译.

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about ' 第 8 章 语法制导翻译和中间代码生成' - rafael


An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript

8章 语法制导翻译和中间代码生成

  • 教学目的:

    [1]掌握语法制导翻译基本原理。

    [2]了解自上而下分析制导翻译基本思想和实现方法。

    [3]掌握几种常用的中间代码:四元式、三元式、逆波兰表示。

    [4]掌握简单表达式的中间代码生成。

  • 教学重点:语法制导翻译基本思想、中间代码的形式、布尔表达式的翻译与控制结构的翻译;布尔表达式与控制结构的语义过程。

  • 学时分配:8学时


本章内容

8.1 属性文法

8.2 语法制导翻译概论

8.3 中间代码的形式

8.4 简单赋值语句的翻译

8.5 布尔表达式的翻译

8.6 控制结构的翻译

8.7 说明语句的翻译

8.8 数组和结构的翻译符号表


8.1 属性文法

编译程序的任务是将汇编语言或高级语言书写成的源程序转换成等价的目标代码程序。其中要求目标代码程序和源程序的语义(Semantics)必须相同。

什么是语义?程序的语义就是它的“意思”。语义分析的任务包括两方面:

一个是静态语义检查,

一个是动态语义的解释执行(通俗地说就是计算并生成中间代码。


语义分析的工作:

一、静态语义分析或静态语义审查

包括:(1)类型检查。根据类型相容性要求,验证程序中执行的每个操作是否遵守语言的类型系统的过程,编译程序必须报告不符合类型系统的信息。

(2)控制流检查。控制流语句必须使控制转移到合法的地方。例如,在C语言中break语句使控制跳离包括该语句的最小while、for或switch语句。如果不存在包括它的这样的语句,则报错。

(3)一致性检查。

(4)上下文相关性检查。比如,变量名字必须先声明后引用;而有时,同一名字必须出现两次或多次,例如,Ada 语言程序中,循环或程序块可以有一个名字,出现在这些结构的开头和结尾,编译程序必须检查这两个地方用的名字是相同的。

(5)名字的作用域分析


二、动态语义处理

如果静态语义正确,语义处理则执行真正的翻译(动态语义)即:生成程序的一种中间表示形式或生成实际的目标代码。

中间代码(中间语言)是介于源语言和机器语言的一种表示形式。

通常语义分析生成中间代码的原因:

  • 便于移植:中间代码相对独立于目标机,在编译程序移植时编译前端保持不变。

  • 利于优化:将优化分为与目标机无关的中间代码优化,以及与目标机相关的目标代码的优化,使优化更加细致有效。


语义的形式化描述

语义分析的整个过程和词法及语法分析相类似。

例如,在语法分析中,我们使用BackusNaus范

式(BNF)中的上下文无关文法描述语法结构,并

用各种自顶向下和自底向上的分析算法实现语法

结构。由于没有标准的方法(如BNF)来说明语言的

静态语义,因此语义分析就没有这么简单。我们常

采用属性文法(attribute grammar)来描述语义。


8.1属性文法

一、属性(Attribute )

  • 属性翻译文法是在上下文无关文法的基础上,为每个文法符号(终结符或非终结符)配备若干相关的“值”(称为属性)。

  • 这些属性代表与文法符号相关信息,例如它的类型、值、代码序列、符号表内容等等。

  • 属性与变量一样,可以进行计算和传递。

  • 属性加工的过程即是语义处理的过程。对于文法的每个产生式都配备了一组属性的计算规则,称为语义规则。


二、属性文法(Attribute Grammar)的定义

一个属性文法是一个三元组A=(G,V,F),其中

  • G为一上下文无关文法 。

  • V为有穷的属性集,每个属性与文法的一个终结符或

    非终结符相连,这些属性代表与文法符号相关信息,如

    它的类型、值、代码序列、符号表内容等等 。属性与

    变量一样,可以进行计算和传递。属性加工的过程即是

    语义处理的过程。

  • F是关于属性的属性断言或一组属性的计算规则(称为语义规则)。断言或语义规则与一个产生式相联,引用该产生式左端或右端的终结符或非终结符相联的属性。


属性文法的表示分两部分

  • 首先在上下文无关文法中,对于每个文法符号引进相关的属性符号;

  • 其次对于每个产生式写出计算属性值的计算规则(即语义规则),来描述各属性间的关系。

    形式为:

    文法规则 语义规则规则1 相关的属性等式. . . . . .规则n 相关的属性等式


例】用属性文法表示简单的无符号整数文法:number → number digit | digitdigit →0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

【分析】一个数最重要的属性是它的值,我们将其命名为val。每个数字都有一个值,可以用它表示的实际数直接计算。

1、文法规则: digit→0

属性等式: digit.val = 0

2、文法规则: number → digit

属性等式表示为:number.val = digit.val。

3、文法规则number → number digit ,我们必须表示出这个文法规则左边符号的值和右边符号的值之间的关系。通过使用下标进行区分,将文法写成如下形式: number1 →number2 digit

语义规则:number1.val:=number2.val*10+digit.val


例】用属性文法表示标识符的类型信息

D → T L

T → int | real

L → L1,id

L → id

[分析] 首先将类型信息作为文法符号类型描述的属性,我们命名为type。

1、文法规则T → int,属性等式是T.type = int

2、文法规则D → T L,属性等式 是L.type = T.type

3、文法规则L →id ,属性等式 是addtype(id.entry,L.type)

4、文法规则L → L1,id ,属性等式是

L1.type = L.type addtype(id.entry,L.type)

【说明】addtype的功能是把每个标识符的类型信息登录在符号表的相关项中。


三、属性的分类

1、继承属性(inherited attribute)

在语法树中,一个结点的继承属性由此结点的父结点和/或兄弟结点的某些属性确定。通常用于“自上而下”传递信息。

2、综合属性(synthesized attribute)

在语法树中,一个结点的综合属性的值由其子结点的属性值确定。因此,通常使用自底向上的方法在每一个结点处使用语义规则计算综合属性的值。


说明】

(1)终结符只有综合属性,它们由词法分析器提供;

(2)非终结符既可有综合属性也可有继承属性,文法开始符号的所有继承属性作为属性计算前的初始值。


E、T、F的val为综合属性

【例】算术表达式求值的语义描述:

产生式 语义规则

L→E print(E.val)

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→digit F.val=digit.lexval

语义过程

L的属性为空

digit仅有综合属性

由词法分析程序提供


例】 带有继承属性L.in的语义规则

产生式 语义规则

DTL Lin:=T  type

T int T  type :=int

T real T  type :=real

L L1,id L1in :=L in

addtype(id entry,L in)

L id addtype(id entry,L in)


8.2 语法制导翻译概论

  • 所谓语法制导翻译法,直观上说是为文法中每个产生式配上一组语义规则,并且在语法规则的指导下,通过计算语义规则,完成对输入符号串的翻译。这种翻译的办法称作语法制导翻译法。


说明】

1)每个语义规则指明了相应产生式中各个符号的具体含义。

2)规定使用该产生式进行分析时所采取的语义动作(如传递或处理信息、查填符号表,计算值,产生中间代码)

3)构造属性文法时,不指明翻译时语义规则的计算次序

4)使用属性文法时把语法规则和语义规则分开,但在使用语法规则进行推导或归约同时又使用这些语义规则来指导翻译与最终产生目标代码,所以称为语法制导翻译。


语法制导翻译过程通常是这样的:

1)对单词符号串进行语法分析,构造语法分析树;

2)从语法分析树得到描述节点实行间依赖关

系的依赖图;

3)由此依赖图得到语义规则的计算次序;进行语义规则计算,得到翻译结果

可表示为:

输入串语法树依赖图语义规则计算次序


依赖图

  • 在一颗语法树中的结点的继承属性和综合属性之间的相互依赖关系可以用称作依赖图的一个有向图来描述。

  • 在为一棵语法树构造依赖图以前,我们为每一个包含过程调用的语义规则引入一个虚综合属性b,这样把每一个语义规则都写成如下形式:

    b:= f(c1,c2, …ck)

  • 依赖图中为每一个属性设置一个结点,如果属性b依赖属性c,则从属性c的结点有一条有向边连到属性b的结点。


对于给定的一棵语法分析树、依赖图是按下面步骤构造出来的:

for分析树中每一个结点n do

for结点的文法符号的每一个属性a do

为a在依赖图中建立一个结点;

for分析树中每一个结点n do

for结点n所用产生式对应的每一个语义规则

b:=f(c1,c2,…ck) do

for i :=1 to k do

从ci结点到b结点构造一条有向边


A.a

X.x

Y.y

X.i

【例如】属性 A.a:=f( X.x, Y.y )

对应于产生式 AXY的语义规则,这条语义规则确定了依赖于属性X.x和Y.y的综合属性A.a。 如果在语法树中应用这个产生式,那么在依赖图中会有三个结点A.a,X.x,和Y.y。由于A.a依赖X.x,所以有一条有向边从X.x到A.a.由于A.a也依赖于Y.y,所以还有一条有向边从Y.y连到A.a.

如果与产生式AXY对应的语义规则还有:

X .i:=g(A.a,Y.y)

那么,图中还应有两条有向边,一条从A.a连到X.i,另一条从Y.y连到X.i

,因为X.i依赖于A.a和Y.y.


例】

产生式 语义规则

EE1+E2 E.val:=E1.val+E2.val

E

E.val

E1

+

E2

E1.val

E2.val

依赖图


如果一属性文法不存在属性之间的循环依赖关系,那么该文法为良定义的。为了设计编译程序,我们只处理良定义的属性文法。如果一属性文法不存在属性之间的循环依赖关系,那么该文法为良定义的。为了设计编译程序,我们只处理良定义的属性文法。


属性值的计算顺序如果一属性文法不存在属性之间的循环依赖关系,那么该文法为良定义的。为了设计编译程序,我们只处理良定义的属性文法。

如何得到计算语义规则的顺序?

通过依赖图的拓扑排序中,得到计算语义规则的顺

序。用这个顺序来计算语义规则就得到输入符号串的翻

译。依赖图的拓扑排序(Topological Sort)给出了对应

分析树中结点按语义规则计算的有效顺序。存在拓扑排序

的充分必要条件是相关图必须是非循环的,这样的图形称

作有向无环图(DirectedAcyclicGraphs,DAG)。


属性值的计算顺序如果一属性文法不存在属性之间的循环依赖关系,那么该文法为良定义的。为了设计编译程序,我们只处理良定义的属性文法。

  • 一个有向无环图的拓扑排序是图中结点的任何顺序m1,m2,…,mk,使得边必须是从序列中前面的结点指向后面的结点

  • 如果mi→mj是mi到mj的一条边,那么在序列中mi必须出现在mj的前面。

  • 若依赖图中无环,则存在一个拓扑排序,它就是属性值的计算顺序。

  • 从依赖图的任何拓扑排序中,我们可以得到计算语义规则的顺序。用这个顺序来计算语义规则就得到输入符号串的翻译。


如果一属性文法不存在属性之间的循环依赖关系,那么该文法为良定义的。为了设计编译程序,我们只处理良定义的属性文法。例】按如下语义规则建立句子

real id1,id2,id3分析树的依赖图

产生式 语义规则

DTL Lin:=T  type

T int T  type :=integer

T real T  type :=real

L L1,id L1in :=L in

addtype(id entry,L in)

L id addtype(id entry,L in)


D如果一属性文法不存在属性之间的循环依赖关系,那么该文法为良定义的。为了设计编译程序,我们只处理良定义的属性文法。

T

4

type

in 5

L

6

real

,

in 7

id3

3 entry

L

8

in 9

L

10

,

id2

2 entry

id1

1 entry


拓扑排序是:如果一属性文法不存在属性之间的循环依赖关系,那么该文法为良定义的。为了设计编译程序,我们只处理良定义的属性文法。

1, 2, 3,4,5,6,7,8,9,10

a4:=real;

a5:=a4;

addtype(id3entry,a5);

a7:=a5;

addtype(id2entry,a7);

a9:=a7;

addtype(id1entry,a9);


属性计算方法如果一属性文法不存在属性之间的循环依赖关系,那么该文法为良定义的。为了设计编译程序,我们只处理良定义的属性文法。

属性计算有树遍历和一遍扫描的方法

树遍历的属性计算方法

  • 假设语法树已经建立好了,并且树中已带有开始符号的继承属性和终结符的综合属性。

  • 然后以某种次序遍历语法树,直至计算出所有属性。最常用的遍历方法是深度优先,从左到右的遍历方法。如果需要的话,可使用多次遍历(或称遍)。


一遍扫描的处理方法如果一属性文法不存在属性之间的循环依赖关系,那么该文法为良定义的。为了设计编译程序,我们只处理良定义的属性文法。

  • 与树遍历的属性计算文法不同,一遍扫描的处理方法是在语法分析的同时计算属性值,而不是语法分析构造语法树之后进行属性的计算,而且无需构造实际的语法树。

  • 因为一遍扫描的处理方法与语法分析器的相互作用,它与下面两个因素密切相关:

    (1)所采用的语法分析方法;

    (2)属性的计算次序。

  • L-属性文法可用于一遍扫描的自上而下分析,而S-属

    性文法适合于一遍扫描的自下而上分析。


在某些情况下可用一遍扫描实现属性文如果一属性文法不存在属性之间的循环依赖关系,那么该文法为良定义的。为了设计编译程序,我们只处理良定义的属性文法。

法的语义规则计算。也就是说在语法分析

的同时完成语义规则的计算,无须明显地

构造语法树或构造属性之间的依赖图。


  • 如果按这种一遍扫描的编译程序模型来理解语法制导翻译方法的话,如果按这种一遍扫描的编译程序模型来理解语法制导翻译方法的话,语法制导翻译就是为文法中每个产生式配上一组语义规则,并且在语法分析的同时执行这些语义规则。

  • 在自上而下语法分析中,若一个产生式匹配输入串成功,或者,在自下而上分析中,当一个产生式被用于进行归约时,此产生式相应的语义规则就被计算,完成有关的语义分析和代码产生的工作。

  • 在这种情况下,语法分析工作和语义规则的计算是穿插进行的。


S-如果按这种一遍扫描的编译程序模型来理解语法制导翻译方法的话,属性文法和自下而上翻译

  • S-属性文法,它只含有综合属性。综合属性结点属性值的计算和自下而上建立语法分析同步进行。

  • 分析器可以保存与栈中文法符号有关的综合属性值,每当进行归约时,新的属性值就由栈中正在归约的产生式右边符号的属性值来计算。

  • S-属性文法的翻译器通常可借助于LR分析器实现。在S-属性文法的基础上,LR分析器可以改造为一个翻译器,在对输入串进行语法分析的同时对属性进行计算。


如果按这种一遍扫描的编译程序模型来理解语法制导翻译方法的话,例】算术表达式求值的语义描述:

产生式 语义规则

L→En print(E.val)

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→digit F.val=digit.lexval

例:输入3*5+4n

演示


在自底向上的分析方法中,我们使用一个栈来存放已在自底向上的分析方法中,我们使用一个栈来存放已

经分析过的子树的信息。可以在分析栈中使用一个附

加的域来存放综合属性。

state

val

...

...

X

X.x

Y

Y.y

top

Z

Z.z

...

...


语义处理采用的方法在自底向上的分析方法中,我们使用一个栈来存放已—语法制导(将语义处理的描述和文法的产生式关联起来)语法分析的同时完成语义处理

【例】类形检查

产生式 语义规则

ET1 + T2 if T1.type = int and T2.type= int then E.type :=int else error

E T1 o T2 if T1.type=bool and T2.type= bool then E.type :=bool else error

T n T.type := int

T  b T.type := bool

编译实现 (LR)增加语义栈, 归约时进行语义动作

(LL(1))匹配时进行语义动作。


在自底向上的分析方法中,我们使用一个栈来存放已总结】

采用自底向上分析,例如LR分析,首先给出S-属性定义,然后,把S-属性定义变成可执行的代码段,这就构成了翻译程序。随着语法分析的进行,归约前调用相应的语义子程序,完成翻译的任务。


L-在自底向上的分析方法中,我们使用一个栈来存放已属性文法在自顶向下分析中的实现

在语法分析过程中进行语义分析和翻译,

属性的计算顺序受到语法分析建立分析树结

点顺序的限制。

一种自然的计算属性的顺序是按深度优

先访问分析树结点的顺序,它适应多种自底

向上和自顶向下的翻译方法。

L-属性定义可用于按深度优先顺序计算

属性值。


  • 一个属性文法称为在自底向上的分析方法中,我们使用一个栈来存放已L-属性文法.如果对于每个产生式A→X1X2…Xn,其每个语义规则中的每个属性或者是综合属性,或者是Xj(1<=j<= n)的一个继承属性且这个继承属性仅依赖于:

    (1)产生式Xj的左边符号X1,X2,…,Xj-l的属性;

    (2) A的继承属性。

  • 【说明】S-属性文法一定是L-属性文法。


在自底向上的分析方法中,我们使用一个栈来存放已思考】非L-属性的语法制导定义

产生式

语义规则

ALM

A  QR

L.i:=l(A.i)

M.i:=m(L.s)

A.s:=f(M.s)

R.i:=r(A.i)

Q.i:=q(R.s)

A.s:=f(Q.s)

【分析】该语法制导定义不是L-属性定义,

文法符号Q的继承属性依赖于它右边文法符

号R的属性。


翻译模式在自底向上的分析方法中,我们使用一个栈来存放已

  • 翻译模式(Translation schemes)是语法制导定义的一种便于翻译的书写形式。其中属性与文法符号相对应,语义规则或语义动作用花括号{ }括起来,可被插入到产生式右部的任何合适的位置上。

  • 这是一种语法分析和语义动作交错的表示法,他表达在按深度优先遍历分析树的过程中

    何时执行语义动作。

  • 翻译模式给出了使用语义规则进行计算的顺序。


最简单的翻译方案是属性文法中只含有综合属性。只需将每个语义规则写成由赋值语句组成的语义动作,并把该语义动作放在相应规则右部之末端,便得到翻译方案。最简单的翻译方案是属性文法中只含有综合属性。只需将每个语义规则写成由赋值语句组成的语义动作,并把该语义动作放在相应规则右部之末端,便得到翻译方案。

如果属性文法中既有综合属性又有继承属性,在建立翻译模式时要满足下列三个条件:

1)产生式右边的符号的继承属性必须在这个符号以前的动作中计算出来。

2)一个动作不能引用这个动作右边符号的综合属性。

3)产生式左边非终结符的综合属性只有在它所引用的所有属性都计算出来后才能计算。计算这种属性的动作通常可放在产生式右端的末尾。


最简单的翻译方案是属性文法中只含有综合属性。只需将每个语义规则写成由赋值语句组成的语义动作,并把该语义动作放在相应规则右部之末端,便得到翻译方案。例】一个简单的翻译模式

E→TR

R→addop T {print(addop.lexeme)}R1|ε

T→num{print(num.val)}

把语义动作看成终结符号,输入9-5+2,其分析树如下图,当按深度优先遍历它,执行遍历中访问的语义动作,将输出

9 5 - 2 +

它是输入表达式9-5+2的后缀式。


E最简单的翻译方案是属性文法中只含有综合属性。只需将每个语义规则写成由赋值语句组成的语义动作,并把该语义动作放在相应规则右部之末端,便得到翻译方案。

T

R

-

R

9

R

Pt(´-´)

Pt(´9´)

T

Pt(´+´)

+

T

5

Pt(´5´)

2

Pt(´2´)

图 9-5+2的带语义动作的分析树


最简单的翻译方案是属性文法中只含有综合属性。只需将每个语义规则写成由赋值语句组成的语义动作,并把该语义动作放在相应规则右部之末端,便得到翻译方案。设计翻译模式(根据语法制导定义)

条件:语法制导定义是L-属性定义

保证语义动作不会引用还没有计算的属性值。

1. 有综合属性的情况:

为每一个语义规则建立一个包含赋值的动作,并把该语义动作放在相应规则右部之末端,便得到翻译方案。

【例如】TT1*F Tval:=T1 val*F val

TT1*F { Tval:=T1 val*F val}


  • 2.最简单的翻译方案是属性文法中只含有综合属性。只需将每个语义规则写成由赋值语句组成的语义动作,并把该语义动作放在相应规则右部之末端,便得到翻译方案。既有综合属性又有继承属性。在建立翻译模式时要满足下列三个条件:

  • 产生式右边的符号的继承属性必须在这个符号以前的动作中计算出来。

    • 一个动作不能引用这个动作右边的符号的综合属性。

    • 产生式左边非终结符号的综合属性只有在它所引用的所有属性都计算出来以后才能计算。计算这种属性的动作通常可放在产生式右端的未尾。


最简单的翻译方案是属性文法中只含有综合属性。只需将每个语义规则写成由赋值语句组成的语义动作,并把该语义动作放在相应规则右部之末端,便得到翻译方案。例】

SA1A2 {A1in:=1; A2 in:=2}

A a { print(A in) }

【分析】该翻译模式不满足要求。因为按深度优先遍历输入串aa的语法树,当要打印第二个产生式A.in时的值时,该属性还没有定义。如果计算A1in, A2 in值的动作分别嵌在产生式SA1A2 的右部A1和A2之前而不是最后,那么A.in在每次执行print(A in) 时就已经有定义了。


练 习最简单的翻译方案是属性文法中只含有综合属性。只需将每个语义规则写成由赋值语句组成的语义动作,并把该语义动作放在相应规则右部之末端,便得到翻译方案。

【例】 在一个移入——归约的分析中采用以下的语法制导的翻译模式,在某产生式归约时,立即执行括号中的动作。

A→aB {print “0” }

A→c {print “1” }

B→Ab { print “2” }

当分析器输入为aacbb时,打印的字符串是什么?


最简单的翻译方案是属性文法中只含有综合属性。只需将每个语义规则写成由赋值语句组成的语义动作,并把该语义动作放在相应规则右部之末端,便得到翻译方案。解】 分析器的分析过程如下图:

由于分析器采用移入归约的方式进行分析,符号串aacbb的分析过程将按标号进行,而按一产生式归约时立即执行括号中的动作所以分析器打印的字符为:

12020


最简单的翻译方案是属性文法中只含有综合属性。只需将每个语义规则写成由赋值语句组成的语义动作,并把该语义动作放在相应规则右部之末端,便得到翻译方案。例】下面文法产生的表达式是对整型和实型常数应用算符+形成的。当两个整数相加时,结果为整数,否则为实数。

EE+T | T

Tnum.num | num

给出语法制导定义确定每个子表达式的类型。


最简单的翻译方案是属性文法中只含有综合属性。只需将每个语义规则写成由赋值语句组成的语义动作,并把该语义动作放在相应规则右部之末端,便得到翻译方案。解】

a)设type是综合属性,代表各非终结符的“类型”属性

语法制导定义


最简单的翻译方案是属性文法中只含有综合属性。只需将每个语义规则写成由赋值语句组成的语义动作,并把该语义动作放在相应规则右部之末端,便得到翻译方案。例】有文法:

S->(L)|a

L->L,S|S

要求:给此文法配上语义动作子程序(或者说为此文法写一个语法制导定义),它输出配对括号的个数。如对于句子(a,(a,a)),输出是2。


最简单的翻译方案是属性文法中只含有综合属性。只需将每个语义规则写成由赋值语句组成的语义动作,并把该语义动作放在相应规则右部之末端,便得到翻译方案。例】拓展文法:加入新开始符号S'和产生式S'->S

设num为综合属性,代表括号个数属性

语法制导定义


最简单的翻译方案是属性文法中只含有综合属性。只需将每个语义规则写成由赋值语句组成的语义动作,并把该语义动作放在相应规则右部之末端,便得到翻译方案。例】令S.val为下面的文法由S生成的二进制数的值(如,对于输入101.101,S.val=5.625);

SL.L | L

LLB | B

B0 | 1


最简单的翻译方案是属性文法中只含有综合属性。只需将每个语义规则写成由赋值语句组成的语义动作,并把该语义动作放在相应规则右部之末端,便得到翻译方案。解】val为综合属性,代表值属性 ,length代表位数。

语法制导定义


8.3 最简单的翻译方案是属性文法中只含有综合属性。只需将每个语义规则写成由赋值语句组成的语义动作,并把该语义动作放在相应规则右部之末端,便得到翻译方案。中间代码的形式

中间代码( Intermediate code)

(Intermediate representation)

(Intermediate language)

是源程序的一种内部表示

复杂性介于源语言和目标机语言之间

中间代码的作用

  • 使编译程序的逻辑结构更加简单明确

  • 利于进行与目标机无关的优化

  • 利于在不同目标机上实现同一种语言

    翻译方法:语法制导翻译


中间代码的形式最简单的翻译方案是属性文法中只含有综合属性。只需将每个语义规则写成由赋值语句组成的语义动作,并把该语义动作放在相应规则右部之末端,便得到翻译方案。

1)逆波兰表示(或称为后缀式)

2)图表示法(DAG 和抽象语法树),

3)三地址代码(四元式、三元式、间接三元式)


逆波兰最简单的翻译方案是属性文法中只含有综合属性。只需将每个语义规则写成由赋值语句组成的语义动作,并把该语义动作放在相应规则右部之末端,便得到翻译方案。式

逆波兰记号是最简单的一种中间代码形式,由波兰逻辑学家卢卡西维奇发明。这种方法是,把运算量(操作数)写在前面,把算符写在后面,所以也称做后缀式 。

一个表达式的后缀式可以如下定义:

(1)如果E是一个变量或常量,则E的后缀式是E自身。

(2)如果E是E1 op E2形式的表达式,这里op是任何二元操作符,则E的后缀式为 E1’ E2’op,这里E1’和E2’分别为E1和E2的后缀式。

(3)如果E是(E1)形式的表达式,则E1的后缀式就是E的后缀式。


用逆波兰表示法表示表达式,最大的优点是易于计算机处理表达式。用逆波兰表示法表示表达式,最大的优点是易于计算机处理表达式。

实现方式:利用一个栈,自左至右扫描算术表达式,1)每遇到运算对象,就将它推进栈,

2)遇到运算符,若该运算符是二目运算,则对栈顶部的两个运算对象实施该运算,并将运算结果代替两个运算对象而进栈。若该运算符是一目运算,则对栈顶元素执行该运算,并将运算结果代替该元素进栈。


用逆波兰表示法表示表达式,最大的优点是易于计算机处理表达式。1:表达式a := b * (- c) + b * (- 34)的后缀式:

a b c - * b 34 - * + :=

例2:算术表达式a*- (b+c)的后缀式:

a b c + uminus *

例3:算术表达式

A + B * ( C - D ) + E / ( C - D ) ^N的后缀式:

A B C D - * + E C D -N ^ / +


用逆波兰表示法表示表达式,最大的优点是易于计算机处理表达式。4:表达式x+y≤z∨a>O∧ (8+z)>3的逆波兰表示为

例5、表达式a ∧b ∨ c ∧(b ∨ x=O ∧ c)的逆波兰表示为

xy+z≤aO>8z+3>∧∨

ab ∧ cbxO=c ∧ ∨ ∧ ∨

例6 -a-(b*c/(c-d)+(-b)*a)的逆波兰表示为

a-bc*cd-/b-a*+-


三地址代码是由下面一般形式的语句构成的序列三地址代码是由下面一般形式的语句构成的序列:

X:=y op z

其中,x、y、z为名字、常数或编译时产生的临时变量;op代表运算符号如定点运算符、浮点运算符、逻辑运算符等。每个语句的右边只能有一个运算符。

三地址语句的具体实现通常有3种表示方法:

(1) 三元式

(2)间接三元式

(3) 四元式

三地址代码


1三地址代码是由下面一般形式的语句构成的序列、三元式

三元式由操作符OP,第一和第二运算对象Operandl,Operand2组成。表示为(OP,Operandl,Operand2)【说明】为了便于代码优化处理,作为中间代码,常常不直接使用三元式表。因为许多三元式是通过指示器紧密相联的,所以改动三元式表很困难。为此,我们另设一张指示器表(间接码表),它将按运算的先后顺序列出有关三元式在三元式表中的位置。换句话说就是用间接码表辅以三元式表的办法来表示中间代码。这种表示法称为间接三元式。当在代码优化过程中需要调整运算顺序时,只需重新安排间接码表而无需改动三元式表。


三地址代码是由下面一般形式的语句构成的序列例】语句a:=b*(-c)+b*(-c) 的三地址语句的三元式表示。

op

arg1

arg2

(0)

(1)

(2)

(3)

(4)

(5)

uminus

*

uminus

*

+

assign

c

b

c

b

(1)

a

(0)

(2)

(3)

(4)


三地址代码是由下面一般形式的语句构成的序列例】语句a:=b*(-c)+b*(-c) 的间接三元式

三地址语句的间接三元式表示

statement

op

arg1

arg2

(0)

(1)

(2)

(3)

(4)

(5)

(14)

(15)

(16)

(17)

(18)

(19)

(14)

(15)

(16)

(17)

(18)

(19)

uminus

*

uminus

*

+

assign

c

b

c

b

(15)

a

(14)

(16)

(17)

(18)

语句的移动仅改变左边的语句表


2三地址代码是由下面一般形式的语句构成的序列.四元式

四元式是一种比较普遍采用的中间代码形式。

四元式的4个组成成分是:由四部分信息组成:操作符OP,第一和第二运算对象Operandl,Operand2,操作结果Result。

表示为:(OP,Operandl,Operand2,Result)


三地址代码是由下面一般形式的语句构成的序列例】语句a:=b*(-c)+b*(-c) 的四元式。

三地址语句的四元式表示

op

arg1

arg2

result

(0)

(1)

(2)

(3)

(4)

(5)

uminus

*

uminus

*

+

assign

c

b

c

b

t2

t5

t1

t3

t4

t1

t2

t3

t4

t5

a


例如:赋值语句三地址代码是由下面一般形式的语句构成的序列A:=-B*(C+D)的四元式表

OP ARGl ARG2 RESULT 注解

(1) @ B T1 Tl为临时变量

(2) + C D T2 T2为临时变量

(3) * T1 T2 T3 Tl为临时变量

(4) := T3 A 赋值运算


四元式与三元式和间接三元式比较三地址代码是由下面一般形式的语句构成的序列

  • 四元式之间的联系是通过临时变量实现的。这一点和三元式不同。要更动一张三元表是很困难的,它意味着必须改变其中一系列指示器的值。但要更动四元式表是很容易的,因为调整四元式之间的相对位置并不意味着必须改变其中一系列指示器的值。因此,当需要对中间代码进行优化处理时,四元式比三元式要方便得多。

  • 对优化这一点而言,四元式和间接三元式同样方便。


图表示法三地址代码是由下面一般形式的语句构成的序列

  • 图表示法包括DAG与抽象语法树。

抽象语法树:

  • 通过语法分析可以很容易构造出语法分析树,因此,语法树可以作为一种合适的中间语言形式。

  • 在语法树中去掉那些对翻译不必要的信息,从而获得更有效的源程序中间表示。这种经变换后的语法树称之为抽象语法树

  • 在抽象语法树中,操作符和关键字都不作为叶结点出现,而是把它们作为内部结点,即这些叶结点的父结点。


S if b then s1 else s2

if_then_else三地址代码是由下面一般形式的语句构成的序列

B

S1

S2

【如】产生式S→ if B then S1 else S2


+三地址代码是由下面一般形式的语句构成的序列

*

-

T

T

T

T

T

(1) (2) (3)

如果表示e1和e2的树为Tl和T2,那么,el+e2、e1*e2和…-e1如图:


3 5 4

+三地址代码是由下面一般形式的语句构成的序列

4

*

5

3

下面是表达式3*5+4的抽象语法树


DAG三地址代码是由下面一般形式的语句构成的序列图

无循环有向圈(Directed Acycli简称DAG)。

与抽象语法树一样,对表达式中的每个子表达式,DAG中都有一个结点。一个内部结点代表一个操作符,它的孩子代表操作数。

与抽象语法树不同的是,在一个DAG中代表公共子表达式的结点具有多个父结点,而在一棵抽象语法树中公共子表达式被表示为重复的子树。

抽象语法树描述源程序的自然层次结构,DAG图也可以描述同样的信息,而且更加紧凑。它可标识出公共子表达式。


三地址代码是由下面一般形式的语句构成的序列例如】表达式 a+a*(b-c)+(b-c)*d 的语法抽象数和DAG图表示


三地址代码是由下面一般形式的语句构成的序列例如】表达式 a:=b*-c+b*-c 的语法抽象数和DAG图表示


三地址代码是由下面一般形式的语句构成的序列练习】写出算术表达式:A+B*(C-D)+E/(C-D)^N的

①四元式序列;

②三元式序列;

③间接三元式序列;

④树形表示


三地址代码是由下面一般形式的语句构成的序列解】

②表达式的三元式序列

(1)(-,C,D)

(2)(*,B,(1))

(3)(+,A,(2))

(4)(-,C,D)

(5)(^,(4),N)

(6)(/,E,(5))

(7)(+,(3),(6))

①表达式的四元式序列:

(1)(-,C,D,T1)

(2)(*,B,T1,T2)

(3)(+,A,T2,T3)

(4)(-,C,D,T4)

(5)(^,T4,N,T5)

(6)(/,E,T5,T6)

(7)(+,T3,T6,T7)


③ A+B*(C-D)+E三地址代码是由下面一般形式的语句构成的序列/(C-D)^N的间接三元式

间接码表 三元式序列

(1) (1) (-,C,D)

(2) (2) (*,B,(1))

(3) (3) (+,A,(2))

(4) (4) (^,(1),N)

(5) (5) (/ ,E,(4))

(6) (6) (+,(3),(5))


*三地址代码是由下面一般形式的语句构成的序列

-

+

-

^

/

+

A B C D E C D N

④ A+B*(C-D)+E/(C-D)^N的抽象语法树表示


8.4 三地址代码是由下面一般形式的语句构成的序列简单赋值语句的翻译

该翻译模式中说明了如何查找符号表的入口

  • 属性id.name表示id所代表的名字本身。

  • 过程lookup(id.name)检查是否在符号表中存在此名字的入口。如果有,则返回一个指向该表项的指针,否则,返回nil表示没找到。

  • 过程emit将生成的三地址语句发送到输出文件中。


简单赋值语句的翻译三地址代码是由下面一般形式的语句构成的序列

t:=arg1 op arg2

语义属性:id.name, E.place

函数:lookup(id.name) ;

过程:emit(t:=arg1 op arg2); newtemp;

产生式 语义描述

(1) Sid:=E { P:=lookup (id.name) ; if Pnil then emit( P“:=”E.place) }

(2)EE1+E2 {E.place:= newtemp; emit(E.place“:=” E1.place“+”E2.place) }

(3)E- E1 { E.place:=newtemp; emit(E.place“:=”“uminus” E1.place) }

(4)E( E1) { E.place:= E1.place}

(5) Eid { P:=lookup(id.name); if Pnil then E.place:=P else error }


8.5 三地址代码是由下面一般形式的语句构成的序列布尔表达式的翻译

在程序设计语言中,布尔表达式有两个基本作用: 一个用作计算逻辑值;另一个是用作控制流语句。

如if-then、if-then-else和 while-do等中的条件表达式。

布尔表达式是用布尔运算符号(and、 or、not )作用到布尔变量或关系表达式上而组成的。关系表达式形式如E1 relop E2, 其中E1和E2是算术表达式, relop为关系运算符 ( < ,<=, = >, > , =, ≠)。 E→E or E | E and E | not E | (E) | id relop id |id

我们使用relop的属性relop.op来确定relop所指的六中关系中的哪一个。按惯例,我们假定or和and 是左结合的,并且规定or 的优先级最低,其次是and, not的优先级最高。


计算布尔表达式的值通常有两种办法三地址代码是由下面一般形式的语句构成的序列:

一是从表达式各部分的值计算出整个表达式的值。

另一种计算法是采取某种优化措施 ,只计算部分表达式:

把A or B解释成 if A then true else B

把A and B解释成 if A then B else false

把not A解释成 if A then false else true


布尔表达式将从左到右按类似算术表达式的求值方法来计算。布尔表达式将从左到右按类似算术表达式的求值方法来计算。

【例】对于布尔表达式:

a or b and not c

将被翻译成如下三地址序列:

T1:=not c

T2:=b and T1

T3:=a or T2


布尔表达式将从左到右按类似算术表达式的求值方法来计算。例】 a<b的关系表达式可等价的写成:

if a<b then 1 else 0 ,并将它翻译成如

下三地址语句序列(假定语句序号从100开

始)

100: if a<b goto 103

  • T:=0

  • goto 104

  • T:= 1

    104


一、布尔表达式的翻译方法布尔表达式将从左到右按类似算术表达式的求值方法来计算。

E->E1 or E2 {E.place:=newtemp:

emit(E.place:=E1.place or E2.place;}

E-> E1 and E2 {E.place:=newtemp:

emit(E.place:=E1.place and E2.place;}

E->not E1{E.palce:=newtemp;

emit(E.place:=not E1.place)}

E->(E1) {E.place:=E1.place}


E->id布尔表达式将从左到右按类似算术表达式的求值方法来计算。1 relop id2

{E.place:=newtemp;

emit(if id1 .place relop id2.place

goto nextstat+ 3) ;

emit(E.place:=0);

emit(goto nextstat+2);

emit(E.place:=1)

}

E->true { E.place:=newtemp;emit(E.place:=1);}

E->false { E.place:=newtemp;emit(E.place:=0);}


布尔表达式将从左到右按类似算术表达式的求值方法来计算。例】a<b or c<d and e<f的翻译结果

(设从序号100开始)


二、控制语句中布尔表达式的翻译布尔表达式将从左到右按类似算术表达式的求值方法来计算。

出现在条件语句if-then,if-else-end和while-do中的布尔表达式E,它的作用仅在于控制对S1和S2的选择。只要能够完成这一使命,E的值就无须最终保留在某个临时单元之中。

因此,作为转移条件的布尔式E,我们可以赋予

它两种“出口”。一是“真”出口,出向S1;一是

“假”出口,出向S2。


作为条件转移的布尔表达式将从左到右按类似算术表达式的求值方法来计算。E,仅把E翻译成代码

是:一串条件转和无条件转四元式。

生成代码为:

if E goto E.true

goto E.false


T布尔表达式将从左到右按类似算术表达式的求值方法来计算。

T

T

F

F

F

【例】将a<b or c<d and e<f作为控制条件的

四元式中间代码。

e>f

a<b

c<d

真出口

假出口


按上图结构进行翻译后生成如下的代码:布尔表达式将从左到右按类似算术表达式的求值方法来计算。

if a<b goto E.true

goto L1

L1:if c<d goto L2

goto E.false

L2:if e<f goto Ltrun

goto E.false


E.true布尔表达式将从左到右按类似算术表达式的求值方法来计算。和 E.false并不能在产生四元式的同时得知,只有在整个布尔表达式的四元式产生完后才得知,因此要采用“回填”技术回填“真链”和“假链”地址。

通过一遍扫描来产生布尔表达式和控制流语句的代码的主要问题在于,当生成某些转移语句时我们可能还不知道该语句将要转移到的标号究竟是什么。为了解决这个问题,我们可以在生成形式分支的跳转指令时暂时不确定跳转目标,而建立一个链表,把转向这个目标的跳转指令的标号键人这个链表。一旦目标确定之后再把它填人有关的跳转指令中。这种技术称为回填。


T布尔表达式将从左到右按类似算术表达式的求值方法来计算。

T

F

F

F

【例】给出a and b or c≥d作为控制条件的四元式中间代码。

T

真出口

a b c≥d

假出口


8.6 布尔表达式将从左到右按类似算术表达式的求值方法来计算。控制语句的翻译

控制流语句

if - then,if – then-else, while-do

文法如下:

S→if E then S1

| if E then S1 else S2

| while E do S1

其中E为布尔表达式.


T布尔表达式将从左到右按类似算术表达式的求值方法来计算。

E的代码

F

S1的代码

.

S2的代码

1、条件语句

条件语句 if E then S1 else s2 可翻译成如下图形式:


布尔表达式将从左到右按类似算术表达式的求值方法来计算。例】 写出条件语句

IF a>0 THEN x:=x+1 ELSE x:=4*( x- 1)四元式序列。

【解】

(1) if a>0 goto

  • goto

  • x:=x+1

    (4)goto

    (5)t1:=x-1

    (7) t2:=t1*4

  • x:=t2

(3)//回填

(5)//回填

(9)//回填


T布尔表达式将从左到右按类似算术表达式的求值方法来计算。

E的代码

F

S的代码

2、条件循环语句

条件循环语句while E do S 可翻译成下图形式:


布尔表达式将从左到右按类似算术表达式的求值方法来计算。例】 考虑如下语句 while a<b do

if c<d then x:=y+z

else x:=y-z

生成下列中间代码:

100: if a<b goto -

101: goto -

102: if c<d goto -

103: goto

104: T1:=y+z;

105 x:=T1

106 goto 100

107: T2:=y-z

108 x:=T2

109 goto 100

200:


3布尔表达式将从左到右按类似算术表达式的求值方法来计算。、计数循环语句

形式:for i:=E1 STEP E2 until E3 do S1

设E2总是正的,则上述循环语句等价为:

i:=E1;

again: if i<= E3 then

begin

S1

i:=i+ E2

goto again

end


8.7 goto布尔表达式将从左到右按类似算术表达式的求值方法来计算。语句

一、标号的形式

L:S (定义形式)

goto L (应用形式)

二、goto 语句的翻译方案

1)如goto L 是一个向上转移的语句,标号L是“定义了”的。

即在符号表中,将登记L的项的“地址”栏中登上语句S的第一个四元式的地址。 goto p(p为符号表中的地址)

2)如goto L 是一个向下转移的语句,标号L是“未定义了”的,对goto L只能产生一个不完全的四元式goto _它的转移目标须待L定义时再回填进去。在这种情况下,必须把所有那些以L为转移目标的四元式地址全都记录下来,以便一旦L定义时就可对这些四元式进行回填。


建链方法:布尔表达式将从左到右按类似算术表达式的求值方法来计算。

1、若goto L中的标号L尚未在符号表中出现,则把L填入表中,置L的“定义否”标志为“未”,把nextstat填进L的地址栏中作为新链首,然后,产生四元式(goto 0),其中0为链尾标志

2、若L已在符号表中出现(但“定义否”标志为“未”),则把它的地址栏中的编号(记为q)取出,把nextstat填进该栏作新链首,然后,产生四元式(goto q)。


布尔表达式将从左到右按类似算术表达式的求值方法来计算。goto 语句的产生式为

S-->label S

label->i:

Label->i:的语义动作为:

1)当i所指的标识符(设为L)不在符号表中,则把它填入,置类型为“标号”,定义否为“已”,地址为nextstat.

2)如L已在符号表中,但类型不为“标号”或定义否为“已”,则报告出错。

3)如L已在符号表中,则把“未”改为“已”,把地址栏中的的链首(记为q)取出,同时把nextstat填在其中,最后,执行backpatch(q,nextstat)


例:对下面程序段,产生相应的四元式布尔表达式将从左到右按类似算术表达式的求值方法来计算。

goto L1;

S1;

goto L1;

L1:S2;

goto L1;

L2:S3;

goto L2;

;


8.8 布尔表达式将从左到右按类似算术表达式的求值方法来计算。数组的翻译

(一)数组元素的地址计算公式

若数组A的元素存放在一片连续单元里,则可以较容易的访问数组的每个元素。假定数组的每个元素的宽度为w,则一维数组A[i] 这个元素的起始地址为:

base + (i – low)*w(1)

其中low为数组下标的下界, base是分配给数组的相对地址,即base为A的第一个元素A[low]的相对地址。

(1) 式可以整理为: i*w + (base –low*w)

其中:

  • i*w 是随数组下标变量而变化的部分,记为VARPART ;

  • (base – low*w)是在数组中不变化的常数记为CONSPART


若二维数组布尔表达式将从左到右按类似算术表达式的求值方法来计算。A按行存放,则可用如下公式计算A[i1,i2]的相对地址:

base + (( i1 – l1)*d2 + i2 – l2) *w

其中,l1、l2分别为i1、i2的下界;di界差。若ui为i的上界,则di=ui – li +1.

假定i1,i2是编译时唯一尚未知道的值,我们可以重写上述表达式为:

( base –( (l1 *d2) + l2) *w)+ ( (i1*d2) + i2) *w

CONSPART VARPART

其中:前一项子表达式( base – ((l1 *d2) + l2) *w )的值是可以在编译时确定的记为常数CONSPART。

后一子项随i1, i2 而改变是一个变数记VARPART。

二维数组


一般编译程序对数组说明的处理是把数组的有关信息汇集在一个叫“内情向量”的表格中,以便以后计算数组元素的地址时引用这些信息,包括:数组的类型、维数、上、下界,首地址等一般编译程序对数组说明的处理是把数组的有关信息汇集在一个叫“内情向量”的表格中,以便以后计算数组元素的地址时引用这些信息,包括:数组的类型、维数、上、下界,首地址等

如右图。


一般来说一般编译程序对数组说明的处理是把数组的有关信息汇集在一个叫“内情向量”的表格中,以便以后计算数组元素的地址时引用这些信息,包括:数组的类型、维数、上、下界,首地址等,设数组A定义如下

array A[l1:u1,l2:u2,…..ln: un],

元素A[i1,i2,…in]的地址D如下:

D=CONSPART+VARPART

其中CONSPART=a-c

C=(…(l1*d2+l2)*d3+l3)*d4+..+ln-1)*dn+ln

VARPART=

(…(i1*d2+i2)*d3+i3)*d4+..+in-1)*dn+in


访问数组元素一般编译程序对数组说明的处理是把数组的有关信息汇集在一个叫“内情向量”的表格中,以便以后计算数组元素的地址时引用这些信息,包括:数组的类型、维数、上、下界,首地址等A[i1,i2,…in]时可设想为:

把它的VARPART计算在某一变址器T中,用

CONSPART作为“基本地址”,以变址的方式访

问存储单元CONSPART[T] ,对于每个数组,

CONSPART只需计算一次。


(二)含数组元素的赋值语句的翻译一般编译程序对数组说明的处理是把数组的有关信息汇集在一个叫“内情向量”的表格中,以便以后计算数组元素的地址时引用这些信息,包括:数组的类型、维数、上、下界,首地址等

数组的翻译方案是:

产生两组计算数组元素地址的四元式:

一组是计算VARPART,并将计算结果放入临

时变量T1中,另一组是计算CONSPART,并将计算结果放入临时变量T2中,同时用T2[T1表示数组元素的地址。


[一般编译程序对数组说明的处理是把数组的有关信息汇集在一个叫“内情向量”的表格中,以便以后计算数组元素的地址时引用这些信息,包括:数组的类型、维数、上、下界,首地址等例]设A为一个10*20的数组,即d1=10,d2=20并设w=4。对赋值语句X:=A[y,z]

(1) 写出该赋值语句被翻译成三地址代码语句序列。

(2)画出该赋值语句的代注释语法分析树。

解:三地址代码:

T1:=y*20

T1:=T1 + z

T2:= A-84 为: A-(l1*d2 +12 )*w

T3:= 4* T1

T4:= T2 [T3]

x:= T4

数组A的内情向量表


一般编译程序对数组说明的处理是把数组的有关信息汇集在一个叫“内情向量”的表格中,以便以后计算数组元素的地址时引用这些信息,包括:数组的类型、维数、上、下界,首地址等例】 令A是一个10*20的数组即 d1=10, d2=20,求:

(1) 赋值语句 X:= A[I, J ]四元式序列。

(2) 赋值语句A[ I+2 , J+1 ] := M+N四元式序列。

【解】(1)

( * ,I, 20 , T1 )

(+ , J , T1 , T1 )

( - , A , 21 , T2 )

( =[ ] , T2[T1] , , T3)

( := , T3 , , X )


解: (一般编译程序对数组说明的处理是把数组的有关信息汇集在一个叫“内情向量”的表格中,以便以后计算数组元素的地址时引用这些信息,包括:数组的类型、维数、上、下界,首地址等2)

( + , I , 2 , T1 )

( + , J , 1 , T2 )

( * , T1, 20 , T3 )

( + , T2 , T3 , T3 )

( - , A, 21 , T4 )

( + , M, N , T5 )

( [ ] =, T5, , T4[T3] )


练 习一般编译程序对数组说明的处理是把数组的有关信息汇集在一个叫“内情向量”的表格中,以便以后计算数组元素的地址时引用这些信息,包括:数组的类型、维数、上、下界,首地址等

1、写出下列各式的逆波兰表示

(1) -a-(b*c/(c-d) + (-b)*a)

(2) -A+B*C↑ (D/E)/F

2、 写出表达式

A+B*(C-D)-E/F↑G

逆波兰表示, 四元组表示。

3、将下面的语句翻译成四元式序列

while A<C and B<D do

if A=1 then C:=C+1

else A:=A+2


作 业一般编译程序对数组说明的处理是把数组的有关信息汇集在一个叫“内情向量”的表格中,以便以后计算数组元素的地址时引用这些信息,包括:数组的类型、维数、上、下界,首地址等

P202 1、2、3 补充 4


4一般编译程序对数组说明的处理是把数组的有关信息汇集在一个叫“内情向量”的表格中,以便以后计算数组元素的地址时引用这些信息,包括:数组的类型、维数、上、下界,首地址等、已知源程序如下:

i:=1;sum:=0;

while i<=10 do

begin

sum:=sum+a[i]*b[i];

i:=i+1;

end;

按语法制导翻译法将该源程序翻译成四元式

(设每个元素占4个字节)


ad