1、语法制导翻译,静态语义分析 这一步才真正开始考虑程序设计语言的实际意义 静态语义分析的作用:检查出源程序中的静态语义错误 并且将语义正确的语句翻译成中间代码 该过程中通常使用的方法是语法制导翻译,1,由苏州翻译公司推荐,2,第四章 语法制导翻译生成中间代码,语法制导翻译是处理语义的基本方法,它以语法分析为基础,在语法分析得到语言结构的结果时,对附着于此结构的语义进行处理,如计算表达式的值、生成中间代码等。 主要内容包括: 语法制导翻译的基本概念 中间代码简介 符号表简介 典型声明语句与可执行语句的翻译,3,4.1 语法制导翻译简介,语法与语义 语法与语义的关系 语法是指语言的结构、即语言的“样
2、子”;语义是指附着于语言结构上的实际含意 ,即语言的“意义”。 语义不能离开语法独立存在; 语义远比语法复杂; 同一语言结构可包含多种含意,不同语言结构可表示相同含意; 语法与语义之间没有明确的界线。例1 猫吃老鼠与老鼠吃猫,晒被子与晒太阳(语法正确不一定语义正确),4,4.1 语法制导翻译简介,语义分析的两个作用 检查是否结构正确的句子所表示的意思也合法; 执行规定的语义动作,如: 表达式求值 符号表填写 中间代码生成等 语义分析的方法语法制导翻译,基本思想:将语言结构的语义以属性的形式赋予代表此结构 的文法符号,而属性的计算以语义规则的形式赋予由文法符 号组成的产生式,在语法分析推导或者规
3、约的每一步骤中, 通过语义规则实现对属性的计算。,5,4.1 语法制导翻译简介,属性与语义规则 语法制导翻译的基本思想为每个产生式配上语义规则并且在适当的时候执行这些规则 具体方法: 将文法符号所代表的语言结构的意思,用附着于该文法符号的属性表示; 用语义规则规定产生式所代表的语言结构之间的关系(即属性之间的关系),即用语义规则实现属性计算。 语义规则的执行:在语法分析的适当时刻(如推导或归约)执行附着在对应产生式上的语义规则,以实现对语言结构语义的处理,如计算、查填符号表、生成中间代码、发布出错信息等。,6,4.1 语法制导翻译简介,属性的表示.attr如:E.val(值),E.type(类
4、型),E.code(代码序列),E.place(存储空间)属性在程序设计中的具体表示可以根据实际情况采用适当的数据结构或者程序代码来实现 语义规则定义定义4.1 对于产生式A,其中是由文法符号X1X2.Xn组成的序列,它的语义规则可以表示为(4.1)所示关于属性的函数:b := f(c1, c2, ., ck) (4.1),7,4.1 语法制导翻译简介,A 的语义规则 b := f(c1, c2, ., ck) (4.1) 语义规则中的属性存在下述性质与关系。 若b是A的属性,c1, c2, ., ck是中文法符号的属性,或者A的其它属性,则称b是A的综合属性。 若b是中某文法符号Xi的属性,
5、c1, c2, ., ck是A的属性,或者是中其它文法符号的属性,则称b是Xi的继承属性。 称(4.1)中属性b依赖于属性c1, c2, ., ck。 若语义规则的形式如下述(4.2),则可将其想像为产生式左部文法符号A的一个虚拟属性。属性之间的依赖关系,在虚拟属性上依然存在。f(c1, c2, ., ck) (4.2) (4.1)中属性之间的依赖关系,实质上反映了属性计算的先后次序,即所有属性ci被计算之后才能计算属性b。,8,4.1 语法制导翻译简介,语义规则的两种形式 语法制导定义用抽象属性和运算符号表示的语义规则 翻译方案用具体属性和运算表示的语义规则语义规则也被习惯上称为语义动作。
6、二者作用等价,语法制导定义适用于设计阶段,翻译方案适用 于实现阶段。,9,4.1 语法制导翻译简介,例4.1 将中缀形式的算术表达式转换为后缀表示。其语法制导定义和翻译方案可分别表示如下。其中print(E.post)是L的虚拟属性,即L.p := print(E.post)。翻译方案中的.lexval表示词法分析返回的记号num的值。,10,4.1 语法制导翻译简介,语法制导定义只考虑“做什么”.post表示表达式的后缀式|表示后缀式的连接属性和运算的具体实现细节不在语法制导定义的考虑范围,11,4.1 语法制导翻译简介,翻译方案不但考虑做什么还要考虑如何做例子中用数组post存放表达式的后
7、缀形式由num归约得到的子表达式E的后缀式就是它自身归约由两个子表达式和加号组成的表达式时,两个子表达式以分析过,已经分别按从左到右的顺序放在post中,此时仅需将+添加到post中,12,4.1 语法制导翻译简介,从某种意义上来说,语法制导定义类似于算法,而翻译方案类似于程序 由于翻译方案与具体的实现密切相关,因此不同实现方法可以达到相同的目的(不唯一),另一种翻译方案:无需存放中间过程,直接在分析的过程中输出表达式的后缀形式。 原因:自下而上分析过程是对表达式分析树的一次后续遍历,而遍历次序与表达式的后缀表示正好一致。,13,4.1 语法制导翻译简介,翻译方案中需要考虑的问题: 采用什么样
8、的语法分析方法,不同的分析方法对语义处理的次序不同 为属性分配存储空间 考虑计算次序 翻译方案1,自下而上计算,LR分析。以3+5+8为例,归约时翻译。,post:(3 5 + 8 +),14,4.1 语法制导翻译简介,属性作为分析树的注释将属性附着在分析树对应文法符号上,形成注释分析树。 例4.2 3+5+8的分析树和注释分析树:,.post=3,.post=5,.post=8,.post=35+,.post=35+8+,(print(35+8+),15,4.1 语法制导翻译简介,注释分析树上看继承属性与综合属性 继承属性是自上而下计算的 综合属性是自下而上计算的 提醒:除非特别提醒,本章讨
9、论的语法制导翻译是综合属性。,.post=3,.post=5,.post=8,.post=35+,.post=35+8+,(print(35+8+),16,4.1 语法制导翻译简介,LR分析翻译方案的设计 LR分析中的语法制导翻译实质上是对LR语法分析的扩充: 扩充LR分析器的功能:当执行归约产生式的动作时,也执行产生式对应的语义动作。由于是归约时执行语义动作,限制语义动作仅能放在产生式右部的最右边; 扩充分析栈:增加一个与分析栈并列的语义栈,用于存放分析栈中文法符号所对应的属性值。例如: EE1+E2 valtop:=valtop+valtop-2;对于表达式5+3当归约为左部E时同时也得到
10、了值8,17,例4.3 3+5*8的语法制导翻译。 产生式 LE EE1+E2 EE1*E2 En 分析栈 语义栈 输入 语义动作 # # 3+5*8# shift #n #3 +5*8# En, valtop:=lexval #E #3 +5*8# shift #E+ #3? 5*8# shift #E+n #3?5 *8# En, valtop:=lexval #E+E #3?5 *8# shift #E+E* #3?5? 8# shift #E+E*n #3?5?8 # En, valtop:=lexval #E+E*E #3?5?8 # EE1*E2, valtop:=valtop*v
11、altop-2 #E+E #3?40 # EE1+E2, valtop:=valtop+valtop-2 #E #43 # acc,翻译方案 print(valtop); valtop:=valtop+valtop-2; valtop:=valtop*valtop-2; valtop:=lexval;,语法制导定义 print(E.val) E.val:=E1.val+E2.val; E.val:=E1.val*E2.val; E.val:=n.lexval;,18,4.1 语法制导翻译简介,递归下降分析翻译方案的设计 递归下降方法是用程序实现对非终结符的展开和对终结符的匹配。翻译方案的设计需
12、要解决两个问题: 如何在递归下降子程序中嵌入语义动作?产生式右部的任何位置; 如何为文法符号的属性设计存储空间?函数返回值、参数、变量等。,19,4.2 中间代码简介,编译器各阶段的完整输出,均可以被认为是源程序的某种中间表示。 本章讨论的是中间代码生成器输出的中间表示,称之为中间代码。 中间代码实际上应起一个编译器前端与后端分水岭的作用。 要求中间代码具有如下特性,以便于编译器的开发移植和代码的优化: 便于语法制导翻译; 既与机器指令的结构相近,又与具体机器无关。 中间代码的主要形式:树、后缀式、三地址码等。,20,4.2 中间代码简介,后缀式 操作数在前,操作符紧随其后,无需用括号限制运算
13、的优先级和结合性。 算法4.1 后缀式计算 采用下述过程进行计算,最终结果留在栈中。x := first_token;while not end_of_exp loop if x in operatorsthen push x; - 操作数进栈else pop(operators); - 算符,弹出操作数 push(evaluate); - 计算,将结果进栈end if;next(x);end loop;,21,4.2 中间代码简介,loop if x in operatorsthen push x; - 操作数进栈else pop(operators); - 算符,弹出操作数 push(ev
14、aluate); - 计算,将结果进栈end if;next(x); end loop;算术表达式3+5+8的后缀式为35+8+。 # 35+8+# push(3) #3 5+8+# push(5) #35 +8+# pop(3和5),push(3+5) #8 8+# push(8) #88 +# pop(8和8),push(8+8) #16 #,22,4.2 中间代码简介,后缀式并不局限于二元运算的表达式,可以推广到任何语句,遵守操作数在前,操作符紧跟其后的原则即可。 对语句: if e then x else y 后缀式可以写为: e x y if-then-else (1) 此时e、x和
15、y均需计算。 实际上,根据条件e的取值,x和y不用都计算:e p1 jez x p2 jump p1: y p2: (2) 其中:p1和p2分别是标号;p1 jez表示e的结果为0(假)则转向p1;p2 jump表示无条件转向p2。 与 (1)比较,(2)中的if-then-else被分解,首先计算e,根据e的结果是否为真,决定计算x还是计算y。,23,4.2 中间代码简介,三地址码 三地址码的直观表示 语法:result := arg1 op arg2 或result := op arg1 或 op arg1 语义:结果存放在result中的二元运算arg1 op arg2结果存放在resu
16、lt中一元运算op arg1一元运算op arg1 赋值句x := a + b * c的三地址码序列:T1 := b * cT2 := a + T1x := T2,24,4.2 中间代码简介,三地址码的种类(三地址码指令集合) 序号 三地址码 (1) x := y op z (2) x := op y (3) x := y (4) goto L (5) if x goto L (6) if x relop y goto L (7) param x (8) call n, P (9) return y (10) x := yi (11) xi := y (12) x := &y (13) x := *y (14) *x := y,25,内容总结,语法制导翻译的基本概念 属性与语义规则 语义规则的两种形式 LR分析翻译方案的设计 递归下降分析翻译方案的设计 中间代码 后缀式 三地址码,谢 谢 http:/,