1.19k likes | 1.51k Views
第 8 章 语法制导翻译和中间代码生成. 教学目的: [1] 掌握语法制导翻译基本原理。 [2] 了解自上而下分析制导翻译基本思想和实现方法。 [3] 掌握几种常用的中间代码:四元式、三元式、逆波兰表示。 [4] 掌握简单表达式的中间代码生成。. 教学重点: 语法制导翻译基本思想、中间代码的形式、布尔表达式的翻译与控制结构的翻译;布尔表达式与控制结构的语义过程。. 学时分配: 8 学时. 本章内容. 8.1 属性文法. 8.2 语法制导翻译概论. 8.3 中间代码的形式. 8.4 简单赋值语句的翻译. 8.5 布尔表达式的翻译.
E N D
第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的语义规则 产生式 语义规则 DTL Lin:=T type T int T type :=int T real T type :=real L L1,id L1in :=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 ) 对应于产生式 AXY的语义规则,这条语义规则确定了依赖于属性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. 如果与产生式AXY对应的语义规则还有: X .i:=g(A.a,Y.y) 那么,图中还应有两条有向边,一条从A.a连到X.i,另一条从Y.y连到X.i ,因为X.i依赖于A.a和Y.y.
【例】 产生式 语义规则 EE1+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分析树的依赖图 产生式 语义规则 DTL Lin:=T type T int T type :=integer T real T type :=real L L1,id L1in :=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(id3entry,a5); a7:=a5; addtype(id2entry,a7); a9:=a7; addtype(id1entry,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 ... ...
语义处理采用的方法—语法制导(将语义处理的描述和文法的产生式关联起来)语法分析的同时完成语义处理语义处理采用的方法—语法制导(将语义处理的描述和文法的产生式关联起来)语法分析的同时完成语义处理 【例】类形检查 产生式 语义规则 ET1 + 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-属性的语法制导定义 产生式 语义规则 ALM 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. 有综合属性的情况: 为每一个语义规则建立一个包含赋值的动作,并把该语义动作放在相应规则右部之末端,便得到翻译方案。 【例如】TT1*F Tval:=T1 val*F val TT1*F { Tval:=T1 val*F val}
2.既有综合属性又有继承属性。在建立翻译模式时要满足下列三个条件:2.既有综合属性又有继承属性。在建立翻译模式时要满足下列三个条件: • 产生式右边的符号的继承属性必须在这个符号以前的动作中计算出来。 • 一个动作不能引用这个动作右边的符号的综合属性。 • 产生式左边非终结符号的综合属性只有在它所引用的所有属性都计算出来以后才能计算。计算这种属性的动作通常可放在产生式右端的未尾。
【例】 SA1A2 {A1in:=1; A2 in:=2} A a { print(A in) } 【分析】该翻译模式不满足要求。因为按深度优先遍历输入串aa的语法树,当要打印第二个产生式A.in时的值时,该属性还没有定义。如果计算A1in, A2 in值的动作分别嵌在产生式SA1A2 的右部A1和A2之前而不是最后,那么A.in在每次执行print(A in) 时就已经有定义了。
练 习 【例】 在一个移入——归约的分析中采用以下的语法制导的翻译模式,在某产生式归约时,立即执行括号中的动作。 A→aB {print “0” } A→c {print “1” } B→Ab { print “2” } 当分析器输入为aacbb时,打印的字符串是什么?