《中间代码翻译》PPT课件.ppt
《《中间代码翻译》PPT课件.ppt》由会员分享,可在线阅读,更多相关《《中间代码翻译》PPT课件.ppt(70页珍藏版)》请在三一办公上搜索。
1、第五讲 语义分析和中间代码产生,语义分析概述中间语言几种常用语句的翻译符号表,CompilerPrinciples,2,静态语义检查和中间代码产生在编译程序中的位置如图所示:,CompilerPrinciples,3,虽然源程序可以直接翻译为目标语言代码,但是通常编译程序还是采用了独立于机器的、复杂性介于源语言与机器语言之间的中间语言。这样做的好处是:(1)便于进行与机器无关的代码优化;(2)使编译程序改变目标机更容易;(3)使编译程序的结构在逻辑上更为简单明确,以中间语言为界面,编译前端和后端的接口更清晰。,CompilerPrinciples,4,1.语义分析概述,一、语义分析的任务审查每
2、一个语法结构的静态语义,即验证语法正确的结构是否有意义。如:赋值语句:x:=x+y,左边变量类型与右边变量类型是否一致。在语义正确的基础上生成一种中间代码或目标代码。,CompilerPrinciples,5,二、语义分析的范围1.确定类型:确定标识符所关联的数据类型。2.类型检查:按语言的类型规则,检查运算的合法性与运算分量类型的一致性,必要时作类型转换。3.识别含义:根据语言的语义定义(形式或非形式),识别程序中各构造成分组合到一起的含义,并作相应的语义处理(生成中间代码或目标代码)。,CompilerPrinciples,6,4.控制流检查:控制流语句必须转移到合法的地方。如C中,bre
3、ak语句规定跳出最内层的循环或switch语句。5.一致性检查:在很多场合要求对象只能被说明一次。如:pascal语言规定同一个标识符在一个分程序中只能被说明一次等。6.相关名字检查:如:Ada,循环或块可以有一个名字,它出现在这些结构的开头或结尾。编译程序必须检查这两个地方用的名字是否相同。其它:如名字的作用域分析等也是语义分析的工作。,CompilerPrinciples,7,三、语义描述工具和语义分析方法语义描述工具 目前流行:用属性文法作为描述语义的工具。语义分析方法根据描述属性文法的语义规则的方式不同分为:语法制导定义翻译方案,CompilerPrinciples,8,属性文法形式定
4、义:一个属性文法是一个三元组A=(G,V,F)其中:G为一个上下文无关文法;V 表示属性的有穷集合;F表示属性的断言或谓词的有穷集。语义规则在对文法符号属性处理过程中,为文法的每一产生式定义一组属性的计算规则,称为语义规则。,CompilerPrinciples,9,3.语法制导翻译 所谓语法制导翻译是指:对文法中的每个产生式都附加上一个语义动作或语义子程序。伴随着语法分析,每当使用一条产生式进行推导或归约时,就执行相应产生式的语义动作(包括:查填表格,改变变量的求值,诊察与报告错误,生成中间代码等),从而完成预定的翻译工作。,自底向上的语法制导翻译自顶向下的语法制导翻译,CompilerPr
5、inciples,10,2.几种常用的中间语言形式,一、逆波兰表示法 波兰表示是波兰逻辑学家J卢卡西维奇于1929年提出的一种既不须考虑优先关系、又不用括号的一种表示表达式的方法(前缀式),在计算机出现以后,这种表示方法显出了巨大的优越性。后人为了纪念他,就用其祖国名字来命名这种表示方法。现在我们要介绍的刚好是另一种波兰表示形式,称为后缀式,即运算符在后。例:a+b ab+a*(b+c)abc+*-a+b*c abc*+,CompilerPrinciples,11,二、图表示法 这里要介绍的图表示包括DAG与我们前面介绍过的抽象语法树。1.无循环有向图(DAG)DAG与抽象语法树基本上一样,对
6、表达式中的每个子表达式,DAG中都有一个结点。一个内部结点表示一个操作符,它的孩子表示操作数。两者所不同的是,在一个DAG中代表公共子表达式的结点具有多个父结点,而在一棵抽象语法树中公共子表达式被表示为重复的子树。如下例:,CompilerPrinciples,12,assign,a,+,*,*,b,uminus,b,uminus,c,c,a:=b*-c+b*-c的图表示法,抽象语法树,DAG,CompilerPrinciples,13,2.再来看A*B+C*D的树、后缀式,后缀式:AB*CD*+不难看出,后缀式实际上是抽象语法树的线性表示形式(后序表示);,CompilerPrinciple
7、s,14,3.树表示的翻译法:例:产生式 语义动作(1)EE1 op E2 E.val:=NODE(op,E1.val,E2.val)(2)E(E1)E.val:=E1.val(3)E-E1 E.val:=UNARY(E1.val)(4)Ei E.val:=LEAF(i),建立一棵新树,以OP为根,以E1.val,E2.val为左右枝。返回指向树根的指针。,与NODE相似,只不过是单枝。,建立以i.LEXCAL为标志的叶结,回送的是结点i的地址。,CompilerPrinciples,15,三、三元式 1.三元式由三个部分组成:算符:OP 第一运算分量:ARG1 第二运算分量:ARG2 2.各
8、种语句都可表示成一组三元式 例1:OP ARG1 ARG2 x+y*z(1)*y z(2)+x(1)这儿实际实现时x,y,z也都是指示器,指向这些变量在符号表中的位置。算符OP一般用整数编码,而且可以加进一些诸如类型之类的信息。,指示器-指向(1)在表格中的位置,CompilerPrinciples,16,对于一目运算符,我们可以规定只用ARG1,而多目运算符可以用若干条相继的三元式来表示。OP ARG1 ARG2 例2:-x+y*z(1)x-(2)*y z(3)+(1)(2)例3:赋值语句的三元式表示 OP ARG1 ARG2 A:=x+y*z(1)*y z(2)+x(1)(3):=A(2)
9、,CompilerPrinciples,17,树、后缀式与三元式,后缀式:AB*CD*+后缀式实际上是抽象语法树的线性表示形式(后序表示);树是三元式的翻版,每个三元式对应一棵(二叉)子树,最后的三元式对应树根。,CompilerPrinciples,18,3.语法制导产生三元式(1)EE1 op E2 我们用E.val表示一个指示器,它或指向有关符号表的某项,或指向三元式表的某项,于是其语义子程序为:E.val:=TRIP(OP,E1.val,E2.val)这儿TRIP(OP,ARG1,ARG2)是一个语义过程,它产生(OP,ARG1,ARG2)并放入三元式表中,返回三元式在表中的位置。,C
10、ompilerPrinciples,19,(2)Ei E.val:=Entry(i)这儿ENTRY是一个语义过程,它查找i在符号表中的位置。若用LOOKUP(NAME)函数表示对NAME查找符号表,找到则返回表项位置,找不到则返回NULL。于是可如下实现:词法分析器扫描到标识符i时送回(种别码,i值),语法分析器把i放入语义变量i.LEXCAL中,这时就可以调用ENTRY过程:,CompilerPrinciples,20,FUNCTION ENTRY(NAME)BEGIN ENTRY:=LOOKUP(NAME);IF ENTRY=NULL THEN ERROR;END 由于三元式的计算过程跟先
11、后顺序密切相关,这就给优化带来麻烦,所以一般不直接使用三元式。,CompilerPrinciples,21,4.间接三元式 在三元式的基础上附加一张指示器表间接码表,按运算的先后顺序列出有关三元式在三元式表中的位置。这种表示方法称为间接三元式。例:语句X:=(A+B)*C;Y:=D(A+B)的间接三元式,CompilerPrinciples,22,有了间接码表后,一方面相同的三元式就无须重复填进表中,节约了空间;另一方面,当在代码优化过程中需要调整运算顺序时,只需重新安排间接码表,无须改动三元式。当然这样一来,语义规则中应添加产生间接码表的动作,并且向三元式表中每填入一个三元式前,必须先查看一
12、下此式是否已经在表中出现过。,CompilerPrinciples,23,四、四元式 一个四元式是一个带有四个域的记录结构:op,arg1,arg2及result。它实际上就是一条三地址的指令。例:A+B*(C-D)-E/FG的四元式为:OP ARG1 ARG2 RESULT-C D T1*B T1 T2+A T2 T3 F G T4/E T4 T5-T3 T5 T6,CompilerPrinciples,24,规定凡只有一个运算量时只用ARG1。以上的Ti都是临时变量,其处理方法可以像用户自定义变量一样进符号表,也可以直接用某种整数码表示。,赋值语句A:=-B*(C+D),CompilerP
13、rinciples,25,例:将语句:if AVBD then i:=i+1 else i:=i-1 写成四元式。(1)(,B,D,T1)(2)(V,A,T1,T2)(3)(BMZ,T2,_,(7)(4)(+,i,1,T3)(5)(:=,T3,i)(6)(JMP,_,_,(9)(7)(-,I,1,T4)(8)(:=,T4,_,i)(9),三地址代码:(1)T1:=BD(2)T2:=AV T1(3)if T2 goto(7)(4)T3:=i-1(5)i:=T3(6)goto(9)(7)T4:=i+1(8)i:=T4(9),有时将四元式表示成更直观的形式三地址代码三地址代码形式:x:=a op b
14、(赋值形式)与赋值语句的区别:其右边最多只能有一个运算符。,CompilerPrinciples,26,参考书中推荐的三地址指令形式:赋值语句x:=y op z,x:=op y,x:=y无条件转移goto L条件转移if x relop y goto L过程调用param x 和call p,n过程返回 return y索引赋值x:=yi和 xi:=y地址和指针赋值x:=&y,x:=y和x:=y,CompilerPrinciples,27,3.某些语句的四元式及翻译,一、说明语句的翻译 程序语言中的说明语句都是给编译程序提供信息的,诸如类型、维数、每维的界种类等,因此一般不生成目标,只是在编译
15、时把有关信息填入相应表格即可。为局部名字建立符号表条目为它分配存储单元符号表中包含名字的类型和分配给它的存储单元的相对地址等信息,CompilerPrinciples,28,1.简单说明句:用一个基本字来定义一串名字,其语法描述一般为:Dinteger namelistreal namelist namelistnamelist,ii 直接用这种文法来制导翻译有点麻烦,就是只能在把所有名字规约成namelist之后才能把性质登记到符号表中。这就意味着在扫描名字时,应把名字用一个队列(或栈)保存起来,然后再处理。实际上,我们可以对文法稍做改动,就可以免去建立队列或栈的过程。修改文法如下:DD,i
16、integer ireal i,CompilerPrinciples,29,例:integer i1,i2,i3,词法分析后:,int i1,i2,i3,(07,-),(06,i1),(12,-),语法分析:,s5,i2,LR分析器,语义动作:FILL(ENTRY(i2),D1ATT);DATT:=D1ATT DD1,i2,语义动作:FILL(ENTRY(i1),int);DATT:=int Dinteger i1,此处的ENTRY过程参见前面,CompilerPrinciples,30,2.数组说明:遇到数组说明,应把有关信息收集到一个“内情向量”表格之中,每个数组对应一个“内情向量”。例如
17、,arrayl1:u1,l2:u2,ln:un的内情向量为:di=ui-li+1所求地址:D=CONSPART+VARPART CONSPART=a-C C=(l1d2+l2)d3+l3)d4+)+ln-1)dn+ln,维数,类型,数组首址,CompilerPrinciples,31,显然,内情向量的大小完全由维数决定。一般来说,像FORTRAN,ALGOL,PASCAL等语言的程序,其内情向量在编译时完全可以确定了。关于内情向量的填写,编译时完全可以做了,而且是只在编译时使用,故可以把它安排成符号表的一部分,无须带到目标程序运行阶段。但有时为了处理方便,也一起带到目标程序中。对动态数组,则编
18、译时开辟出信息向量表区,同时应有填写信息向量的目标指令,我们可以用如下一个子程序来处理。该程序的入口参数为维数n,界限序列l1,u1,l2,u2,ln,un,以及类型type和数组首址。,CompilerPrinciples,32,BEGIN i:=1;N:=1;C:=0;WHILE i=n DO BEGIN di:=ui-li+1;N:=N*di;C:=C*di+li;把li,ui,di填入内情向量中;i:=i+1 END;申请N个单元的数组空间,令其首址为a;把n,C,type和a填入内情向量中 END;其他记录说明、过程说明的翻译也大同小异,此处不再赘述。,CompilerPrincip
19、les,33,二、赋值语句的翻译 1.简单算术表达式的赋值语句:所谓简单指不考虑数组元素、记录、函数的引用等情况。对这种算术表达式和赋值语句的四元式我们已经介绍过,现在就来看看如何翻译。我们先来讨论所有分量都是相同类型的情况,如都是整型。于是,我们可用如下的二义文法来进行描述:Sid:=E EE1+E2E1*E2(E1)-E1id,CompilerPrinciples,34,语义动作:Sid:=E p:=lookup(id.name);if(p!=nil)then emit(p:=E.place)else error EE1 op E2 E.place:=newtemp;emit(E.plac
20、e:=E1.place op E2.place)E-E1 E.place:=newtemp;emit(E.place:=uminus E1.place)E(E1)E.place:=E1.place Eid p:=lookup(id.name);if(p!=nil)then E.place:=p else error,CompilerPrinciples,35,2.类型转换 实际上我们可以把类型信息反映到运算符中,例如用+i,*i表示定点+、*,用+r,*r表示浮点+、*。有的程序设计语言允许混合运算,有的不允许。如果不允许,则发现有类型不相同的运算分量就应该报错。如果允许,就要进行类型转换。按
21、照惯例,整、实运算要全部转成实型。处理的方法就是:给每个非终结符添加一个类型信息,如我们用E.MODE表示E的类型,其值为r或者i。如此一来,关于EE1 op E2 的语义子程序也应作相应改动,使其在必要时能产生对运算分量进行类型转换的四元式。,CompilerPrinciples,36,例:X:=Y+I*J 其中X,Y为实型,I,J为整型(*i,I,J,T1)(itr,T1,-,T2)加入一个类型转换四元式(+r,Y,T2,T3)(:=,T3,-,X)语义动作:对Ei来说,E.place:=ENTRY(i)现在应加上E.MODE:=MODE(i);而对EE1 op E2,其语义子程序可以用如
22、下流程图来表示:,CompilerPrinciples,37,T1:=newtemp,start,E1.MODE=int&E2.MODE=int,E1.MODE=r&E2.MODE=r,E1.MODE=int,E.MODE:=rT2:=newtempemit(itr,E2.place,-,T2)emit(opr,E1.place,T2,T1),E.MODE:=rT2:=newtempemit(itr,E1.place,-,T2)emit(opr,T2,E2.place,T1),E.MODE:=intemit(opi,E1.place,E2.place,T1),E.MODE:=remit(opr
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 中间代码翻译 中间 代码 翻译 PPT 课件
链接地址:https://www.31ppt.com/p-5456895.html