




已阅读5页,还剩80页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第七章 语法制导翻译技术及中间代码的生成,主 要 内 容 1.语义翻译的方法:采用语法制导翻译技术的方法。 依据的文法(描述文法的语义):属性文法。(一般掌握) 语法制导翻译过程:根据已有的属性文法,生成句子的 中间代码过程。(重点掌握) 2.语义翻译结果的表示:中间代码 。(重点掌握) 常见: 逆波兰表示 四元式表示和三地址代码 三元式和树形表示,1. 语义分析概述,一、语义分析的任务 任务有: 审查每一个语法结构的静态语义,即验证语法正确的结构是否有意义。 如:赋值语句:x:=x+y,左边变量类型与右边变量类型是否一致。 在语义正确的基础上生成一种中间代码或目标代码。,二、语义分析的范围 1o.确定类型:确定标识符所关联的数据类型。 2o.类型检查:按语言的类型规则,检查运算的合法性与运算分量类型的一致性,必要时作类型转换。 3o.识别含义:根据语言的语义定义(形式或非形式),识别程序中各构造成分组合到一起的含义。,并作相应的语义处理(生成中间代码或目标代码) 4o.控制流检查:控制流语句必须转移到合法的地方。 如:C中,break语句规定跳出最内层的循环或switch语句. 5o.一致性检查:在很多场合要求对象只能被说明一次,如:pascal语言规定同一个标识符在一个分程序中只能被说明一次等。,6o.相关名字检查:如:Ada,循环或块可以有一个名字,它出现在这些结构的开头或结尾。编译程序必须检查这两个地方用的名字是否相同。 其它:如名字的作用域分析等也是语义分析的工作。 三、语义描述工具和语义分析方法 语义描述工具 目前流行:用属性文法作为描述语义的工具。 语义分析方法 根据描述属性文法的语义规则的方式不同,语义分析方法分为: 语法制导定义方法 翻译方案,2. 属 性 文 法,一、属性 属性常用来描述事物或人的特征。如:人的姓名,性别等,商品的颜色、重量、单位等。 属性:在编译中,对文法的每一个符号,引进一些属性,用这些属性描述文法符号相关的信息,如:类型、值或存储位置等。 如:A:=X ,在语法推导或归约时,有时结合X的类型,位置,值,考虑语法分析的正确性,即语法分析中有语义检查。 如:X的属性:Xtype,Xplace,Xval分别表示X的类型,位置,值等语义。,属性值:可以在语法分析过程中计算和传递。 属性的加工过程就是语义的处理过程。 二、属性文法 语义规则 在对文法符号属性处理过程中,必须遵守一定义的规则语义规则。 为文法的每一产生式定义一组属性的计算规则,称为语义规则。 属性文法 形式定义:一个属性文法是一个三元组A,A=(G,V,F) 其中:G为一个上下文无关文法; V 表示属性的有穷集合; F表示属性的断言或谓词的有穷集。,在属性文法中: 每个属性与文法中某个符号相关联,用“符号属性”表示。如:Xtype,Xint,Xbool等。 每个断言与文法的某产生式相关联。断言就是产生式上定义的一组语义规则。 例:一个简单表达式方法: E:=T1+T2|T1orT2 T:=num|true|false,根据程序语言中有关类型的检验原则,可以得到关于类型检验的属性文法: E:=T1+T2 T1.type=int and T1.type=int E:=T1orT2 T1.type=bool and T1.type=bool T:=num T.type=int T:=true T.type=bool T:=false T.type=bool 属性分类:综合属性 继承属性 综合属性:从语法分析角度看,如果一个结点的某一属性,其值由子结点的属性的值来计算,称该属性为综合属性。,例:已知上例属性文法的输入串3+4语法树。 其中:E中语义规则中的T1.type和T2.type中的type属性的值分别由子结点T1.type=int和T2.type=int中的int值来计算,使得E中的语义规则(断言)为真。因此:type是综合属性。 综合属性用于“自下向上”传递信息。,继承属性:在语法分析树中,结点的某个属性值由该结点的兄弟结点和(或)父结点的属性值来计算,此结点的属性称为继承属性。 继承属性用于“自上而下”传递信息。 注意: 终结符号只有综合属性,他由词法分析器提供。 非终结符号既有综合属性,也可有继承属性。文法识别符号(开始符号)的所有继承属性作为属性计算前的初始值。 根据处理不同的要求,属性和断言可以多种形式出现,如:语义规则或者程序段等。,例:简单表达式求值的属性文法。 产生式: L:=E print(E.val) E:=E1+T E.val:=E1.val+T.val E:=T E.val:=T.val T:=T1*F E.val:=T1.val*F.val T:=F T.val:=F.val F:=(E) F.val:=E.val F:=digit F.val:= digit.lexval,例:描述说明语句中简单变量类型信息的属性文法 产生式 语义规则 D:=TL L.in:=T.type T:=int T.type :=integer T:=real T.type :=real L:=L1,id L1.in:=L.in addtype(id.entry,L.in) L:=id addtype(id.entry,L.in),文法定义了一种说明语句,该说明语句的形式是由关键字int或real开头,后跟一个标识符表,每一个标识符间用逗号隔开: real id1,id2,idn或 int id1,id2,idn 属性文法中,非终结符T有综合属性type,其值由关键字int和real决定。 语义规则L.in:=T.type将L的属性值置为该说明语句指定的类型。 L.in将被沿着语法树传递到下边的结点使用,与L产生式相联的规则里使用了它。 如:句子int id1,id2语法树: 图2,一、基本思想 对文法中的每个产生式都附加上一个语义动作或语义子程序,伴随着语法分析,每当使用一条产生式进行推导或归约时,就执行相应产生式的语义动作(包括:查填表格,改变变量的求值,打印信息和生成中间代码等),从而完成预定的翻译工作。即在语法翻译过程中伴随部分语义的检查工作。,3. 语法制导翻译概述,语法制导翻译方法: 自底向上的语法制导翻译方法 自顶向下的语法制导翻译方法 二、语法制导翻译的步骤 1、为所给文法每个产生式设计相应的语义规则。 例:为一个简单表达式计值的文法: E= E+E|E*E|(E)|digit 设计计值的语义规则如下: 1. E=E(1)+E(2) Eval:=E(1)val+E(2)val 2. E=E(1)*E(2) Eval:=E(1)val*E(2)val 3. E=(E(1) Eval:=E(1)val 4. E=digit Eval:=lexdigit 为文法产生式写语义规则或语义子程序是本章的难点.,2.采用LR分析方法,则构造LR分析表,3. 将原LR语法分析栈扩充,增加语义值栈。,4. 根据语义分析栈的工作过程设计总控程序,使语法分析与语义分析工作同时完成。 例:计算表达式7+8*5的语法树,以及用LR语法制导翻译法得到该表达式的计值过程:,注:自底向上语法制导翻译的特点: 当栈顶形成句柄执行归约时,调用相应的语义动作。 语法分析与语义分析同步操作。,*,说明:若把计值的动作改为产生某种中间代码的子程序,那么,就能在伴随着语法分析的制导下,随着分析的进展逐步生成中间代码。 问题:1.什么是中间代码?它有哪几种形式表示源程序语言的句子? 4.中间语言 2.在语义规则中,怎么样定义生成中间代码(主要是四元式或三地址式)的一些语义规则? 5. 表达式及语句的语义翻译 3.根据具有生成中间代码的属性文法,生成中间代码的过程是怎样的?,一、中间语言概述 1 中间语言 中间语言:它介于源程序到目标语言程序中间程序的语言 中间语言程序:用中间语言表示的程序。 作用:用于编译程序,将源程序翻译成等价的中间语言程序,再将中间语言程序转化成目标程序(即将语义分析和目标代码生成分开处理) 源程序 中间语言程序 目标程序 中间语言是表示语法制导翻译的结果。,等价变换,转化,4. 中 间 语 言,好处: 中间语言与机器无关,使采用中间语言进行翻译的编译程序系统易于移植。 易于优化翻译后的代码。 使编译程序的结构在逻辑上更简单明确。 2 中间语言的表示 常见:逆波兰表示 四元式表示和三地址代码 三元式和树形表示 二、逆波兰表示,由波兰逻辑学家J.Lukasiewicz(卢卡西维兹)首先提出用来表示表达式的方法,后来推广到表示程序设计语言中的其它语法成分。 表达式的逆波兰表示 表达式的表示: 中缀表示:运算符居中,运算对象在左右两边:a+b 波兰表示: 前缀表示:运算符在前,运算对象在后:+ab 后缀表示:运算对象在前,运算符在后:ab+ (逆波兰表示),例:逆波兰表示的例子,(1)表达式逆波兰表示的定义: 设E是一般表达式,则: 一般表达式 逆波兰表达式 若E为变量或常量 E (E) E的逆波兰式 E(1)opE(2)(二目运算) E(1)的逆波兰式E(2)的逆波兰式op opE(单目运算) E的逆波兰式op,在编译过程中,生成逆波兰表示的语义规则描述: 产生式 语义规则 E:=E(1)opE(2) E.code=E(1).code|E(2).code|op E:=(E(1) ) E.code=E(1).code E:=i E.code=i 其中:E.code表示E的逆波兰式;|表示逆波兰式的连接。 (2)逆波兰表示的特点 a.标识符(运算对象)出现的顺序(从左到右)和原有顺序相同。 b. 运算符是按实际计算顺序(从左到右)出现的。 c. 运算符紧跟在运算对象的后面出现,并且没有括号。,(3) 好处:易于对表达式的计算处理 对于中缀表达式的计算,系统需要用两个工作栈分别处理运算对象和运算符。 对于逆波兰表示的表达式计算处理只用一个工作栈。 例:逆波兰式ab+c*的计算处理过程,遇运算对象a,b入栈,扫描ab+c*,栈,遇运算符+,取出a,b,运算结果T入栈,c*,遇运算对象c入栈,*,遇运算法*取出c,T作运算,设结果T1,2. 形成逆波兰表示 怎样将一般表达式转换成逆波兰表示? 基本思想:从左到右扫描表达式,每遇到: 1o 表达式中的运算对象则往左去。 2o 表达式中的运算符,则与运算符栈顶元素比较优先数:,逆波兰表示,表达式,运算对象,运算符,进栈,出栈,运算符栈,如果运算符栈顶元素的优先数大于或等于表达式中当前的运算符优先数,则栈顶元素退栈向左去。 然后当然运算符继续与栈顶的新元素比较优先数。直到栈顶元素的优先数小于表达式中当前运算符为止。 此时,才将表达式中当前运算符进栈。,例:画出形成表达式a*(b+c/d)的逆波兰表示过程,a,*(b+c/d)#,#,a,(b+c/d)#,* #,a,b+c/d)#,( * #,ab,+c/d)#,( * #,ab,c/d)#,+ ( * #,abc,/d)#,+ ( * #,步骤,步骤,步骤,步骤,步骤,步骤,abc,d)#,abcd,)#,/ + ( * #,/ + ( * #,/,+ ( * #,Abcd/,)#,+,( * #,Abcd/+,)#,*,#,Abcd/+*,#,步骤,步骤,步骤,步骤,步骤,形成逆波兰表示的过程,实质上是表达式的翻译过程。(算法不难写出) 例:a/b/c+d = ab/c/d+ (a+b)*(c-d/e) = ab+cde/-* 3. 扩充的逆波兰表示 逆波兰不仅仅用来表示计算表达式,而且可以推广到其它语法成分的表示。 赋值语句:a := e (其中e是表达式) 逆波兰表示:ae:=(其中e应该为逆波兰表示),例:a:=3*(b+c)的逆波兰表示:a3bc+*:= 条件语句:if u then S1 else S2 逆波兰表示:u l1 jumpf S1 l2 jump S2 其中:u为布尔表达式的逆波兰表示 S1,S2均为相应语句的逆波兰表示。 jumpf 表示一个双目运算符:当u为假(0)时,它引向标号 l1的分支, l1表示语句S2的开始位置。 jump表示单目运算符:它无条件的引向标号为l2的分支, l2表示语句S2后的符号位置。 逆波兰式表示的语义:当u=0(假)转去执行S2,否则转向执行S1,然后跳到S2之后的语句。,有下列源程序段: K := 0; if ij then K := K+6*ai-j else Begin i:=i+1; j:=j-1; End;,逆波兰表示: K0:= ijl1 jumpf KK6ij-aSubs*+:=l2 jump l1: ii1+:=jj1-:= l2: 含义:当ij为假便转向l1处执行S2;否则执行S1后无条件转到l2处即语句S2的后继部分。,三、三元式和树形表示 1。三元式 一个三元式由三个主要部分和一个序号组成: (i)(op,arg1,arg2) 其中:op是运算符,arg1和arg2是运算对象。当op为一目运算符时,只有一个运算对象。 (i)表示三元式的序号,三元式的运算结果由每个三元式前序号(i)指示。序号(i)指向三元式所处的表格位置,因此引用一个三元式的计算结果是通过引用该三元式的序号实现的。三元式出现的先后顺序与表达式的计值顺序一致。,例:a:=-b*c+b*d三元式: (1)(,b,_) (2)(*,(1),c) (3)(*,b,d) (4)(+,(2),(3) (5)(:=,(4),a) 2. 间接三元式 由于三元式的先后顺序决定了值的顺序,因此在产生三元式形式的中间代码后,对其进行代码的优化时难免涉及到改变三元式的顺序(即三元式表示的中间代码不利用代码优化),这就要修改三元式表。 为了最少改动三元式表,可以另设一张间接码表来表示有关三元式在三元式表的计值顺序,用这种办法处理的中间代码称为间接三元式。 例:表达式 x=A+B*C y=D-B*C,其间接三元式表示如下:,由于间接码表的作用,编译程序每产生一个三元式时,先查看三元式表中是否存在当前三元式,若存在就不需要重复填写三元式表,如上例中的三元式(1) (*,B,C)在间接码表中出现了两次,但三元式表中实际只有一个三元式。 注: 三元式表示的中间代码不利于中间代码的优化。 间接三元式表示的中间代码有利于中间代码的优化。,3.树形表示 树形结构是三元式的另一种表示形式 例如:上例a:=-b*c+b*d的树形表示(由三元式的下至上画出),树形表示法很容易表示一个表达式或语句。 一个表达式中简单变量或常数的树形表示就是它们的本身。 如果表达式e1和e2的树分别为T1和T2,则: e1和e2, e1* e2, -e1的树分别:,注:二目运算对应二叉树 三目运算对应三叉树:如条件语句if u then S1 else S2 可看作三目运算。其三目运算符定义为:if then else 则:树表示,注:多叉树不便于存储,可以化为二叉树:,四、四元式和三地址代码 四元式是一种比较普遍采用的中间代码形式。 四元式由四个部分组成: (i)(op,arg1,arg2,result) 其中:op为运算符;arg1,arg2为运算对象。result存放结果的变量。四元式之间的联系通过变量来联系(而不用三元式中的序号联系) 例:a:=b*c+b*d四元式表示: (1) (*,b,c,t1) (2) (*,b,d,t2) (3) (+, t1, t2, t3) (4) (:=, t3,_,a),注:四元式和三元式的主要不同在于: 四元式之间的联系通过中间引用的变量名实现,而三元式之间的联系通过三元式序号实现。这说明要更改一张三元式表比较困难,它需要改变一序列的三元式的序号。四元式表的修改比较容易,调整四元式之间位置,不改变其中的参数。因此:四元式和三地址代码表示的中间代码便于中间代码的优化。而三元式和树不便于优化。,有时将四元式表示成更直观的形式三地址代码 三地址代码形式: x:=a op b (赋值形式) 与赋值语句的区别:其右边最多只能有一个运算符。 例:上例的四元式写成三地址代码: (1) t1:=b*c (2) t2:=b*d (3) t3:= t1+ t2 (4) a:= t3,三地址代码表示的好处:表示中间代码更直观,有利于中间代码的优化和目标代码的生成。 四元式的生成算法与逆波兰式生成算法基本相同。 扩充四元式可表示程序语言的其它语法成分。 例:将表达式: A+B*(C-D)-E/F G写成逆波兰表示、三元式和四元式 逆波兰表示:ABCD-*+EFG /- 三元式: (1) (-,C,D) (2) (*,B,(1) (3) (+,A,(2) (4) ( ,F ,G) (5) (/,E,(4) (6) (-,(3),(5),四元式:(1)(-,C,D,T1) (2)(*,B, T1, T2) (3)(+,A, T2, T3) (4)( ,F,G, T4) (5)(/,E, T4, T5) (6)(-, T3, T5, T6),三地址代码: T1:=C-D T2:=B*T1 T3:=A+ T2 T4:=F G T5:=E/ T4 T6:= T3- T5,例:将语句:if AVBD then i:=i+1 else i:=i-1 写成四元式。 (1) (,B,D, T1) (2) (V,A, T1, T2) (3) (BMZ, T2, ,(7) (T2为假) (4) (+,i,1, T3) (5) (:=, T3, ,i) (6) (JMP,(9) (7) (-,I,1, T4) (8) (:=, T4, , i) (9),三地址代码: (1) T1:=BD (2) T2:=A V T1 (3) if T2 goto (7) ( T2为 真转) (4) T3:=i-1 (5) i:= T3 (6) goto (9) (7) T4:=i+1 (8) i:= T4 (9),注: 四元式表示中间代码最大的优点是便于中间代码的优化。缺点:引用临时变量较多,占用的空间比三元式要多。 三元式表示中间代码的优点:无须引用较多的临时变量、占用空间少。但不便于代码优化。 四元式及三地址代码在后面的语义规则中都要使用。,5. 表达式及语句的语义翻译,如何为文法写出产生表达式和语句的中间代码(如:四元式或三地址式)的语义规则。以便在检查它们语法的同时,将它们生成用四元式或三地址式表示的中间代码。下面主要介绍将表达式、赋值语句、条件语句生成四元式或三地址式的语义规则设计。 一、简单算术表达式和赋值语句的翻译 简单算术表达式仅含有简单变量、常数和算术运算符的式子,不含有数组元素、结构等复合型数据类型。简单算术表达式的计值顺序与四元式出现的顺序相同,因此很容易将其翻译成四元式形式。 例:已知文法G: A = i:=E E= E+E|E*E|-E|(E)|i,对此写出语义子程序,以便在进行归约的同时执行语义子程序。这些语义子程序中所设置的语义变量、语义过程及函数是: (1)对非终结符E定义语义变量E place。 E place表示存放E值的变量名在符号表中的入口地址或者临时变量名的整数码。 (2)定义语义函数newtemp(),其功能是产生一个新的临时变量名字,如T1, T2等。具体实现时,每产生一个Ti,就及时送符号表;也可以不进符号表,直接将单词值用整数码表示。 (3)定义过程emit(T=arg1 op arg2),emit的功能时产生一个四元式,并及时填进四元式表中。 (4)定义过程lookup(i,name),其功能时审查i name是否出现在符号表中,存在则返回其指针,否则返回null 利用以上定义的语义变量、过程、函数等,给文法G中每个产生式写出语义子程序:,(1) A = i:=E p=lookup(i name); if(p=NULL) error(); else emit(p=E place) (2)E = E(1) +E(2) E place=newtemp(); emit(E place=E(1) place+ E(2) place) (3) E = E(1)*E(2) E place=newtemp(); emit(E place=E(1) place* E(2) place (4) E = -E(1) E place=newtemp(); emit(E place = uminus E(1) place (5) E = (E(1) E place= E(1) place; (6) E = i p=lookup(i name); if(p!=NULL) E place=p; else error();,若考虑表达式中变量及常数的类型之间的运算问题:如规定整型与实型运算时需将整型置换成实型量。这样需要进行类型的语义处理。增加语义变量,用E type表示E的类型信息, E type的值成为int 或real。此外,用单目运算符itr表示将整型运算对象转换成实型。为了区别整型加(乘)和实型加(乘),把+(*)分别写成+i(*i)和+r(*r)。 这样上面文法中的第(3)条产生式及语义描述:,E = E(1)*E(2) E place=newtemp(); if(E(1) type=int AND E(2) type=int) emit(Eplace=E(1) place*i E(2) place); Etype=int; else if(E(1) type=real AND E(2) type=real) emit(Eplace=E(1) place*r E(2) place); Etype=real; else if(E(1) type=int AND E(2) type=real) t:=newtemp(); emit(t=itr E(1)place); emit(E=t*r E(2) place);,Etype=real; else if(E(1) type=real AND E(2) type=int) t:=newtemp(); emit(t=itr E(2)place); emit(E=E(1) place*r t); Etype=real; ,例:赋值语句X:=B*(C+D)+A的语法制导翻译过程如表:,逆波兰表示: XBCD+*A+:=,(2),(2),(3),(1),例子:有文法: (1)EE(1)+E(2) (2)EE(1)*E(2) (3)E(E(1) (4)Ei 其后的语义规 则见上面文法 对应产生式 的语义规则,例:表达式B*(C+D)的语法制导翻译过程如表:,逆波兰表示: BCD+*,二、布尔表达式的翻译 程序中的布尔表达式的作用: (1)计算逻辑值 (2)用作语句的控制条件 常用的布尔表达式可用下述文法描述: E =EE|EE|E|(E)|i rop i|i 其中, , , 为逻辑运算符;rop代表关系运算符(, , );i为逻辑变量或逻辑常量;i rop i为关系表达式。 1. 布尔表达式的翻译 布尔表达式的计值方法: (1)通过逐步计算出各部分的值来计算整个表达式的值. 例:假定用1表示true,0表示false,则布尔表达式:,1(0 0) 1 =1 (0 1) 1 =1 0 =1 (2)利用逻辑运算符的性质计值 如:当A=1,则AB的值(不管B为何值)一定为1。 布尔表达式计值方法不同,则采用的翻译方法也不同。 例:按第(1)种方法,布尔表达式A=BCD将被翻译成如下的四元式序列: (1) if A=B goto (4) (A=B为真转(4)) (2) T1=0 (3) goto (5) (4)T1=1 (5) T2=C D (6) T3=T1 T2,例:按布尔表达式第(1)种计值法,将文法:E =EE|EE|E|(E)|i rop i|i表示的布尔表达式翻译成四元式的翻译方案。 E =E(1) E(2)E place=newtemp(); emit(E place=E(1) place E(2) place); E =E(1) E(2)E place=newtemp(); emit(E place=E(1) place E(2) place); E = E(1) E place=newtemp(); emit(E place=E(1) place); E = (E(1) E place= E(1) place; E = i(1)rop i(2) E place=newtemp(); emit(if i(1) place rop i(2) place goto nextq+3); emit(E place=0); emit(goto nextq+2); emit(E place=1) E = i E place= i place,2.控制语句中布尔表达式的翻译 布尔表达式不仅可以计值,而且其值还决定了程序控制流的转向(如if和while中). 现讨论布尔表达式E在if-then,if-then-else和while-do中翻译。 三种语句的语法和代码结构为: S =if E then S(1)|if E then S(1)else S(2)|while E do S(1),为了将作为条件控制的布尔表达式E正确翻译成四元式,且E翻译的代码是一串条件转移和无条件转移的四元式代码,则定义下面的一组控制转移的四元式: (1)if E goto Li 当E为真,转向Li ,称Li 为E的真出口,记为E true。 (2)if E(1) rop E(2) goto Li 当E(1) rop E(2)为真,转向Li ,Li 为关系运算符rop的真出口。 (3)goto Lj 无条件转向标号Lj,称Lj为假出口,记为: E false。 例:E的布尔表达式为:af,翻译为如下四元式序列: (1)if af goto E true (6)goto E false,注: 布尔表达式计值是采用第二种方式进行。 描述布尔表达式控制功能的语义的四元式序列都是由一串条件转移和无条件转移四元式代码组成。 现把E布尔式放在条件语句中考察条件语句转移的出口问题 例:有条件语句: if af then S(1) else S(2) 其四元式序列为: (1)if af goto (7) (6)goto (p+1) (7)(关于S(1)的四元式序列)(p)goto (q) (p+1)(关于S(2)的四元式序列) (q)后继四元式,四元式中的地址回填问题 上述if四元式序列中的(1)和(5)四元式的转移地址(7)不能在产生式(1)和(5)四元式时立即得知,至少要等到if语句的then时才能回填(7)表示的产生S(1)的第一个四元式的地址。同理(4)和(6)四元式中的转移地址(p+1)也需要S(2)的第一个四元式的地址回填。 采用拉链技术解决四元式序列中的地址回填 为了记录需回填地址的四元式,把需回填E true 的四元式拉成一个链(为真值的链简称真链);把需要回填E false 的四元式拉成另一个链(为假值的链简称假链) 拉链的方法:若有四元式序列: (10).goto E true (20).goto E true (30). goto E true 则链成:,(10).goto (0) (20).goto (10) (30). goto (20) 其中,地址(30)为链头,0为链尾标志,地址(10)为链尾。 最后,讨论用于if 语句和while语句中的布尔表达式的语义翻译问题。 为了回填四元式中地址信息,要用到公共变量,过程和函数: 四元式(标号或地址)指针nextq nextq的值表示下一个即将要产生的四元式标号,初值为1,每生成一个四元式,其值自动加1。 设置非终结符E的语义变量E bcode E bcode表示非终结符E的第一个四元式标号。 回填过程backpatch(p,t),功能:把p所链接的每个四元式的第四区段都回填为t。若原第四区段已有信息,应保存后再回填为t。 链接函数merge(p1,p2) 将p1和p2为链首的两个链合并为一条,返回合并后的链首值。 根据布尔运算特性,采用自下而上的语法制导翻译方法,给出布尔表达式文法中每个产生式相应的语义子程序: (1) E =i E true=nextq; E fale=nextq+1; E bcode=nextq; emit(if i place goto 0); emit(goto 0); (2)E =i(1) rop i(2) E true=nextq; E bcode=nextq; E fale=nextq+1; emit(if i(1)place rop i(2) place goto 0); emit(goto 0);,(3) E =(E(1) Etrue = E(1)true ; Efalse = E(1)false; Ebcode = E(1)bcode; (4) E = E(1) Etrue = E(1)false; E false = E(1)true; E bcode = E(1) bcode (5) E =E(1)E(2) backpatch(E(1) false, E(2) bcode); Ebcode=E(1) bcode; Etrue=merge(E(1) true, E(2) true); Efalse=E(2) false; (6) E =E(1) E(2) backpatch(E(1) true, E(2) bcode); Ebcode=E(1) bcode; E true =E(2) true; E false =merge(E(1) false, E(2) false); ,产生式(1)(同理(2),(3),(4)式一样)语义子程序中,可见用E =i归约后,E的真假链都有了具体值。这样,在用产生式(5)归约时,E(1)与E(2)的真假链分别也有了具体值。 根据布尔运算的特性可知: (1)当E(1)为假时,计算E(2),所以E(2)的第一个四元式地址(这是已记录在E(2) bcode中) E(2) bcode这时回填为E(1)的假值链,因此有backpatch(E(1) false, E(2) bcode)。 (2)若E(1)为真时,无须计算E(2)而去执行S(1)的第一个四元式,但此时尚未扫描到“then”,因此,保留E(1)已形成的值链首E(1) true;若E(2)为真时,其转移地址用E(1),所以将E(1),E(2)两个真链E(1) true, E(2) true合并为E的一个链。 (3)若E(1)为假,在计算E(2), E(2)也为假,这时整个布尔式E(1) E(2)为假,可见E(2)的假出口与整个布尔式的假出口一致,此时E(2)的假出口E(2) false业已形成。因此,有E false= E(2) false。 (4)尽管有E(1),E(2)参与运算,但按扫描顺序,首先生成E(1)的四元式。因此,E(1)的第一个四元式也就是整个布尔式的第一个四元式,所以有Ebcode=E(1) bcode. 同理不难分析(6)产生式的语义子程序。,下面以表达式ABD为例,按上面的翻译方案,说明将它生成四元式的过程。 (1)首先指示器nextq赋初值为1,当扫描到A时,用E =i归约,根据产生式(1)的语义子程序,有: E(1) true=nextq=(1), E(1) false=nextq+1=(2),Ebcode=1, 生成四元式: (1)if A goto 0 (2)goto 0 此时nextq=3 (2)继续扫描,由自底向上的语法制导翻译可知,这时应归约BD,用产生式 E =E(1) rop E(2) ,有: E(2) true=nextq=(3), E(2) false=nextq+1=(4), E(2) bcode=nextq=(3), 生成四元式: (3)if BD goto 0 (4)goto 0 此时nextq=5 ,(3)继续向上归约,用E=E(1) E(2)归约,有: 回填backpatch(E(1) false, E(2) bcode) Ebcode= E(1) bcode; Etrue=merge(E(1) true, E(2) true); Efalse=E(2) false; 因为E(1) ture=(1), E(2) ture=(3) 所以合并后Etrue(3),将E(1) true放到E(2)的链尾。 回填得:E(2) bcode=(3),将(3)填入E(1) false中,即goto(3)。合并E(1),E(2)的真链将E(2) true填到以E(1) 为真链头的一个四元式区段中。最后E(2)的假链就是E的假链:Efalse=E(2) false; 得到一组四元式: (1)if A goto 0 (2)goto (3) (3) if BD goto(1) (4)goto 0 这时,Etrue=(3),Efalse=(4),三、控制语句的翻译 在程序设计语言中,控制语句的一般形式: if-then, if-then-else, while-do 这些语句由下列文法定义: GS: (1)S =if E then S(1) (2)S =if E then S(1) else S(2) (3)S=while E do S(1) (4)S=A (5)S=L (6)L=L(1);S (7)L=S 其中:非终结符L表示语句串,A表示赋值语句,S为语句,E为布尔表达式。,下面着重介绍控制语句翻译过程中涉及的回填和拉链技术。 1.if语句的翻译 如:S =if E then S(1) else S(2) 翻译此语句应明确以下几点: (1)布尔表达式E的作用仅在于控制对S(1)或S(2)的选择。因此,作为转移条件的布尔式E,使用E true和E false分别指出尚待回填“真”,“假”出口的四元式串; (2)E的“真”出口只有在扫描到then时才能知道,而它的“假”出口则需要S(1)并且到达else之后才能明确。这就是说,必须把Efalse的值传下去,以便在到达相应的else时才能进行回填。 (3)另外,当S(1) 执行完之后意味着整个if语句也已经执行完毕,因此在S(1) 的编码之后产生一条无条件转移指令(goto 0),但在完成S(2) 的翻译之前,该无条件转移的转移目标无法知道。对于语句嵌套的情况,如:if E(1) then if E(2) then S(1) else S(2) else S(3),在翻译S(2)后,S(1) 后的无条件转移目标仍无法确定,因为它不仅跨越S(2),还要跨越S(3)。,可见,转移目标的确定与if所处的环境有关。因此,对非终结符S(或L)设置一个语义变量S CHAIN(或L CHAIN),记忆所有待填信息的四元式链,知道翻译完整个语句后再回填转移目标地址。 为了扫描控制语句的每一时刻不失时机地处理和回填有关信息,将文法改写,并写出if 语句各产生式相应语义子程序。 (1)S =CS(1) (2)C=if E then (3)S=TpS(2) (4)Tp= CS(1) else 根据程序设计语言的处理顺序,首先用产生式(2)C=if E then 归约,这时在then后可产生E的真出口地址。因此将then后的第一个四元式回填至E的真出口地址。E的假出口地址作为待填信息放在C的语义变量C CHAIN中,即,C=if E then backpatch(Etrue,nextq); CCHAIN=Efalse; 接着用产生式(1) S =CS(1)继续向上归约。此时已经处理到C=if E then S(1),注意到归约时E的真出口已经处理,由于E不成立时注意地址V与S(1)语句的待填转移地址相同,E的假出口地址已放在CCHAIN中,但此时转移地址仍未确定,S(1)的待填转移地址的链放在S(1) CHAIN中,所以应将CCHAIN与S(1) CHAIN一并作为S的待填信息链,用函数merge链起来,链头保留在S CHAIN中,即有: S=CS(1) SCHAIN=merge(CCHAIN, S(1) CHAIN 如果if语句没有后继部分,在产生式(1)(2)归约为S后,随即可产生后续第一个四元式地址,以此回填S的语义值SCHAIN。即为if E then S(1)语句的语义子程序。,如果if 语句为if-then-else 形式,用产生式Tp= CS(1) else继续归约。 归约时首先产生S(1)语句序列的最后一个无条件转移四元式,它的标号保留在q中。 (i) S(1)第一个四元式 /*E的真出口*/ 。 (q)goto 0 /*q的第四区段有待回填*/ nextq /*else后的第一个四元式,即E的假出口*/ q就是整个语句S的语义值SCHAIN.因为有待回填q第四区段的值,它与SCHAIN一样,链在以链头为TpCHAIN的链中,用merge函数实现。过程emit产生(q)四元式后,nextq自动加1,这时nextq是else后的第一个四元式地址,也是E的假出口地址,回填该值时Efalse即CCHAIN中,因此有 Tp= CS(1) else q=nextq;,emit(goto 0); backpatch(CCHAIN,nextq); TpCHAIN=merge(SCHAIN,q); 最后用产生式(3) S=TpS(2)归约。当S(2)语句序列处理完后,产生if的后继语句。这时就有了后继语句四元式的地址,该地址是整个if语句的出口地址,它与S(2)语句序列的出口一致。S(2)的出口待填信息在S(2) CHAIN中,因此将TpCHAIN和S(2) CHAIN链接,并以SCHAIN为链头。 S=TpS(2)SCHAIN=merge(TpCHAIN,S(2)CHAIN); 2.WHILE语句的翻译 将产生式:S=while E do S(1) 分解如下: (1)S=WdS(1) (2) Wd=WEdo (3)W=while 写出文法各产生式的语义子程序如下:,观察while语句的代码结构如图,,执行到while时,首先记下E的第一条四元式地址,以便归约到do S(1)后能准确地转到该入口。 其次,语义值W CHAIN仍是待填信息链。 根据while语句的语义,S(1)语句序列的最后一条语句要由能转移到E的第一个四元式的功能,以便判断E是否成立。E成立再执行S(1),E不成立则离开while语句,执行后继语句。因此E的假出口Efalse为待填信息存放在WCHAIN与SCHAIN中。 由while语句执行的顺序,首先用产生式(3)W =while归约,这时nextq记下E的第一个四元式地址,并保留在Wbcode中,即有: (1)W=while Wbcode=nextq;,继续扫描,用产生式Wd=WEdo归约。如前所述,扫描完E后,应该会产生Etrue和Efalse。扫描完do后,可回填Etrue值,用backpatch(Etrue,nextq),而Efalse要等到S(1)语句序列全部产生后才能回填,因此作为待填信息,由WdCHAIN传下去,WdCHAINEfalse继续传下去。即有: (2) Wd=WEdo backpatch(Etrue,nextq); WdCHAIN=Efalse; Wdbcode=Wbcode; 用产生式(1)S=Wd S(1)归约时, S(1)语句序列的全部四元式已产生。应无条件返回E的第一个四元式,因此产生四元式(goto Wdbcode),同时回填E的入口地址到S(1)语句序列中所有需要该信息的四元式中,用backpatch(S(1) CHAIN, Wdbcode)。即有: (3)S=WdS(1) backpatch(S(1) CHAIN, Wdbcode); emit(goto Wdbcode); SCHAIN=WdCHAIN; goto Wdbcode是while的后继语句。后继语句的第一个四元,式地址是E的假出口,已在WdCHAIN中,将该信息作为整个while语句的假出口保留SCHAIN中,以便回填。 例:将下列语句翻译成一组四元式, while AB6) then x=x-1 else y=x+1 根据while,if语句的文法中产生式语义动作和布尔表达式以及赋值语句的翻译方案,翻译该语句的一组四元式如下: 100 if A goto 104 /*Wbcode=100*/ 101 goto 102 102 if B6 goto 106 105 goto 109 106 T1=x-1 107 x= T1,108 goto 111 109 T2=x+1 110 y= T2 111 goto 100 112,最后,SCHAIN112回填在E的假出口中。,A代码,BD代码,X6代码,X=X-1代码,Y=X+1代码,T,F,T,T,F,F,代码结构图,小结及举例 一.小结 1.主要内容:语义分析采用语法制导翻译方法以及中间代码的生成。 (1)语义描述的工具属性文法。 属性文法定义为三元组AG(G,V,E),它将文法G.属性V和属性的断言E有机的结合在一起,准确的描述了处理(归约或推导)每
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年统计业务题库及答案
- 工业分析与检验模拟练习题及答案
- 托福考试试题及答案
- 2025购销合同(国内产品)
- 2025花卉绿植购销合同协议书样本
- 2025(参考)城市供用电合同(示范文本)样式例文办公文档
- 2025年戏腔音乐考试题及答案
- 2025年重庆特种作业建筑考试试题及答案
- 消防员证考试试题及答案
- 2025合作协议公司加盟合同范本示例
- 帕金森病患者吞咽障碍康复中国专家共识 2025版解读
- 现代农业产业园的信息化管理平台建设
- 全套电子课件:网络信息编辑实务
- 《网店色彩设计》课件
- 《铁路技术管理规程》(普速铁路部分)
- 《中国汽车产业格局》课件
- 老年女性子宫颈癌筛查中国专家共识(2024版)解读
- CNAS-GL025:2023 校准和测量能力(CMC)表述指南
- 船用齿轮箱基础知识培训讲义
- 古建筑屋面瓦拆除与修复方案
- DB22T 2091-2014 国境空港口岸检验检疫设施建设规范
评论
0/150
提交评论