中间代码生成_第1页
中间代码生成_第2页
中间代码生成_第3页
中间代码生成_第4页
中间代码生成_第5页
已阅读5页,还剩29页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、计算机科学与工程学院课程设计报告题目全称:常用边缘算法的实现学生学号:2506203010 姓名:王嘉指导老师:职称:指导老师评语:签字:课程设计成绩:设计过程表现设计报告质量总分编译器中间代码生成的研究与实现作者: 王嘉 学号: 2506203010 指导老师:吴洪摘要 : 在编译器的翻译流水线中,中间代码生成是处于核心地位的关键步骤。它的实现基 于语法分析器的框架, 并为目标机器代码的实现提供依据。 虽然在理论上没有中间代码生成 器的编译器也可以工作, 但这将会带来编译器的高复杂度, 低稳定性和难移植性。 现代编译 理论不仅要求中间代码的生成, 还要求基于中间代码的优化。 本文研究并实现了

2、一个轻量级 类 C 语言的中间代码生成器,并就中间代码生成的原理进行了细致的阐述。关键字 :中间代码生成、语法制导翻译、翻译模式、语法树、三地址码一、目的及意义在编译器的分析综合模型中, 前端将源程序翻译成一种中间表示, 后端根据这个中间表 示生成目标代码。 目标语言的细节要尽可能限制在后端。 尽管源程序可以直接翻译成目标语 言,但使用与机器无关的中间形式具有以下优点:1. 重置目标比较容易:不同机器上的编译器可以在已有前端的基础上附近一个适合这 台新机器的后端来生成。2. 可以在中间表示上应用与机器无关的代码优化器。本文介绍如何使用语法制导方法, 基于一种轻量级的类 C 语言 FineC 的

3、词法分析器和语 法分析器,一遍地将源程序翻译成中间形式的编程语言结构,如声明、赋值及控制流语句。 为简单起见, 我们假定源程序已经经过一遍扫描, 生成了相应的词法记号流和符号表、 词素 表结构。基于 FineC 语法标准的语法分析器框架也已经能够正常工作。 我们的任务就是补充 这个框架, 使其在语法分析的过程中生成相应的中间代码, 并将必要的变量和函数声明存放 在一个符号表链中。二、目标语言词法和语法标准:这里定义一个编程语言称作 FineC(“ fine ”指代轻量、精妙) 。它是一种适合编译器设 计方案的语言。 本质上是 C 语言的一个限制了数据类型、 算术操作、 控制结构和处理效率的 轻

4、量子集。1. FineC 语言的词法描述:1 语言的关键字:else ifreturn whileintvoid所有的关键字都是保留字,并且必须是小写2 下面是专用符号:+ - * / < <= > >= = != = ; , ( ) /* */RELOP = < <= > >= = !=ADDOP = + -MULOP = * /3 其他标记是 NUM和ID,由正则表达式定义:ID = letter (letter|digit)*NUM = digit digit*letter = a| , |z|A| , |Zdigit = 0| , |9小

5、写和大写字母是有区别的4 空格由空白、换行符和制表符组成。空格通常被忽略,除了它必须分开NUM、ID 关键字5 注释用通常的 C 语言符号 /* , */ 围起来。注释可以放在任何空白出现的位置(即注释不能放在标记内 ) 上,且可以超过一行。注释不能嵌套。不支持单行 / 注释。FineC 语言的词法分析器输出记号流,记号是一个二元组 (tokentype, lexeme) 。 tokentype 包含了记号的类型, lexeme 包含记号的词素。 例如一个标识符 gcd 的记号是 (ID, 6)。6表示这个标识符在符号表的第 7 项里(与首元的距离是 6,可以把这个整数看作指向 符号表的指针)

6、 。词法分析器后面的步骤分析这个标识符时, 就可以根据此指针访问符号表, 并取出它的词素,也就是字符串“ gcd”。又例如一个整型值36的记号是(NUM, 36)。这里的36不是指向符号表的指针,而是NUM类型的数值。编译器会根据tokentype 决定lexeme的含义。2. FineC 语言的语法描述语法分析器调用词法分析器,对源程序做一遍词法分析,返回的记号流放在缓冲区tokens 中。在 FineC 的实践中, 我们用一个 vector<token> 容器来存放词法分析器返回的这 些记号。语法分析器在这个缓冲区(容器)之上,进行匹配、回溯等必要的操作,实现语法 分析。 常见

