西安电子科技大学《编译原理.ppt

上传人:xin****828 文档编号:15526556 上传时间:2020-08-17 格式:PPT 页数:41 大小:653KB
返回 下载 相关 举报
西安电子科技大学《编译原理.ppt_第1页
第1页 / 共41页
西安电子科技大学《编译原理.ppt_第2页
第2页 / 共41页
西安电子科技大学《编译原理.ppt_第3页
第3页 / 共41页
点击查看更多>>
资源描述
1,第四章 语法制导翻译生成中间代码,语法制导翻译是处理语义的基本方法,它以语法分析为基础,在语法分析得到语言结构的结果时,对附着于此结构的语义进行处理,如计算表达式的值、生成中间代码等。 与语法分析部分的讨论不同,本章的内容更注重于实际方法的讨论。 主要内容包括: 语法制导翻译的基本概念 中间代码简介 符号表简介 典型声明语句与可执行语句的翻译 上机作业第三部分:语法制导翻译绘制函数图形,2,4.1 语法制导翻译简介4.1.1 语法与语义, 语法与语义的关系 语法是指语言的结构、即语言的“样子”;语义是指附着于语言结构上的实际含意 ,即语言的“意义”。 对于语法和语义: 语义不能离开语法独立存在; 语义远比语法复杂; 同一语言结构可以包含多种含意,不同语言结构表示相同含意; 语法与语义之间没有明确的界线。,例1:猫吃老鼠与老鼠吃猫 例2:程序设计语言中的分情况结构:,1case condition is case1: stat1; case2: stat2; . end case;,2switch (condition) case condition1:stat1; case condition2:stat2; . ,break; break;,3,4.1.1 语法与语义(续1), 语义分析的两个作用 检查是否结构正确的句子所表示的意思也合法; 执行规定的语义动作,如: 表达式求值 符号表填写 中间代码生成等 语义分析的方法 语法制导翻译,(2004年3月31日在此结束),4,4.1.2 属性与语义规则, 语法制导翻译的基本思想 通俗地讲: 以语法分析为基础,伴随语法分析的各个步骤,执行相应的语义动作。 具体方法: 1将文法符号所代表的语言结构的意思,用附着于该文法符号的属性表示; 2用语义规则规定产生式所代表的语言结构之间的关系(即属性之间的关系),即用语义规则实现属性计算。 语义规则的执行: 在语法分析的适当时刻(如推导或归约)执行附着在对应产生式上的语义规则,以实现 对语言结构语义的处理,如计算、查填符号表、生成中间代码、发布出错信息等。,5,4.1.2 属性与语义规则(续1), 属性的抽象表示 .attr 例如:E.val(值) E.type(类型) E.code(代码序列) E.place(存储空间) 对文法的约定 本章关注的是语法分析的基础上的语义处理,忽略语法分析。 为了简单,本章的文法一般为二义文法。默认解决二义的方法是规定常规意义下的优先级和结合性。,6,4.1.2 属性与语义规则(续2), 属性的定义* 定义4.1 对于产生式A,其中是由文法符号X1X2.Xn组成的序列,它的语义规则可以表示为(4.1)所示关于属性的函数: b := f(c1, c2, ., ck) (4.1) 语义规则中的属性存在下述性质与关系。 (1) 若b是A的属性,c1, c2, ., ck是中文法符号的属性,或者A的其它属性,则称b是A的综合属性。 (2) 若b是中某文法符号Xi的属性,c1, c2, ., ck是A的属性,或者是中其它文法符号的属性,则称b是Xi的继承属性。 (3) 称(4.1)中属性b依赖于属性c1, c2, ., ck。 (4) 若语义规则的形式如下述(4.2),则可将其想像为产生式左部文法符号A的一个虚拟属性。属性之间的依赖关系,在虚拟属性上依然存在。 f(c1, c2, ., ck) (4.2) ,(4.1)中属性之间的依赖关系,实质上反映了属性计算的先后次序,即所有属性ci被计算之后才能计算属性b。,EE1+E2 E.val:=E1.val+E2.val,EE1+E2 print(E.val),7,4.1.3 语义规则的两种形式, 语法制导定义 用抽象的属性和运算符号表示的语义规则;(公式,做什么) 翻译方案 用具体属性和运算表示的语义规则。(程序段,如何做) 语义规则也被习惯上称为语义动作。 忽略实现细节,二者作用等价。(设计与实现),8,4.1.3 语义规则的两种形式(续1),例4.1 将中缀形式的算术表达式转换为后缀表示的语法制导定义和翻译方案。虚拟属性print(E.post)可想象为L.p:=print(E.post)。,产生式 LE EE1+E2 Enum,语法制导定义 print(E.post) E.post:=E1.post |E2.post|+; E.post:=num.lexval;,翻译方案1 print_post(post); post(k):=+; k:=k+1; post(k):=lexval; k:=k+1;,翻译方案中需要考虑的问题: 1采用什么样的语法分析方法; 2为属性分配存储空间; 3考虑计算次序。,产生式 翻译方案2 LE EE1+E2 print(+); Enum print(lexval);,语法制导定义算法 翻译方案程序实现,多种方法,翻译方案1,自下而上计算,LR分析。 (以3+5+8为例,归约时翻译),post:(3 5 + 8 +),9,4.1.3 语义规则的两种形式(续2), 属性作为分析树的注释 将属性附着在分析树对应文法符号上,形成注释分析树。,产生式 语法制导定义 翻译方案 LE print(E.post); EE1+E2 E.post:=E1.post print(+); |E2.post|+; Enum E.post:=num.lexval; print(lexval);,例4.2 3+5+8的分析树和注释分析树:,.post=3,.post=5,.post=8,.post=35+,.post=35+8+,(print(35+8+),10,4.1.3 语义规则的两种形式(续3), 注释分析树上看继承属性与综合属性 继承属性是自上而下计算的 综合属性是自下而上计算的 提醒:除非特别提醒,本章讨论的语法制导翻译是综合属性。,11,4.1.4 LR分析翻译方案的设计,LR分析中的语法制导翻译实质上是对LR语法分析的扩充: 扩充LR分析器的功能:当执行归约产生式的动作时,也执行产生式对应的语义动作。由于是归约时执行语义动作,因此限制语义动作仅能放在产生式右部的最右边; 扩充分析栈:增加一个与分析栈并列的语义栈,用于存放分析栈中文法符号所对应的属性值。,例如: EE1+E2 valtop:=valtop+valtop+2;,对于表达式: 5+3,当归约为左部E时, 同时也得到了值8。,12,4.1.4 LR分析翻译方案的设计(续1),例4.3 3+5*8的语法制导翻译。,语法制导定义 print(E.val) E.val:=E1.val+E2.val; E.val:=E1.val*E2.val; E.val:=n.lexval;,翻译方案 print(valtop); valtop:=valtop+valtop+2; valtop:=valtop*valtop+2; valtop:=lexval;,产生式 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*valtop+2; #E+E #3?40 # EE1+E2,valtop:=valtop+valtop+2; #E #43 #acc,13,4.1.5 递归下降分析翻译方案的设计,递归下降方法是用程序实现对非终结符的展开和对终结符的匹配。翻译方案的设计需要解决两个问题: 1如何在递归下降子程序中嵌入语义动作: 产生式右部的任何位置; 2如何为文法符号的属性设计存储空间: 函数返回值、参数、变量等。,例 函数绘图语言的解释器中语法制导翻译的设计: 1递归子程序可以设计为函数,用于返回必要的属性值; 2适当设计子程序中的临时变量,用于保存属性值; 3将语义动作嵌入在子程序的适位置,正确计算属性值。 (第三次上机课介绍),阅读:95页的例4.4,14,4.2. 中间代码简介,编译器各阶段的完整输出,均可以被认为是源程序的某种中间表示。 本章讨论的是中间代码生成器输出的中间表示,称之为中间代码。 中间代码实际上应起一个编译器前端与后端分水岭的作用。 要求中间代码具有如下特性,以便于编译器的开发移植和代码的优化: 1便于语法制导翻译; 2既与机器指令的结构相近,又与具体机器无关。 中间代码的主要形式:树、后缀式、三地址码等。,15,4.2.1 后缀式, 后缀式的特征 操作符在前,操作数紧随其后,无需用括号限制运算的优先级和结合性。 计算后缀式的虚拟机,算法4.1 后缀式计算 输入 后缀式 输出 计算结果 方法 采用下述过程进行计算,最终结果留在栈中。,x := first_token; while not end_of_exp loop if x in operators then push x; - 操作数进栈 else pop(operators); - 算符,弹出操作数 push(evaluate); - 计算,并将结果进栈 end if; next(x); end loop; ,16, 后缀式计算 4.2.1 后缀式(续1),算术表达式3+5+8的后缀式为35+8+。 算法4.1的计算: (#35+8+#进栈) (#3 5+8+#进栈) (#35 +8+#弹出3和5,计算3+5,结果进栈) (#8 8+#进栈) (#88 +#弹出8和8,计算8+8,结果进栈) (#16 # ),x := first_token; while not end_of_exp loop if x in operators then push x; - 操作数进栈 else pop(operators); - 算符,弹出操作数 push(evaluate); - 计算,并将结果进栈 end if; next(x); end loop;,17, 将后缀式推广到其他语句 4.2.1 后缀式(续2),后缀式并不局限于二元运算的表达式,可以推广到任何语句,只要遵守操作数在前,操作符紧跟其后的原则即可。 语句:if e then x else y 它的后缀式可以写为: e x y if-then-else(1) 上述表示中,e、x和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。,18,4.2.2 三地址码, 三地址码的直观表示 语法: 语义:,例如: 赋值句x := a + b * c的三地址码序列: T1 := b * c T2 := a + T1 x := T2 注意:直观表示与源程序中赋值句的区别。,result := arg1 op arg2 或 result := op arg1 或 op arg1,结果存放在result中的二元运算arg1 op arg2 结果存放在result中一元运算op arg1 一元运算op arg1,19, 三地址码的种类,序号 三地址码四元式 (1) x := y op z(op, y, z, x) (2) x := op y(op, y, , x) (3) x := y(:=, y, , x) (4) goto L(j, , , L) (5) if x goto L(jnz, x, , L) (6) if x relop y goto L(jrelop, x, y, L) (7) param x(param, , , x) (8) call n, P(call, n, , P) (9) return y(return, , , y) (10) x := yi(=, yi, , x) (11) xi := y(=, y, , xi) (12) x := emit(:=,E.code, , A.code) emit(:=,E.code, , entry(id.name) E.code:=newtemp; emit(+,E1.code,E2.code,E.code) E.code:=newtemp; emit(*,E1.code,E2.code,E.code) E.code:=E1.code E.code:=newtemp; emit(,E1.code, , E.code) E.code:=entry(id.name),25,4.2.3 图形表示, 树作为中间代码 语法树真实反映句子结构,对语法树稍加修改(加入语义信息),即可以作为中间代码的一种形式(注释语法树)。 例4.8 赋值句x:=(a+b)*(a+b)的树的中间代码表示:,T1/(1),T2/(2),T3/(3),T4/(4),26, 树的语法制导翻译,(1) A id := E (2) E E1 + E2 (3) E E1 * E2 (4) E ( E1 ) (5) E - E1 (6) E id,A.nptr:= mknode(:=,mkleaf(entry(id.name),E.nptr) E.nptr:=mknode(+,E1.nptr,E2.nptr) E.nptr:=mknode(*,E1.nptr,E2.nptr) E.nptr:=E1.nptr E.nptr:=mknode(,E1.nptr, ) E.nptr:=mkleaf(entry(id.name),属性.nptr:指向树节点的指针; 函数mknode(op,nptr1,nptr2): 生成一个根或内部节点,节点数据是op, nptr1和nptr2分别指向的左右孩子的子树。若仅有一个孩子,则nptr2为空; 函数mkleaf(node): 生成一个叶子节点。,27, 树的优化表示DAG,如果树上若干个节点有完全相同的孩子,则这些节点可以指向同一个孩子,形成一个有向无环图(Directed Acyclic Graph, DAG)。 DAG与树的唯一区别是多个父亲可以共享同一个孩子,从而达到资源(运算、代码等)共享的目的。,DAG的语法制导翻译与树的语法制导翻译相似,仅需要在mknode和mkleaf中增加相应的查询功能。 首先查看所要构造的节点是否已经存在,若存在则无需构造新的节点,直接返回指向已存在节点的指针即可。,28, 树与其他中间代码的关系,树表示的中间代码与后缀式和三地址码之间有着内在的联系。 对树进行深度优先的后序遍历,得到的线性序列就是后缀式,或者说后缀式是树的一个线性化序列。 树的每个内部节点和它的孩子,对应一个三元式或四元式。,例4.9 赋值句x:=(a+b)*(a+b)的注释语法树:,后缀式:xab+ab+*:= 三元式:,(1)(+, a, b ) (2)(+, a, b ) (3)(*,(1),(2) (4)(:=,x, (3),四元式:,(1)(+, a, b, T1) (2)(+, a, b, T2) (3)(*, T1,T2,T3) (4)(:=,x, T3,T4),因此,现代的编译器基础架构均用语法树作为中间表示。,29,4.3 符号表简介,符号表的作用:连接声明与引用的桥梁,记住每个符号的相关信息,如作用域和绑定等,帮助编译的各个阶段正确有效地工作。 符号表设计的基本要求:目标是合理存放信息和快速准确查找。 正确存储各类信息。 适应不同阶段的需求; 便于有效地进行查找、插入、删除和修改等操作; 空间可以动态扩充;,30,4.3.1 符号表条目,逻辑上讲:每个声明的名字在符号表中占据一栏,称为一个条目,用于存放名字的相关信息。 符号表中的内容:保留字、标识符、特殊符号(包括算符、分隔符等)等等。不同类别的符号存放在不同的子表中,如变量名表、过程名表、保留字表等。 存放方式:关键字属性。 关于组合关键字:,. int x; double x; struct x float y, z; ; ,为C+构造的符号表中,组合关键字至少应该包括三项:名字作用域类型。 当一个名字x在同一作用域中允许有多于一个的声明,则对x的引用时需要根据上下文确定x到底属于哪个对象。 因此程序设计语言在语法上规定了不允许这样的声明,以简化编译时的处理。,31,4.3.2构成名字的字符串的存储,定长数据变长数据 直接存放间接存放,名字(直接存储)属性 sort proc, . a int, . readarray proc, . draw_a_red_line_for_object_aboolean, .,名字(间接存储)属性 101 (或101/4) proc, . 106 (或105/1)int, . 108 (或106/9)proc, . 118 (或105/28)boolean, .,sort#a#readarray#draw_a_red_line_for_object_a# 101,sortareadarraydraw_a_red_line_for_object_a 101,间接存储的方法实际上解决了复杂信息的存储问题,将其推广到属性,则任何一个复杂的属性,均可以为其另辟空间(空间本身可以是复杂结构,如数组的内情向量等),而仅需要将指向此空间的指针放在此属性在符号表中的对应位置即可。,32,4.3.3 名字的作用域,程序设计语言的名字可以出现在不同的范围内,并且可以具有不同的意义。 两种划分范围的方式:并列的和嵌套的。 不同的语言采用不同的方式:如Pascal的过程定义可以是嵌套的,而C的过程定义是并列的,但是C允许程序块是嵌套的。,名字的作用域:名字在哪个范围内起作用。并列的两个范围内的名字作用域互不相干,但是分别在嵌套的两个范围内的名字,其作用域的问题就需要制定规则来限定,以使得任何一个名字在任何范围内涵义都是无二义的。,名字的作用域规则:规定一个名字在什么样的范围内应该表示什么意义。,33,4.3.3 名字的作用域(续1), 静态作用域原则(static-scope rule): 编译时就可以确定名字的作用域,也可以说,仅从静态读程序就可确定名字的作用域。 最近嵌套原则(most closely nested): 以程序块为例,也适用于过程。 程序块B中声明的作用域包括B; 如果名字x不在B中声明,那么B中x的出现是在外围程序块B的x声明的作用域中,使得 (a) B有x的声明,并且 (b) B比其它任何含x声明的程序块更接近被嵌套的B。,通俗地讲,名字的声明在离其最近的内层起作用,即在名字引用处从内向外看, 它处在所遇到的第一个该名字声明的作用域。 例子:找人 张三;软件学院的张三;计算机学院的张三;西电软件学院的张三,34,4.3.3 名字的作用域(续2),例4.10 说明符合作用域规则的C+程序。 void main() int a=0, b=0;/* B0层 */ int b=1;/* B1层,被B0嵌套 */ int a=2, c=4, d=5;/* B2层,被B1嵌套 */ printf(%d %dn, a, b);/* 结果为:2,1 */ int b=3; /* B3层,与B2并列 */ printf(%d %dn, a, b); /* 结果为:0,3 */ printf(%d %dn, a, b);/* 结果为:0,1 */ printf(%d %dn, a, b); /* 结果为:0,0 */ ,声明与作用域:,声 明作用域 int a=0 B0-B2 int b=0 B0-B1 int b=1B1-B3 int a=2 B2 int b=3B3,35,4.3.4 线性表,线性表应是一个栈,以正确反映名字的作用域,即符号的加入和删除,均在线性表的一端进行。,线性表上的操作:关键字:名字作用域; 查找:从表头(栈顶)开始,遇到的第一个名字; 插入:先查找,再插入在表头;,1 void main() 2 int a=0, b=0; / B0 3 int b=1; / B1 4 int a=2, c=4, d=5; / B2 7 int b=3; / B3 11 ,36,4.3.4 线性表(续1),1 void main() 2 int a=0, b=0;/ B0 3 int b=1;/ B1 4 int a=2, c=4, d=5; / B2 7 int b=3; / B3 11 ,线性表上操作的效率(n个条目): 一个名字的查找:成功查找(平均):(n+1)/2;不成功查找:n+1 建立n个条目的符号表(最坏): = (n+1)(n+2)/2,删除: (a) 暂时:将在同一作用域的名字同时摘走,适当保存; (b) 永久:将在同一作用域的名字同时摘走,不再保存。 修改:与查找类似,修改第一个遇到的名字的信息。 修改可以用插入删除代替。,37,4.3.5 散列表, 散列表的构成 将线性表分成m个小表。构造hash函数,使名字均匀地散布在m个子表中。如果散列均匀,则时间复杂度会降到原线性表的1/m。,每个名字挂在两个链上(便于删除操作): 哈希链(hash link): 链接所有具有相同hash值的元素,表头在表头数组中; 作用域链(scope link):链接所有在同一作用域中的元素,表头在作用域链中。,其中: S1、S2、S4在同一作用域 S3在另一作用域,38, 散列表上的操作 4.3.5 散列表(续1),1查找:首先计算散列函数,然后从散列函数所指示的入口进入某个线性表,在线性表中沿hash link,象查找单链表中的名字一样进行查找。 2插入:首先查找,以确定要插入的名字是否已在表中,若不在,则要分别沿hash link和scope link插入到两个链中,方法均是插在表头,即两个表均可看作是栈。 3删除:把以作用域链连在一起的所有元素从当前符号表中删除,保留作用域链所链的子表,为后继工作使用(如果是临时删除,则下次使用时直接沿作用域链加入到散列链中即可)。,39,4.3.5 散列表(续2),设:hash(s)=ord(s)-ord(a),1 void main() 2 int a=0, b=0; / B0 3 int b=1; / B1 4 int a=2, c=4, d=5; / B2 7 int b=3; / B3 11 ,分析在B2中:,退出B2进入B3:,40, 散列函数的计算 hash: string integer,减少冲突,分布均匀 充分考虑程序设计语言的特点 若有变量:V001,V002,V300,且首字母的值作为hash值。 会发生什么?,一种可行的hash函数计算方法: 从串s=c1c2ck的字符ci确定正整数h: 令: h0=0, 计算:hi=hi-1+ci, 1ik, 得到:h=hk =1或是素数,如=65599。,思考题:根据上述方法,设计一个hash函数并测试之。根据测试结果讨论各参数值对函数结果的影响。, 取一素数m, 令 h=h mod m。,41, 散列函数的计算(续1),思考题(P108):对于下列函数: #include const int PRIME=211; const int EOS=0; int hashpjw(char *s) char *p; unsigned h=0, g; for (p=s; *p!=EOS; p+) h=(h24); h=hg; return h%PRIME; (1) 为每行语句写注释; (2) 写出此函数的计算公式; (3) 若参数是abcd,试给出返回值。,结 束,
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 图纸专区 > 课件教案


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!