编译原理 第七章 语法制导翻译和中间代码生成
第7章+语法制导翻译和中间代码生成
![第7章+语法制导翻译和中间代码生成](https://img.taocdn.com/s3/m/c74ad2c75022aaea988f0f10.png)
四元式形式:
31
翻译 a:= -b+c*d
t1:=uminus b
S a := E
t2:=c*d t3:=t1+t2 a:=t3
E1 - E 11
b
+ E 21
c
E2 * E 22
d
32
类型转换
如:X := Y + I * J,X,Y为实型,I,J为整型, 则相应的四元式序列应为: (*i , I , J , T1 ) ( itr , T1 , _ , T2 ) ( +r , Y , T2 , T3 ) ( := , T3 , _ , X )
间接三元式
用一张间接码表辅以三元式表的办法 来表示中间代码。 例:X:=(A+B)*C Y:=D↑(A+B) 三元式表 间接码表 (1) ( + , A , B ) (1) (2) ( * , (1) , C ) (2) (3) (:= , X , (2) ) (3) (4) ( ↑ , D , (1) ) (1) (5) (:= , Y , (4) ) (4) (5)
28
四元式
1. 四元式对中间结果的引用必须通过 给定的名字,而三元式是通过产生中间结 果的三元式编号。四元式之间的联系是通 过临时变量实现的。 2. 四元式出现顺序与原表达式计算顺 序一致。(同三元式)
29
§ 7.6
简单赋值 语句的翻译
30
文法:S→i:=E
E→E+E|E*E|-E|(E)|id
44
if a<b or c<d and e>f then S1 else S2
编译原理张晶版 第七章 语法制导翻译和中间代码生成
![编译原理张晶版 第七章 语法制导翻译和中间代码生成](https://img.taocdn.com/s3/m/017b47e3770bf78a65295472.png)
(1)s=s0
(2)s=s1 (3)s=ε
课程名称
第七章 语法制导翻译和中间代码生成(22)
输入输出对可由(,)表示,其中是输入句子形式而是输出句子形 式。
(S,S)开始用产生式s0s来扩展得到(0S,S0).
再用一次规则(1),得到(00S,S00)。 再用规则(2),就得到(001S,S100). 然后应用规则(3)并得到(001,100)。
L id
T.type=integer T.type:=real
L1.in:=L.in addtype(id.entry,L.in) addtype(id.entry,L.in)
课程名称
第七章 语法制导翻译和中间代码生成(17)
Real id1,id2,id3
D T.type=real real L.in= real L.in= real , id3
E T T F F
T T1 * F F (E) digit
设表达式为3*5+4,则语义动作打印数值19
. L
E.val=19 E.val=15
+
T.val=3 F.val=3 digit.lexval=3 F.val=5
*
F.val=4
digit.lexval=4 digit.lexval=5
课程名称
第七章 语法制导翻译和中间代码生成(23)
课程名称
第七章 语法制导翻译和中间代码生成(3)
属性文法 表达式文法 E—>T+T| T or T T—>n | b ET1 + T2 { T1.type = int T2.type= T1.type E.type :=int} E T1 or T2 { T1.type = bool T2.type= T1.type E.type :=bool} T n { T.type := int} T b { T.type := bool}
编译原理课件 第 7 讲 语法制导翻译和中间代码生成(1)
![编译原理课件 第 7 讲 语法制导翻译和中间代码生成(1)](https://img.taocdn.com/s3/m/02bd8191bed5b9f3f80f1c3d.png)
简单赋值语句的翻译
四元式形式 : t := arg1 op arg2
语义属性:, E.place
E.place:值E的位置
语义函数:lookup() ;
返回指向id的指针
性值。
3*5+4的带注释的分析树
继承属性
出现在产生式右部的文法符号的继承属性是从其所在产生 式左部非终结符和/或右部文法符号的属性值计算出来的;
在分析树中,一个结点的继承属性值是由此结点的父结点 和/或兄弟结点的某些属性来决定的。
生 产式 D TL T int T real L L1,id
L id
翻译成分
E = ET+ E=T T = TF T=F F=E F=a
将下列语句翻译成后缀式: if x>y then y=y+z else x=x+z
错误的翻译: (if E then S1 else S2 翻译成:ES1S2¥) x y > y y z + = x x z + =¥
正确的翻译:
L1
三元式表示
:=
+
*
*
b
c
b
d
树形表示
间接三元式
执行表 三元式表
例如:x:=(a+b)*c
b:=a+b y:=c*(a+b)
间接三元式:
三元式: (1) ( +, a ,b ) (2) ( *, (1),c ) (3) ( :=,(2),x ) (4) ( +, a ,b ) (5) ( :=,(4),b ) (6) ( +, a, b ) (7) ( *, c,(6) ) (8) ( :=,(7),y )
语法制导翻译与中间代码生成
![语法制导翻译与中间代码生成](https://img.taocdn.com/s3/m/636a9d3943323968011c92a1.png)
(2)如果b是产生式右部某个文法符号X的一个属性,并且 c1,c2,„,ck是A或产生式右边任何文法符号的属性,则称b 是文法符号X的继承属性。
2013-8-12 莆田学院许振和 12
综合属性:归约型属性,用于“自下而上”传递信 息。 继承属性:推导型属性,用于“自上而下”传递信 (1)非终结符既可有综合属性也可有继承属性,但文法 息。 开始符号没有继承属性。 (2)终结符只有综合属性,它们由词法程序提供。例 8.1中,E、T和F的val属性是综合属性,例8.2中的L的in 是继承属性。 结点的综合属性值通过分析树中该结点的子结点的属 性值计算。继承属性值由该结点的兄弟结点和父结点的属 性值计算。
莆田学院许振和
18
1、计算语义规则
属性之间的依赖关系, 实质上反映了属性计算 的先后次序
所谓依赖图是一个有向图,用于描述分析 树中的属性和属性间的相互依赖关系。
如果分析树中一结点的属性b依赖于属性c, 那么这个结点的属性b的语义规则的计算必须 在定义属性c的语义规则的计算之后。分析树 结点的继承属性和综合属性间的互相依赖关系 可以用名为依赖图的有向图来描绘。
2013-8-12
莆田学院许振和
13
例5.1
产 生 式
简单算术表达式求值的语义描述 综合属性的例子
语 义 规 则
Print(E.val) L→ E 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
2013-8-12
编译原理chapter7 语义分析及中间代码生成
![编译原理chapter7 语义分析及中间代码生成](https://img.taocdn.com/s3/m/8adcafb765ce0508763213a0.png)
编译原理
chapter7
语义分三元式 三元式顾名思义就是带有三个域的记录结构。 三元式顾名思义就是带有三个域的记录结构。 一般形式为: (i)( ,arg1,arg2) 一般形式为: )(op, )( , ) 其中,( )为三元式的编号, 其中,(i)为三元式的编号,也代表了该式的运算 ,( 结果, , 的含义与四元式类似, 结果,op,arg1,arg2的含义与四元式类似,区别在 , 的含义与四元式类似 于arg可以是某三元式的序号,表示用该三元式的结果 可以是某三元式的序号, 可以是某三元式的序号 作为运算对象。 作为运算对象。
编译原理
chapter7
语义分析和中间代码生成
对于文法G[E]: E →E+T | T 例:对于文法 T→ digit 产生式 ) E→ E(1)+T E→ T T→ digit 语 法 分 析 栈 T + E … # 语义子程序 ) {E.Val=E(1).Val+T.Val} {E.Val=T.Val} {T.Val=digit} T.Val 语 义 ‘+’ ) E(1).Val 分 析 … 栈 #
编译原理
chapter7
语义分析和中间代码生成
三地址代码可以看成是抽象语法树一种线性表示。 三地址代码可以看成是抽象语法树一种线性表示。 线性表示 例: a=b*-c+b*-c = a + T1=-c T2=b*T1 T3=-c
*
b
* - b
c
c
T4=b*T3 T5=T2+T4 a=T5
编译原理
语义分析和中间代码生成
图表示法—抽象语法树 图表示法 抽象语法树 在语法树中去掉一些对翻译不必要的信息后 在语法树中去掉一些对翻译不必要的信息后,获得 去掉一些对翻译不必要的信息 的更有效的源程序的中间表示, 的更有效的源程序的中间表示,这种经过变换后的语法 树称为抽象语法树。 树称为抽象语法树。 内部结点代表操作符,它的孩子代表对应的操作数。 内部结点代表操作符,它的孩子代表对应的操作数。 例:a+a*(b-c)+(b-c)*d ( ) ( ) + + a a b
语法制导翻译和中间代码生成【共50张PPT】
![语法制导翻译和中间代码生成【共50张PPT】](https://img.taocdn.com/s3/m/cfb7fa6aa4e9856a561252d380eb6294dd882287.png)
例 完成类型检查的属性文法
1) E→T1+T2{T1.t=int AND T2.t=int}
2) E→T1 or T2 {T1.t=bool AND T2.t=bool}
3) T→num
{T.t :=int}
4) T→true {T.t :=bool}
5) T→false
{T.t :=bool}
6.1 属性文法(续)
四元式(续)
四元式的优点:
四元式比三元式更便于优化 优化要求改变运算顺序或删除某些运算,引起编号的变化。 三元式通过编号引用中间结果,编号的变化引起麻烦;四元 式通过临时变量引用中间结果,编号变化无影响。
四元式对生成目标代码有利
四元式表示很类似于三地址指令,很容易转换成机器代 码。
四元式(续)
3) E→T
{ E.val :=T.val }
4) T→T1*F { T.val :=T1.val * F.val }
5) T→F
{ T.val :=F.val }
6) F→(E) { F.val :=E.val }
7) F→digit { F.val :=digit.lexval }
E.val、T.val、F.val都是综合属性
每个使用性标识符是否都有声明? 运算符的分量类型是否相容? 赋值语句的左右部的类型是否相容?
➢ 赋值语句的翻译目标:
在赋值语句右部表达式产生的四元式序列后加一 条赋值四元式
简单赋值语句到四元式的翻译
考虑如下文法描述的简单赋值句的翻译: A→i:=E E→E+E|E*E|-E|(E)|i (6.1)
:=
a
+
叶子结点代表运算量, 非叶子结点代表运算符
编译原理中的语法分析与中间代码生成
![编译原理中的语法分析与中间代码生成](https://img.taocdn.com/s3/m/6508287ce55c3b3567ec102de2bd960590c6d9cf.png)
编译原理中的语法分析与中间代码生成编译原理是计算机科学中一门非常重要的学科,主要研究将高级语言翻译成机器语言的方法和技术。
其中,语法分析和中间代码生成是编译器实现的两个重要步骤。
一、语法分析语法分析是编译器将源代码转换成抽象语法树的过程。
在这个阶段,编译器会检查源代码的语法是否符合语言规范,并将代码转化为一系列的语法结构。
一个好的语法分析器能够快速准确地识别代码中的语言结构,同时能够在出现语法错误的时候给出有意义的错误报告。
常见的语法分析方法包括LL(1)分析、LR分析等。
LL(1)分析器通过构造预测分析表来实现分析,而LR分析器则采用自底向上的分析方法,通过状态迁移来实现分析。
在语法分析的过程中,编译器还需要处理语法的优先级,如算术运算符的优先级,逻辑运算符的优先级等。
对于不同的语言规范,将有不同的算法来处理语法。
例如,C语言中的运算符优先级和结合性与其他语言不同,因此需要特殊的处理方式。
二、中间代码生成中间代码生成是语法分析后的下一步,它的作用是将抽象语法树转化为中间表示,通常是三地址码或四地址码。
中间代码可以看作是目标代码的前一步,它是一种更加抽象的代码形式,方便后续的优化和翻译。
中间代码的生成方法有很多种,最常用的是遍历抽象语法树并根据语法结构生成中间代码。
不同的语言规范会对中间代码的生成方式有不同的要求。
例如,Java语言规范对着重于类型检查和异常处理的中间代码生成,而C语言的中间代码生成则着重于指针和数组的处理等。
在生成中间代码的过程中,编译器还需要考虑优化问题。
编译器能够在生成中间代码的时候进行一些基本的优化,例如删除冗余代码、常量合并等等,这样可以减少目标代码的大小和程序的运行时间。
总之,语法分析和中间代码生成是编译器实现的两个关键步骤。
它们需要一个好的算法和优秀的实现方式,以便在编译过程中产生高效、可靠的目标代码。
07-第7章-中间代码生成-编译原理PDF精讲课件-中国科技大学(共13讲)
![07-第7章-中间代码生成-编译原理PDF精讲课件-中国科技大学(共13讲)](https://img.taocdn.com/s3/m/f84c4f472b160b4e767fcf1b.png)
7.2 声 明 语 句
sort readarray exchange quicksort partition readarray 表头 i 空 sort 表头 指向readarray 指向exchange quicksort 表头 k v partition partition a x readarray exchange quicksort exchange 表头
7.2 声 明 语 句
7.2.2 作用域信息的保存 • 所讨论语言的文法
P D; S D D ; D | id : T | proc id ; D ; S sort var a:…; x:…; readarray var i:…; exchange quicksort var k, v:…; partition var i, j:…; 图6.14的程序 参数被略去
E E1 E2 E.nptr = mkNode( ‘’, E1.nptr, E2.nptr) E.nptr = mkUNode( ‘uminus’, E1.nptr) E E1 E (E1) F id E.nptr = E1.nptr E.nptr = mkLeaf (id, id.entry)
7.2 声 明 语 句
本节介绍 • 为局部名字建立符号表条目 • 为它分配存储单元 • 符号表中包含名字的类型和分配给它的存储 单元的相对地址等信息
7.2 声 明 语 句
7.2.1 过程中的声明
7.2 声 明 语 句
计算被声明名字的类型和相对地址 P {offset = 0} D; S DD;D D id : T {enter ( id.lexeme, T.type, offset); offset = offset + T.width } T integer {T.type = integer; T.width = 4 } T real {T.type = real; T.width = 8 } T array [ num ] of T1 {T.type = array (num.val, T1.type); T.width = num.val T1.width} T T1 {T.type = pointer (T1.type); T.width = 4 }
编译程序原理与实现:第7章 中间代码生成(1)
![编译程序原理与实现:第7章 中间代码生成(1)](https://img.taocdn.com/s3/m/b4fd323acdbff121dd36a32d7375a417866fc12b.png)
--- 传值
• 结构语句
• (THEN, t ,_ ,_ )
--- THEN分支标记
• (ELSE, _ , _ ,_ )
--- ELSE分支标记
• (ENDIF, _ , _ , _ )
--- IF语句结束四元式
• (WHILE, _ , _ , _ )
---WHILE语句开始标记
• (DO,t,_ ,_ )
• 三地址中间代码
• 三地址:两个操作分量和一个结果的抽象地址;
• 为方便起见, 通常用变量名代替抽象地址;
• 三元式
• No. (op, operand1, operand2) • 编号 (操作符, 操作分量1, 操作分量2) • 其中操作分量可以是变量名(抽象地址)或者编号
• 四元式
• (op, operand1, operand2, result) • (操作符, 操作分量1, 操作分量2, 结果) • 其中操作分量可以是变量名(抽象地址)或者临时变量(抽象地址)
--- 函数出口
• (CALL, f, true/false, Result) --- 调用函数f,返回值给Result
• (RETURN, -,-, -)
• (RETURN, -,-, t)
• 传递参数
• (VARACT, id, offset, size )
--- 传地址
• (VALACT, id, offset, size )
•
{ op = pop(S1,1); (str1, str2)=pop(S2,2);
•
push(S2, str2+str1 + “op”);
•
}
•
push(S1,tk); goto (2);
编译原理第7章 语法制导翻译和中间代码生成
![编译原理第7章 语法制导翻译和中间代码生成](https://img.taocdn.com/s3/m/b8e32e1faeaad1f347933f24.png)
• 检查静态语义 • 生成中间代码/目标代码
语义处理
语义处理的环境:符号表 • 为语义分析提供类型、作用域等信息。 • 为代码生成提供类型、作用域、存储类别、
存储(相对)位置等信息。
语义处理
PL/0编译程序的语义处理(一)call语句的处理
if sym = callsym
then
源语言程序
词法分析
前
语法分析
端
处理Biblioteka 语义分析语 义 处 理
后 端
代码生成
处
理
汇编代码
语义处理
语义处理的任务: • 静态语义检查
• 静态语义:语法规则的良形式条件 • 静态语义检查:审查静态语义
• 动态语义处理
• 动态语义:程序单元执行的操作 • 动态语义处理:生成(中间/目标)代码
语义处理
语义处理的实现: • 属性文法:描述语义规则。 • 语法制导翻译:在语法分析的同时,执行
类型的基本概念
声明和定义,使用: • 声明:
• 程序通过声明语句把标识符的名称、类型和 作用域等信息传递给编译器。
• 声明语句本身传递名字和类型信息,声明语 句的位置传递作用域信息。
• 定义:
• 变量、类的声明就是定义。 • 函数可以先声明一个原型,在定义中再给出
实现的代码。
类型的基本概念
强类型语言和弱类型语言: • 强类型语言
第七章语法制导翻译和中间代码生成
7.1语义处理概述 7.2属性文法和语法制导翻译 7.3 中间代码生成(一些语句的翻译) 7.4符号表
7.1 语义处理(语义分析和中间代码生成)
在编译中的逻辑阶段
源语言程序
词法分析
编译原理:语法制导翻译和中间代码生成
![编译原理:语法制导翻译和中间代码生成](https://img.taocdn.com/s3/m/a54764834128915f804d2b160b4e767f5acf80ee.png)
中间代码生成的常用方法
三地址码
使用类似于三元表达式的形式 来表示指令,使得生成的代码 更加简洁和高效。
间接中间代码
通过引入临时变量和临时操作 符的方式,将复杂的表达式转 化为更简单的形式。
基于栈的代码生成
将表达式的计算过程用栈来组 织,以实现表达式的计算和结 果的存储。
中间代码表示的形式和结构
符号表达式
编译原理:语法制导翻译 和中间代码生成
在编译原理中,语法制导翻译和中间代码生成是至关重要的步骤。本次演讲 将深入探讨其基本概念、步骤、目的以及常用方法等内容。
语法制导翻译的基本概念
语法制导翻译是基于文法规则和语义分析,将源程序转化为目标程序的过程。它利用文法规则来进行翻译和转 换,以实现对源程序的解释和执行。
使用符号来表示变量、常量和操 作符等,用于描述程序的特定语 义。
抽象语法树
以树的形式组织代码的结构,表 示程序在语法和语义上的结构。
四元式
使用四元组来表示中间代码的指 令和操作数,以便进行翻译和执 行。
中间代码生成的优化技术
1 常量折叠
对于常量表达式,将其直 接计算为常量的值,以减 少运行时的开销。
语法制导翻译的步骤和原理
1
语法分析
通过词法分析和语法分析,将源程序转化为语法树。
2
ห้องสมุดไป่ตู้语义分析
在语法树的基础上,进行类型检查、语义检测和符号表管理。
3
翻译
根据语法树和语义动作,生成目标代码。
中间代码生成的作用和目的
中间代码生成是将源代码转化为一种介于源代码和目标代码之间的中间形式,用于承载程序的执行。 它提供了优化和跨平台的能力,使编译器的输出能够在不同体系结构上正常运行。
语法制导翻译及中间代码生成
![语法制导翻译及中间代码生成](https://img.taocdn.com/s3/m/3772b04e49d7c1c708a1284ac850ad02de80076f.png)
5.1 引言(续)
存在一种称为语法制导翻译的模式,这种模式实际上是对前后文无关文法的一种扩充。
定义 对每个产生式p:X0→X1X2…Xn ,设属性定义性出现的集合为
⒊ Expr→Term Expr’
所有这样这的有种向边模构成式的集既合D把T(T)语,称法为树分T上的析依赖与关系语。义处理分开,又令其平行
属性依赖关系
各个文法符号的属性之间,可能存在某种依赖关系,这 种依赖关系可用属性规则(语义规则)定义。
定义 设p:X0→X1X2…Xn是文法G的一个产生式,则与p
相关联的属性规则集
R(p)={Xi.a=f(Xk1.ak1,…,Xkm.akm)|Xi.a∈A(Xi)}
定义了该产生式所涉及的文法符号之属性的求值规则, 它表示:Xi的a属性是由的Xk1的ak1属性,…,的Xkm的 akm属性计算而得的。
语法制导翻译及中间代 码生成
5.1 引言
词法分析与语法分析仅仅是编译程序的一小部分。 在早期的一些编译程序中,是在语法分析的基础上根
据源程序中各语法成份的语义,直接产生机器语言或 汇编语言形式的目标代码。 现在的编译系统一般都将经过语法分析的源程序先翻 译为某种形式的中间语言代码,然后再将其翻译为目 标代码。 优点:
综合属性与继承属性
定义 对每个产生式p:X0→X1X2…Xn ,设属性定 义性出现的集合为
AF(p)={Xi.a|Xi.a=f(Xk1.ak1,…,Xkm.akm)∈ R(p),0≤kj≤n}
(1)对G中任意两个不同的文法符号X和Y而言,属性集合A(X)和A(Y)不相交,A(X) ∩A(Y)=
。 T→digit {T.
⒉在一个产生式中,每一个符号的各个综合属性的定义互不依赖;
编译第七章语法制导翻译
![编译第七章语法制导翻译](https://img.taocdn.com/s3/m/fc41e73cbceb19e8b9f6ba57.png)
16
第一节 概述
-------树形表示法
-------三元式
-------四元式:最常用的形式
精选PPT
第七章中间代码的生成 1 2
第一节 概述
❖ 二、翻译方法
1、语法制导翻译
----在语法分析的基础上进行边分析边翻译。
●注:1)语法制导翻译时会根据文法产生式右部符 号串的含义进行翻译,翻译的结果是生成相应中间 代码。
精选PPT
15
第一节 概述
❖ 四、常见的中间代码形式 ❖ 2.三元式 ❖ (Operator,Operand1, Operand2) ❖ 注:1)这里三元式本身作为存放结果的单元。
2)为了在其它三元式中利用当前三元式的结果, 需要对三元式进行遍号。三元式的编号就作为相应 三元式的结果值。
精选PPT
第七章语法制导翻 译和中间代码生成
精选PPT
1
第一节 概述
❖ 语法分析之后,编译的任务是由已识别为正确的源程 序生成一组规格一致,便于计算机加工的指令形式。
一、中间代码生成方法
语法制导翻译,属性文法制导翻译
二、中间代码
●中间代码:不是机器语言,便于生成机器语言,便于代 码优化。
●中间代码的形式:
-------逆波兰式
S3
S2
r4
r4
S3
S2
S3
S2
S4
S5
r1(S4) S5(r1)
r1(S4) r2(S5)
r3
r3
精选PPT
)#
acc
r4 r4
S9 r1 r1 r2 r2 r3 r3
GOTO S 1 6 7 8
13
步骤 状态
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第七章语法制导翻译和中间代码生成编译程序的任务是把源程序翻译成目标程序,这个目标程序必须和源程序的语义等同,也就是说,尽管它们的语法结构完全不同,但它们所表达的结果应完全相同。
通常,在词法分析程序和语法分析程序对源程序的语法结构进行分析之后,要么由语法分析程序直接调用相应的语义子程序进行语义处理,要么首先生成语法树或该结构的某种表示,再进行语义处理。
编译中的语义处理是指两个功能:第一,审查每个语法结构的静态语义,即验证语法结构合法的程序是否真正有意义。
第二,如果静态语义正确,语义处理则要执行真正的翻译,即,要么生成程序的一种中间表示形式(中间代码),要么生成实际的目标代码。
为什么有的编译程序直接生成目标代码,有的编译程序采用中间代码,所谓中间代码,也称中间语言,是复杂性介于源程序语言和机器语言的一种表示形式。
一般,快速编译程序直接生成目标代码,没有将中间代码翻译成目标代码的额外开销。
但是为了使编译程序结构在逻辑上更为简单明确,常采用中间代码,这样可以将与机器相关的某些实现细节置于代码生成阶段仔细处理,并且可以在中间代码一级进行优化工作使得代码优化比较容易实现。
本章重点:属性文法、语法制导翻译方法的基本思想、几种典型的中间代码形式、一些语法成分的翻译工作。
第一节属性文法现在很多编译程序采用语法制导翻译方法。
这仍不是一种形式系统,但它是比较接近形式化的。
这种方法使用属性文法为工具来说明程序设计语言的语义。
一个属性文法包含一个上下文无关文法和一系列语义规则,这些语义规则附在文法的每个产生式上,在语法分析过程中,完成附加在所使用的产生式上的语义规则描述的动作,从而实现语义处理。
首先简单介绍属性文法。
属性,常用以描述事物或人的特征、性质、品质等等。
比如,谈到一个物体,可以用“颜色”描述它,谈起某人,可以使用“有幽默感”来形容他。
对编译程序使用的语法树的结点,可以用“类型”、“值”或“存储位置”来描述它。
形式上讲,一个属性文法是一个三元组,A=(G,V,F),一个上下文无关文法G;一个属性的有穷集V和关于属性的断言或谓词的有穷集F。
每个属性与文法的某个非终结符或终结符相联。
每个断言与文法的某产生式相联。
如果对G中的某一输入串而言(句子),A中的所有断言对该输入串的语法树结点的属性全为真,则该串也是A语言中的句子。
编译程序的静态语义审查工作就是验证关于所编译的程序的断言是否全部为真。
比如,有文法G为:E→T1+T2|T1orT2T→num|true|false因为T在同一个产生式里出现了两次,使用上角标将它们区分开。
对输入串3+4的语法树如图7-1-1(a)相联的属性t。
比如可把完成对上面表达式的类型检查的属性文法写成图7-1-2的形式。
与每个非终结符T相联的有属性t,t要么是int,要么是bool。
与非终结符E的产生式相联的断言指明:两个T的属性必须相同。
图7-1-1(b)是图7-1-1(a)语法树结点带有语义信息的表示。
E→T1+T2 {T1.t=int AND T2.t=int } T→true{T.t:=bool}E→T1orT2 {T1.t=bool AND T2.t=bool } T→false{T.t:=bool}T→num{T.t:=int}图7-1-2 类型检查的属性文法属性文法最早出自克努特笔下。
他把属性分成两类:继承属性和综合属性,我们不对属性文法进行理论上的研究而仅仅将它做为工具描述语义分析。
在编译的许多实际应用中,属性和断言以多种形式出现,也就是说,与每个文法符号相联的可以是各种属性、断言、以及语义规则,或者某种程序设计语言的程序段等等。
下面再给出一些例子。
例1: 简单算术表达式求值的语义描述。
产生式 语义规则(0)L →E print(E.val)(1)E→E 1+T E.val :=E 1.val+T.val(2)E→T E.val :=T.val(3)T→T 1*F T.val :=T 1.val ×F.val(4)T→F T.val :=F.val(5)F→(E) F.val :=E.val(6)F→digit F.val :=digit.lexval在该描述中,每个非终结符都有一个属性:一个整数值的称作val 的属性。
按照语义规则对每个产生式来说,它的左部E ,T ,F 的属性值的计算来自它右部的非终结符,这种属性称作综合属性。
单词digit 仅有综合属性,它的值是由词法分析程序提供的。
和产生式L →E 相联的语义规则是一个过程,打印由E 产生的表达式的值。
我们可以理解为L 的属性是空的或是虚的。
第二节 语法制导翻译概论在语法分析过程中,随着分析的步步进展,根据每个产生式所对应的语义子程序(或语义规则描述的语义动作)进行翻译的办法称作语法制导翻译。
假定我们现在要分析的语法成分是简单算术表达式,所完成的语义的处理不是将它翻译成中间代码或目标代码,而是计算表达式的值。
采用的描述系统是上节的例1。
假如语法分析方法是自下而上的。
在用某一产生式进行归约的同时就执行相应的语义动作,在分析出一个句子时,这个句子的“值”也就同时产生了,例如输入串是2+3*5,其语法树如图7-2-1(a),在第一步归约用到了产生式(6),执行的语义动作是置F.val 的值为单词digit 值,我们把语法树中每个结点的语义值括在该结点处。
那么第一步归约并完成语义动作后的情形在图7-2-1(b)中指出。
继续进行分析,第七次归约后的情形在图7-2-1(c)中指出归约至E 时,它的值17也计算出来了。
语法制导翻译的具体实现途径不困难。
假定有一个LR 语法分析器,现在把它的分析栈扩充,同时把LR分析器的能力扩大,使它不仅执行语法分析任务,且能在用某个产生式进行归约的同时调用相应的语义子程序,完成在例1的属性文法中描述的语义动作。
每步工作后的语义值保存在扩充的分析栈里“语义值”栏中。
采用的LR分析表见图7-2-3,其中使用d代替digit。
分析和计值2+3*5的过程列在图7-2-4中。
按照上述实现办法,若把语义子程序改为产生某种中间代码的动作,那么则可在语法分析的制导下,随着分析的进展逐步生成中间代码。
步骤归约动作状态栈语义栈(值栈)符号栈留余输入串1)0 —# 2+3*5#2)05 ——#2 +3*5#3)r6 03 —2 #F +3*5#4)r4 02 —2 #T +3*5#5)r2 01 —2 #E +3*5#6)016 —2—#E+ 3*5#7)0165 —2——#E+3 *5#8)r6 0163 —2—3 #E+F *5#9)r4 0169 —2—3 #E+T *5#10)01697 —2—3—#E+T* 5#11)016975 —2—3——#E+T*5 #12)r6 01697(10) —2—3—5 #E+T*F #13)r3 0169 —2—(15) #E+T #14)r1 01 -(17)#E #15)接受图7-2-4 2+3*5的分析和计值过程第三节中间代码的形式编译程序所使用的中间代码有多种形式。
常见的有逆波兰记号、三元式、四元式和树形表示。
下面分别介绍。
一、逆波兰记号逆波兰记号是最简单的一种中间代码表示形式,早在编译程序出现之前,它就用于表示算术表达式,是波兰逻辑学家卢卡西维奇发明的。
这种表示法将运算对象写在前面,把运算符号写在后面,比如把a+b写成ab+,把a*b写成ab*,用这种表示法表示的表达式也称做后缀式。
图7-3-1给出了程序设计语言中的简单表达式和赋值语句a+b*c abc*+(a+b)*c ab+c*a :=b*c+b*d abc*bd*+:=图7-3-1 逆波兰表示后缀表示法表示表达式,其最大的优点是最易于计算机处理表达式。
利用一个栈,自左至右扫描算术表达式(后缀表示)。
每碰到运算对象,就把它推进栈;碰到运算符,若该运算符是二目的,则对栈顶部的两个运算对象实施运算,并将运算结果代替这两个运算对象而进栈。
若是一目运算符,则对栈顶元素执行该运算,并以运算结果代替该元素进栈。
最后的结果留在栈顶。
例如 B@CD*+(它的中缀表示为—B+C*D ,使用@表示一目减)的计值过程为:1、B 进栈;2、对栈顶元素施行一目减运算,并将结果代替栈顶,即—B 置于栈顶;3、C 进栈;4、D 进栈;5、栈顶两元素相乘,两元素退栈,相乘结果置栈顶;6、栈顶两元素相加,两元素退栈,相加结果进栈,现在栈顶存放的是整个表达式的值。
由于后缀式表示上的简洁和计值的方便,特别适用于解释执行的程序设计语言的中间表示,也方便具有堆栈体系的计算机的目标代码生成。
逆波兰表示很容易扩充到表达式以外的范围。
二、 三元式和树形表示另一类中间代码形式是三元式。
把表达式及各种语句表示成一组三元式。
每个三元式三个组成部分是:算符op ,第一运算对象ARG1,和第二运算对象ARG2。
例如:a :=b*c+b*d 的表示为:(1)(* b , c )(2)(* b , c )(3)(+ (1), (2))(4)(:= (3), a )与后缀式不同,三元式中含有对中间计算结果的显式引用,比如三元式(1)表示的是b*c 的结果。
三元式(3)中的(1)和(2)分别表示第一个三元式和第二个三元式的结果。
对于一目算符op ,只需选用一个运算对象,不防规定只用ARG1。
至于多目算符,可用若干个相继的三元式表示。
表达式的树形表示很容易实现:简单变量或常数的树就是该变量或常数自身,如果表达式e 1和e 2的树分别为T 1和T 2,那么e 1+ e 2,e 1* e 2,—e 1的树分别为:树可以通过引进新结而表示成一棵二叉子树。
三、 四元式四元式是一种比较普遍采用的中间代码形式。
四元式的四个组成成分是:算符op ,第一和第二运算对象ARG1和ARG2及运算结果RESULT 。
运算对象和运算结果有时指用户自己定义的变量,有时指编译程序引进的临时变量。
例如a:=b*c+b*d 的四元式表示如下:(1)(*, b, c, t1)(2)(*, b, d, t2)(3)(*, t1, t2, t3)(4)(:=, t3, —, a)四元式和三元式的主要不同在于,四元式对中间结果的引用必须通过给定的名字,而三元式是通过产生中间结果的三元式编号。
也就是说,四元式之间的联系是通过临时变量实现的。
四元式表示很类似于三地址指令,有时把这类中间表示称为“三地址代码”因为这种表示可看作一种虚拟三地址机的通用汇编码,即这种虚拟机的每条“指令”包含操作符和三个地址,两个是为运算对象的,一个是为结果的。
这种表示对于代码优化的目标代码生成都较有利。
为了更直观,把四元式的形式写成简单赋值形式。
比如把上述四元式序列写成:(1)t1:=b*c(2)t2:=b*d(3)t3:= t1+ t2(4)a:= t3把(jump,—,—,L)写成goto L把(jrop,B,C,L)写成if B rop C goto L为了叙述的方便,两种形式我们将同时使用。