7、的语法分析方法有三种: 带回溯的递归下降法、预测分析法 (不带回溯的递归下 降)以及常用于语法分析器自动生成的LR文法分析。前两者属于自顶向下的分析,后者属于自底向上的分析。 FineC 的语法分析器基于带回溯的递归下降法实现,在分析的过程中可 能产生递归和回溯。 当发生回溯时, 意味着出现了某个记号的匹配失败, 但在其之前某些记 号可能已经被成功匹配并扫描。 因此回溯到上层调用时, 不仅要恢复指向记号流的指针, 也 需要考虑是否已经生成了无效的中间代码,并对其进行撤销。语法分析器的原理和实现不是本文讨论的范畴, 这里只给出 FineC 语言的文法标准和简 单的语义解释,供中间代码生成时建立翻

8、译模式使用:(1) program -> declaration-list 程序由一个声明表组成(2) declaration-list -> declaration declaration-list | declaration 声明表包含至少一条声明(3) declaration -> var-declaration | fun-declaration 声明可以是变量声明或函数声明(4) var-declaration ->“int ”ID;由于FineC只支持整型,所以变量声明也只有“int ID ”的形式。注意,不支持变量声明时赋初值。(5) fun-declar

9、ation -> type-specifier ID (params) compound-stmt| type-specifier ID () compound-stmt 函数的返回类型可以是“ int ”或“ void ”, 函数可以有参数也可以没有(6) type-specifier -> "int" | "void"(7) params -> param params | param如果函数有形参,则至少要有一个参数(8) param ->“int ”ID函数的形参也只支持“ int ”一种(9) compound-stmt

10、 -> local-declarations statement-list函数的主体是一个语句块, 包含局部变量的声明和语句表。 注意, 所有的局部变量声明 必须出现在语句之前。(10) local-declarations -> var-declaration local-declarations | empty 局部变量声明可以为空,一个,或多个(11) statement-list -> statement statement-list | empty 语句表也可以为空,或有一个或多个语句组成(12) statement -> expression-stmt |

11、compound-stmt | selection-stmt| iteration-stmt | return-stmt 语句有五种类型,分别是表达式语句,语句块,选择语句,循环语句和返回语句(13) expression-stmt -> expression; | ; 表达式语句可以没有内容,或者由一个表达式构成。(14) selection-stmt -> "if" (condition-expression) statement|“if ”(condition-expression) statement“else ”statement选择语句支持一路分支和

12、二路分支。 根据 condition-expression 的真假决定程序控制流 的流向。(15) iteration-stmt -> "while" (condition-expression) statement循环语句只支持“ while ”的形式,while语句的含义与C语言一致。(16) return-stmt ->“return ”;|“return ”expression;返回语句可以返回值,也可以什么都不返回。(17) expression -> ID = additive-expression | additive-expression表

13、达式可以是赋值语句或者加法运算语句,其中赋值语句返回ID的值。(18) condition-expression -> additive-expression RELOP additive-expression条件表达式比较两个整型值的关系,包括大于,小于,大于等于,小于等于,不等于 和等于,根据其真值指向不同的语句流向(19) additive-expression -> addtive-expression ADDOP term | term(20) term -> term MULOP factor | factor(21) factor -> (additive

14、-expression) | ID | call | NUM以上三条文法生成算术表达式,ADDO包括加和减,MULO包括乘除。运算的因子可以是变量,整数字面值,表达式或者函数返回的结果。这样安排文法是为了满足运算符 的优先级和结合性。即加减比乘除优先级低,加减乘除都是左结合的。(22) call -> ID (args) | ID ()函数调用可以有实参也可以没有。(23) args -> additive-expression, args | additive-expression三、中间代码生成原理1. 中间代码生成器的作用:中间代码生成器不是一个独立的部件, 而是建立在语法分

15、析器框架中的语义动作。 可以 把编译器比作一个流水线, 源程序是源材料, 词法分析器是过滤器, 源程序经过词法分析器 后形成记号流。 语法分析器是一系列相互相关的函数, 控制流在这些函数中的转移过程就是 语法分析的过程。 记号流比作精炼过的材料被送到语法分析器这个流水线上流动。如果没有中间代码生成动作, 语法分析器就像是只有履带没有加工机的流水线, 记号流流过之后没有 任何变化。由上面的比喻可以看出, 中间代码生成和语法分析应该构成一遍( “遍” 的概念请参考 文献 1 ),以词法分析生成的记号流作为输入,以某种表示程序结构的中间表示(语法树 或三地址码)作为输出。生成的中间代码是介于源代码和

16、目标代码中间的一种结构化表示。 它的意义在于能够把前端和后端分开, 提高编译器的可移植性 (因为结构清晰, 对于编译器 研究者来说也提高了可读性)和易优化性(对中间代码的优化可以独立于机器)。2. 语法制导翻译:语法制导翻译是一种实现翻译的思路, 不仅可以用来指导中间代码生成。 实际上, 应用 语法制导翻译的概念, 可以实现任何基于语法分析器框架的语义动作, 应用非常广泛。 比如 把源代码中的算术表达式中缀表示化成前缀表达式,或者类似数学排版语言EQN的构造等等。本文不对语法制导定义做广泛抑或深入的探讨, 只简单介绍其基本原理, 指导中间代码 生成器的设计。1 语法制导定义: 语法制导定义是对

17、上下文无关文法的推广,其中每个文法符号都有一个相关的属性集。 属性分为两个子集,分别称为该文法符号的综合属性和继承属性。属性可以代表任何对象:字符串、数字、类型、内存单元或其他对象。分析树节点上属性的值由该节点所用产生式的 语义规则来定义。节点的综合属性是通过分析树中其子节点的属性值计算出来的;而继承属性值则是由该节点的兄弟节点和父节点的属性值计算出来的。2 语法制导定义的形式:在语法制导定义中,每个产生式 A -> a都有一个形如b := f(c1,c2, ,ck)的语义规则集合与之相关联,其中f是函数,且满足下列两种情况之一:i) b 是A的一个综合属性,且c1,c2, , ,ck是

18、该产生式文法符号的属性ii) b是产生式右部某个文法符号的一个继承属性,且c1,c2, , ,ck也是该产生式文法符号的属性。对这两种情况都称为属性b依赖于属性c1,c2, , ,ck。有时,语法制导定义中的某个规则的目的就是为了产生副作用,比如输出某个字符串或者操作某个结构等。这种语义规则一般被写成过程调用或程序段。在针对语法制导定义的翻译中,把副作用看作非终结符的一个虚综合属性值处理会比较方便。为了便于理解,以下给出一个台式计算器程序的语法制导定义表1台式计算器程序的语法制导定义产生式语义规则LEnprin t(E.val)EE1 + TE.val :=El.val + T.valETE.

19、val :=T.valTT1 * FT.val :=Tl.val * F.valTFT.val :=F.valF(E)F.val :=E.valFdigitF.val := digit exval该定义将一个整数值综合属性val与每个非终结符 E,T和F联系起来。对每个以 E,T和F为左部的产生式,语义规则从产生式右部非终结符的 val值计算出产生式左部非终结符 的val值。记号digit具有综合属性lexvaI ,其值由词法分析器提供,而产生式 L En所对应的 语义规则只是打印 E所产生的算术表达式的值的过程,我们可以认为该规则为非终结符L定义了一个虚属性。3. 翻译模式语法制导定义只是给

20、出了属性值的计算标准,并没有给出属性值的计算顺序。实际上,在一个产生式中,右端非终结符的综合属性、继承属性、左端符号的继承属性的计算顺序是 有要求的。否则,则会出现引用尚未得到的值的翻译错误。由语法制导定义可以得到某种特定的翻译模式,这个翻译模式不仅包含了语法制导定义的属性关系,还包括了计算它们的顺序。当得到一个具体的翻译模式后,编码将变得非常简单。1 L属性定义在介绍翻译模式之前,先介绍一种属性定义:L属性定义。它的特点是其属性总可以用深度优先顺序来计算。基于带回溯的递归下降分析法的语法分析器和L属性结合,能够对词法记号流进行自顶向下的一遍翻译。L属性的规范化定义是:一个语法制导定义是L属性

21、定义,如果对每个产生式A X1X2 Xn,其右部符号 Xj( 1<= j <= n )的每个继承属性仅依赖于下列属性:i) 产生式中Xj左边的符号XI, X2,,, Xj-1的属性。ii) A的继承属性。只含有综合属性的语法制导定义也是L属性定义,因为L属性定义只规定了继承属性。2 翻译模式翻译模式就是将文法符号同属性相关联的上下文无关文法,而且包含在 中的语义动作可以插入产生式右部的任何一个位置。本文所考虑的翻译模式可以同时具有综合属性和继承属性。下面是一个简单的翻译模式,它把带有加号和减号的中缀表达式翻译成后缀表达式。表2一个简单的翻译模式原文法定义翻译模式ET RET RRa

22、ddop T R1 |?R| ?addop T pri nt(addop .1 exeme) R1TnumTnum pri nt( nu mval)下图是输入串9-5+2的分析树,每个语义动作都作为产生式左部所对应节点的子节点。 实际上,我们将语义动作看成终结符,对确定动作何时执行来说,它是一种方便的助记符号。 图中用具体的数字和加(减)运算符代替了记号num和addop。当以深度优先顺序执行下图中的动作时,其输出为 95-2+。E+ Tpri nt( +'R2pri nt( +'图1 9-5+2的带有动作的分析树在构造翻译模式时,要注意,如果同时存在继承属性和综合属性,则(1

23、) 产生式右部符号的继承属性必须在这个符号以前的动作中计算出来。(2) 个动作不能引用该动作右边符号的综合属性。(3) 产生式左部非终结符的综合属性只有在其引用的所有属性都计算出来以后才能计算。 计算该属性的动作通常放在产生式右部的末尾。从一个L属性语法制导定义,我们总能构造出满足上述3个条件的翻译模式。4. 语法树语法树是分析树的压缩形式,对表示语言的结构很有用。如产生式S if B then S1 elseS2在语法树中可能出现为:if-then-else图2 if-then-else语句的语法树在语法树中,运算符和关键字不再是叶节点,而是作为内部节点成为分析树中叶节点的父节点。语法树的另

24、一个简化是单产生式(形如 A B)链可能消失mknode(head, descentl, descent2,)和 mkleaf(ID, id.place)是基于翻译模式构造语法树的两种动作。前者建立一个树节点,如mknode(+, a, b)表示a+b的结构;后者建立一个叶节点,id.place指向标识符在符号表中的位置。语法树有两种表示,一种是指针式,另一种是数组式。数组式用数组的下标取代节点的地址,是指针的另一种表现形式而已,本质上没有大的差别。树的实现算法可以参考数据结构。本文的讨论重点是三地址码的生成,故不对语法树做详细的阐述。5. 三地址码三地址码是下列一般形式的语句序列:x :=

25、y op z 。其中,x、y以及z是名字、常量或编译器生成的临时变量;op代表操作符,例如定点或者浮点算术操作符,或者是布尔型变量的逻辑操作符。注意这里不允许组合的算术表达式,因为语句右边只有一个操作符。这样,像x + y * z这样的源语言表达式应该被翻译成如下序列:t1 := y * zt2 := x + t1t1 与t2是编译器生成的临时变量。这种复杂表达式及嵌套控制流语句的拆解使得三地 址码适合于目标代码生成及优化。由程序计算出来的中间值的名字的使用使得三地址码容易 被重新排列。通用的三地址语句有以下几种(1) 形如 x := y op z 的赋值语句,其中, op 是二元算术操作符或

26、逻辑操作符。(2) 形如 x := op y 的赋值指令,其中 op 是一元操作符。(3) 形如 x := y 的复制语句,将 y 的值赋给 x 。(4) 无条件跳转语句goto L101。接下来将执行标号为L101的三地址语句。(5) 形如 if x relop y goto L101 的条件跳转语句。这条指令对 x 和 y 应用逻辑操作符( <,=, >= 等),如果 x 与 y 满足 relop 关系则执行带有标号 L101 的语句。如果不满足,紧接 着执行 if x relop y goto L101后面的语句,与通常的顺序一样。(6) 过程调用 param x 和 cal

27、l p 及 return y ,其中 y 代表一个返回值,是可选的。它们的 典型应用如下面的三地址语句序列:param x1param x2 param xncall p 作为过程调用 p(x1,x2, , , xn) 的一部分生成。6. 中间代码生成1 三地址码的实现三地址码的实现方法为四元式。四元式是带有四个域的记录结构,即op,arg1 ,arg2以及 result 。其中视三地址码的类型,某些域可能为空。 arg1 ,arg2 以及 result 域的内容 正常情况下是指向这些域所代表的名字在符号表表项的指针。这样的话, 临时名字在生成时一定要被填入符号表。对于支持作用域规则的语言,生

28、成三地址码时需要有一个符号表栈, 栈顶的符号表代表当前作用域。 源代码中的 Par_table_chain 结构实现了这个栈及其必须支 持的操作。2 声明语句的翻译这里用 FineC 语言声明语句的翻译模式说明声明语句翻译的原理。 FineC 语言声明语句 的翻译模式及其解释如下:I declaration-list -> declaration declaration-list1 | declaration1 这条文法可以产生至少一个声明, declaration-list 是起始符II declaration -> var-declaration| Par_table_chai

29、n.mktable() fun-declarationPar_table_chain.jumpout() 这条文法有两个候选式,第一个候选式 var-declaration 匹配变量声明;当地一个候选 式匹配失败时, 说明当前记号流是一个函数声明。 进入一个函数声明后, 会产生一个新的作 用域,一个作用域对应一个符号表,即 Par_table 。在这个函数声明中声明的变量如果和外 围作用域的变量重名,则应该在这个函数的符号表中加入这一变量。 Par_table_chain.mktable() 在进入下面的函数声明语法分析前,先生成一个新的符号 表,并把它置为当前符号表。外围符号表被挂起, 外围

30、符号表的地址被赋予新表。 符号表链 Par_table_chain 实际上是一个栈式结构,它的成员是有相互嵌套关系的符号表。函数声明 匹配完后,跳出它的作用域,把外围作用域置为当前活动作用域。III var-declaration ->“int ”ID; Par_table_chain.enter(ID.name, "int", 4) 这条文法对应变量声明,当匹配完“分号”时,说明当前记号流的确是一个变量声明 (不需要回溯到 II )。此时,在当前符号表中加入这个变量,三个参数分别是变量的名字, 类型和宽度。符号表中有一个 offset 值,初始为 0,每加入一个变量

31、则把 offset 值加上此变 量的宽度。如此一来,新加入的变量就能总是拥有正确的地址(在符号表中的位置)。IV fun-declaration -> type-specifier ID Par_table_chain.set_name_type(ID.name,type-specifier.type) Par_table_chain.add_to_previous() Quads_code.gen_entry(ID.name) (params) compound-stmt| type-specifier ID Par_table_chain.set_name_type(ID.name,

32、 type-specifier.type)Par_table_chain.add_to_previous() Quads_code.gen_entry(ID.name) () compound-stmt这条文法很长。 当匹配函数声明, 得到其返回值类型和函数名时。 先在当前函数的符号 表中附上当前函数的信息。 然后在其外围作用域中加入这个函数项, 参数为函数名, 类型和 当前函数作用域编号(隐含加入,详见源代码)。然后生成一个“ entry 函数名”的三地址 码,代表函数的入口在这里,调用函数时转向这个入口。Quads_code是三地址码数组。然后视情况判断是否匹配参数,然后匹配函数体。注意,

33、因为作用域的跳出在文法II 中, 所以在匹配当前函数的参数和函数体时 , 发生的任何变量或函数声明 ,都被加入到当前函数域中 ,也 就是我们想要的结果。V type-specifier -> "int" type-specifier.type := "int"| "void" type-specifier.type := "void"匹配函数返回值的类型。VI params -> param, params | param 这条文法生成至少一个参数。VII param -> "int&q

34、uot; ID Par_table_chain.enter(ID.name, "int", 4) Quads_code.gen_param_load(Par_table_chain, "load", ID.name)当发生参数的声明时,把此参数加入当前作用域中,然后生成形如“load 形参名”的三地址码,与过程调用时的“param 实参名”一一对应。3 算术表达式的翻译FineC 算术表达式的翻译模式如下I additive-expression -> termadditive-expressionR.i := additive-

35、expressionR := additive-expressionR.sadditive-expressionR -> ADDOP termadditive-expressionR.n := newtempPar_table_chain.enter(additive-expressionR.n, "int", 4) Quads_code.gen_tri(Par_table_chain, ADDOP.name,additive-expressionR.n, additive-expressionR.i, term.nam

36、e) additive-expressionR1.i := additive-expressionR.nadditive-expressionR1additive-expressionR.s := additive-expressionR1.s additive-expressionR-> empty additive-expressionR.s := additive-expressionR.i上面的文法是经过了消除左递归的(语法制导翻译中消除左递归的算法参见参考文献1 )。newtemp在当前作用域中返回一个临时变量的名字,第一次调用返回$1,第二次调用返回 $2,以此类推。 然后把

37、这个临时变量放进符号表中。 再生成以临时变量为 result ,以匹 配到的标识符为argl和arg2,(先在符号表中找到它,当前作用域的符号表找不到,则顺着符号表栈往上找, 如果找到最外层符号表依然找不到, 说明发生了未声明变量的调用, 程序 出错),以ADDO的真值(+或-)为op的四元式,放进 Quads_code结构中。II. term -> factortermR.i := termR := termR.stermR -> MULOP factortermR.n := newtemp Par_table_chain.enter(te

38、rmR.n, "int", 4)Quads_code.gen_tri(Par_table_chain, MULOP.name, termR.n, termR.i, )termR1.i := termR.ntermR1 termR.s := termR1.stermR -> emptytermR.s := termR.i文法II实现的功能与I无异,11和I结合,能够实现算术表达式的左结合性和优先级规 则。III. factor -> (additive-expression) := additive-expressio

39、| ID := ID.name| := | NUM := int_to_str(NUM.value) 操作符运算对象或者是变量,或者是函数调用返回的结果,或者是整型字面值,或者是括号中的表达式求得的值。4 控制流语句的翻译I selection-stmt -> "if" ( to_true := newlabel; to_false := newlabel condition-expression.to_true := to_true condition-exp

40、ression.to_false := to_falsecondition-expression) Quads_code.gen_label(to_true)statementQuads_code.gen_label(to_false)| "if" ( to_true := newlabel; to_false := newlabel condition-expression.to_true := to_true condition-expression.to_false := to_falsecondition-expression)statement1Quads_cod

41、e.gen_label(to_true)to_next = newlabelelse ”Quads_code.gen_goto(to_next)Quads_code.ge n_label(to_false)stateme nt2 Quads_code.ge n_label(to_ next)FineC中的控制流语句有if-else 和while两种。以上文法是if-else的翻译模式。if-then, if-then-else生成的三地址码如下图所示图 3 if-thenif-the n-else 的中间代码当匹配到"if"后,调用newlabel返回一个语句编号(第一次调

42、用返回101,第二次102,第三次103,一次类推),to_true, to_false 作为condition-expression的两个继承属性,用于生成E.code中条件转向三地址码的goto目的地。condition-expresson成功匹配后,生成一个三地址码“ L101 ”,表示当上面的条件为真时,转向这一条语句往下执行,然后调用 statement函数匹配if-then 的执行函数体。匹配结束后,生成一个三地址码“L102 ”,表示当上面的条件为假是,转向这一条语句往下执行。这样一来,当con diti on-expressio n为假时,就自然地跨过了 statement的语

43、句不执行。if-then-else 的翻译与if-then有一样的原理,区别只在于 E.false的指向是另一个 statement ,而在Statement1后面放一个无条件跳转语句,即表示“执行完statement1后不需要再执行statement2 ”。II. iteratio n-stmt -> "while" (to_begin := n ewlabelQuads_code.ge n_label(to_beg in) to_true := n ewlabel; to_false := n ewlabel con diti on-expressi on .to

44、_true := to_truecon diti on-expressi on .to_false := to_falsecon diti on-expressi on)Quads_code.ge n_label(to_true)stateme nt Quads_code.ge n_goto(to_beg in)Quads_code.ge n_label(to_false)while语句生成的三地址码如下图所示图4 while语句的中间代码while 语句的翻译思路也与if-then 类似,只是在Sl.code后面有一条"goto S.begin ”, 表示函数体执行结束后回到S.b

45、egin再次检查E.code的真假,当E.code为假时,跨过"gotoS.begin ",也就结束了整个 while的执行。注意,if-then 语句和while语句的函数体都是 statement,也就是说,它们都有各自的作用域。III.condition-expression-> additive-expression1RELOPadditive-expression2 Quads_code.ge n_con diti on (Par_table_chai n, RELOP. name, additive-expressi on1.n ame, additive

46、-expressi on2.n ame,con diti on-expressi on .to_true) Quads_code.ge n_goto(c on diti on-expressi on .to_false)文法III生成布尔表达式 E.code的代码,需要与文法I ,11的翻译思路相匹配。5过程声明和调用的翻译函数声明的翻译已经在前面说明,下面是 FineC语言中过程调用语句的翻译I . call -> ID ( call. name := n ewtemp Par_table_cha in.en ter(call .n ame, "in t", 4)

47、Quads_code.ge n_uni( "begi n_args")args ) Quads_code.ge n_call(Par_table_cha in, ID.n ame) | ID (call. name := n ewtemp Par_table_cha in.en ter(call .n ame, "in t", 4)Quads_code.ge n_uni( "begi n_args") Quads_code.ge n_call(Par_table_cha in, ID.n ame) II . args -> ad

48、ditive-expressi on Quads_code.ge n_param_load(Par_table_cha in,"param",additive-expressi on.n ame) ,args| additive-expressi on Quads_code.ge n_param_load(Par_table_cha in, "param",additive-expressi on.n ame) 当发生函数调用时,先生成一个当前作用域下的临时变量,用来代表返回值。然后生成一个“ begin_args ”的三地址码,表示开始发送实参。然后进

49、入文法II匹配实参,每次匹配call 函数名”到一个,输出一个“ param 实参”形式的三地址码。实参匹配完毕后,生成 语句,转向相应的“ enter 函数名”。四、 FineC 语言中间代码生成的完整翻译模式1. program -> Par_table_chain.mktable() declaration-list2 declaration-list -> declaration declaration-list1 | declaration13 declaration -> var-declaration| Par_table_chain.mktable() fun

50、-declaration Par_table_chain.jumpout()4 var-declaration ->“int ”ID; Par_table_chain.enter(ID.name, "int", 4) 5 fun-declaration -> type-specifier ID Par_table_chain.set_name_type(ID.name, type-specifier.type) Par_table_chain.add_to_previous() Quads_code.gen_entry(ID.name) (params) com

51、pound-stmt| type-specifier ID Par_table_chain.set_name_type(ID.name, type-specifier.type) Par_table_chain.add_to_previous() Quads_code.gen_entry(ID.name) () compound-stmt6 type-specifier -> "int" type-specifier.type := "int"| "void" type-specifier.type := "void&

52、quot;7 params -> param, params | param8 param -> "int" ID Par_table_chain.enter(ID.name, "int", 4) Quads_code.gen_param_load(Par_table_chain, "load", ID.name)9. compound-stmt -> local-declarations statement-list10. local-declarations -> var-declaration local

53、-declarations | empty11. statement-list -> statement statement-list | empty12. statement -> expression-stmt | selection-stmt | iteration-stmt| return-stmt| Par_table_chain.mktable() Par_table_chain.add_to_previous()compound-stmt Par_table_chain.jumpout() 13. expression-stmt -> expression; |

54、 ;14 selection-stmt -> "if" ( to_true := newlabel; to_false := newlabel condition-expression.to_true := to_truecondition-expression.to_false := to_false condition-expression) Quads_code.gen_label(to_true)statement| "if" (condition-expression)statement1Quads_code.gen_label(to_f

55、alse) to_true := newlabel; to_false := newlabel condition-expression.to_true := to_truecondition-expression.to_false := to_falseQuads_code.gen_label(to_true)to_next = newlabel“else ”Quads_code.gen_goto(to_next)Quads_code.gen_label(to_false)statement2 Quads_code.gen_label(to_next)15. iteration-stmt -

56、> "while" (to_begin := newlabelQuads_code.gen_label(to_begin) to_true := newlabel; to_false := newlabel condition-expression.to_true := to_true condition-expression.to_false := to_false condition-expression) Quads_code.gen_label(to_true) statement Quads_code.gen_goto(to_begin)Quads_code

57、.gen_label(to_false)16. condition-expression -> additive-expression1 RELOP additive-expression2 Quads_code.gen_condition(Par_table_chain, RELOP.name, , , condition-expression.to_true) Quads_code.gen_goto(condition-expression.to_false)17. return-stmt ->“return ”; Quads_code.gen_uni("return") | “return ”expression; Quads_code.gen_param_load(Par_table_c

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论