[工学]编译原理课程设计报告.doc_第1页
[工学]编译原理课程设计报告.doc_第2页
[工学]编译原理课程设计报告.doc_第3页
[工学]编译原理课程设计报告.doc_第4页
[工学]编译原理课程设计报告.doc_第5页
已阅读5页,还剩4页未读 继续免费阅读

下载本文档

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

文档简介

编译原理课程设计上海交通大学编译原理课程设计报告Tiger编译器的设计与实现张至先 5080309910目录1.介绍32.词法分析53.语法分析74.语义分析115.中间代码生成186.汇编指令选择247.寄存器分配298.生成汇编代码359.感想3610.附录A Tiger.flex3711.附录B Grm.cup4112.附录C queens.tig4613.附录D parse.txt4714.附录E lib.s5515.附录F out.s5716.附录G 参考文献631. 介绍本课程设计旨在实现一个Tiger语言的编译器。1.1 Tiger语言规范详见Tiger Language Reference Manual。1.2 课程设计所用语言JAVA1.3 课程设计参考“虎书”Modern compiler implementation in JAVA,1st edtion1.4 实验环境(工具)Java 开发环境: Eclipse词法分析器: JFlex语法分析器: CUPMIPS模拟器:PCSPIM1.5 设计模块编译器的设计涉及到很多方面,可分为多个模块,从前端(词法分析)到后端(目标代码生成)依次完成。具体如下(按完成先后顺序):1. 词法分析2. 语法分析3. 语义检查4. 中间代码生成5. 代码规范化6. 汇编指令选择7. 寄存器分配8. 目标代码生成9. 程序运行模块流程图如图1.1所示。每个模块的实现方法将在接下分章节详述。图1.1 Tiger编译器模块流程图1.6 项目时间安排本学期第十周开始启动该项目,第十四周完成词法分析和语法分析(本项目的前两个模块),第十七周完成至寄存器分配之前,第十八周完成工程及课程设计文档,第十九周提交检查。1.7 项目完成情况基本上符合原计划,现已完成最终的目标代码生成,可以将较复杂的tiger程序编译MIPS汇编文件,并在模拟器上正确运行。2. 词法分析将源程序字符串读入,利用了有穷自动机原理将其按照词法规则分割为符号单元,实现词法分析程序由工具JFlex生成。122.1 安装词法分析工具JFlexJFlex是java语言环境下非常好用的一款词法分析工具,本次课程设计所用的JFlex为其官网上最新的JFlex1.4.3,本章中所有有关JFlex的操作均参考自JFlex Users Manual。由于本工程早期是在Linux下进行的,所以我下载的是tar格式的压缩包,再执行以下指令进行安装:tar -C /zzx1989/ -xvzf jflex-1.4.3.tar.gzln -s /zzx1989/JFlex/bin/jflex /usr/bin/jflex运行是运行如下指令:jflex Tiger.flex即可生成词法分析程序yylex.java。2.2 Tiger.flex代码清单详见附录A。2.3 问题解决2.3.1 多重注释在yylex中新加入一个状态COMMENT。当读入/* 时进入此状态并设置一个计数器count。继续读入若读入/*则计数器count+;若读入/*则count-;并判断当前count值,若等于0则退出COMMENT状态。2.3.2 转义字符转义字符位于字符串中,首先设定有STRING状态。当读入”时进入。而后对转义字符进行处理。典型如n t 则直接进行转义处理。对于121等转义字符,则先读入判断其数字大小是否属于0,255中。若符合则进行转义,否则报错。具体代码如下:yybegin(YYINITIAL);return tok(sym.STRING,string.toString();nt+ string.append(yytext();tstring.append(t);nstring.append(n);string.append();|string.append();:digit:digit:digit:int d=new Integer(yytext().substring(1,4); if(d=0&d=127) string.append(char)d); else err(The escape sequence is out of the range);(A-Z|_)char temp=yytext().charAt(2); int num=(int)temp-64; string.append(char)num);(WhiteSpace|LineTerminator)+.|n2.3.3 用到的开关量在Tiger.flex开头的选项声明部分打开%line和%column两个开关,JFlex就会在扫描时维护两个变量yyline和yycolumn表示当前扫描到的行与列,这在报错时可以用到。3. 语法分析这个模块的目的是以词法分析的结果作为输入,进行语法分析,输出抽象语法树。语法分析的中心思想依然是有穷自动机。根据LR语法,将对应的语法用实现其相应自动机。首先写出对应语法,而后利用java_cup来生成对应的自动机。依次读出lexer中的词法单元,而后在自动机的控制下按照语法逐渐规约,并在规约过程中通过result的传递得到对应的语法树,而后将抽象语法树输出。33.1 Symbol包Symbol包中封装了符号(Symbol.Symbol)和符号表(Symbol.Table)。常用的函数有:Symbol.symbol (String) 静态函数,如果字符串表示的符号存在,则返回原来的符号,否则新建一个与字符串对应的符号。Table.put (Symbol, Object) 将“符号对象”序对放入当前符号表中。Table.get (Symbol) 返回当前符号表中符号所对应的对象。Table.BeginScope() 在当前符号表中新建一个子符号表。Table.EndScope() 退回到上一级符号表。注意,在Table.BeginScope()之后父符号表的内容依然可见,但在Table.EndScope()之后子符号表的内容将被删去。符号(Symbol.Symbol)和符号表(Symbol.Table)将在接下来的模块中用到。3.2 Absyn包Absyn包中包含了抽象语法树的结点。其中类的组织关系如图3.1-3.5所示。图3.1 Absyn包中的类图(1)图3.2 Absyn包中的类图(2)图3.3 Absyn包中的类图(3)图3.4 Absyn包中的类图(4)图3.5 Absyn包中的类图(5)3.3 Java cup的使用javacup目录提示符下输入: java java_cup.Main -expect 2 Grm.cup其中参数 -expect 2 表示至多2个冲突(规约移进或规约规约是允许的),在这种情况下,javacup将使用移进代替规约,遇到规约规约冲突时采用高优先级。 运行后将生成两个java文件:parser.java和sym.java。parser为分析器,sym为常数表。3.4 Grm.cup代码清单详见附录B。3.5 问题解决3.5.1 优先级定义在开始文法规则之前,javacup允许定义终结符号的优先级和结合情况。precedence right FUNCTION,TYPE;precedence right OF;precedence right DO, ELSE, THEN;precedence nonassoc ASSIGN;precedence left OR;precedence left AND;precedence left LPAREN;precedence nonassoc LE, GT, EQ, NEQ, GE, LT;precedence left PLUS, MINUS;precedence left TIMES, DIVIDE;precedence left UMINUS;precedence left LBRACE;precedence left LBRACK;在这里,优先级为由低到高排列,left/right/nonassoc表明其结合情况。特别的,将ELSE和THEN设置为又结合可以很好的解决if-else二义性的问题。3.5.2 参数,表达式列表可以为空因此应当把为空的情况分别单独列出来考虑。如函数调用:expr:=ID:id LPAREN expr_list:e RPAREN : RESULT= new CallExp(idleft,idright,sym(id),e); :;expr:=ID:id LPAREN RPAREN : RESULT= new CallExp(idleft,idright,sym(id),null); :;3.5.3 下标变量的规约冲突比如x.a3可以被规约成x.(a3)。解决的办法是:lvalue:=ID:id1 DOT ID:id2 : RESULT= new FieldVar(id2left,id2right,new SimpleVar(id1left,id1right,sym(id1),sym(id2); :;lvalue:=lvalue:l DOT ID:id : RESULT= new FieldVar(idleft,idright,l,sym(id); :;lvalue:=lvalue:l LBRACK expr:e RBRACK : RESULT= new SubscriptVar(eleft,eright,l,e); :;lvalue:=ID:id LBRACK expr:e RBRACK : RESULT= new SubscriptVar(eleft,eright,new SimpleVar(idleft,idright,sym(id),e); :;4. 语义分析语义分析主要是对上阶段生成的抽象语法树进行语法规则检查。检查通过则交给接下来的中间代码生成模块产生中间代码树(IRTree)。从功能上看这两个模块是分开的,但在实现的时候则并不是先后完成的,而往往是语义分析通过了一部分便立刻将其翻译,再递归的分析翻译接下来的部分。44.1 Semant包Semant包主要包括了和语义分析有关的类。具体如下:Entry:指明了一个非数据类型标识符 (变量和函数) 的种类。VarEntry: 派生自Entry,用于普通变量LoopVarEntry: 派生自Entry,用于循环变量StdFuncEntry:派生自Entry,用于库函数FuncEntry:派生自Entry,用于普通函数Env:环境符号表,其中包含两个Symble.Table tEnv和vEnv。tEnv 记录了当前的类型名称,是符号类型表, 注意其中会有类型绑定机制: 如果其中的类型是用Types.NAME表示的,则实际类型存储在NAME.binding里面。vEnv记录了当前的变量、函数等信息,是符号入口表。在其中的每个项目为Entry的某个派生类。LoopEnv:主要用于在分析时判断是否处于循环当中,具体详见本章的问题解决。Semant:负责对抽象语法分析树进行语义分析和翻译,其中翻译部分往往是通过调用其中的Translate成员变量来实现的,该类内部的主要工作还是语义分析。ExpTy:其实就是对Translate.Exp和Types.Type进行分装,在Semant类中对Absyn包中的表达式进行翻译,即返回带类型的表达式ExpTy。4.2 Type包Type包主要用来描述数据类型标识符,其类关系如图4.1所示。图4.1 Type包类图Type类的coerceTo函数描述了关于类型的强制转换部分的信息: 除了nil类型可以赋值给record类型外,其它只能转换到本身,且不能将nil赋值给nil。4.3 语义分析步骤语义分析的一般步骤为: 当检查某个语法结点时,需要递归地检查结点的(包括以后的中间代码翻译)每个子语法成分 ,确认所有子语法成分的正确且翻译完毕后,调用Translate对整个表达式进行翻译。这些步骤主要是在Semant类中进行的,主要用到的函数有:ExpTy Semant:transVar(Absyn.Var)将抽象语法树中的变量翻译成带类型的表达式ExpTy Semant:transExp(Absyn.Exp)将抽象语法树中的表达式翻译成带类型的表达式Expre Semant:transDec(Absyn.Dec)将抽象语法树中的声明翻译成Translate.ExpreType Semant:transTy(Absyn.Ty)将抽象语法树中的类型翻译成数据类型标识符4.4 语义检查规则IntExp StringExpNilExp VarExp CalcExp左右均为int类型 EqExp左右中任一个不能为void类型 左右不能全为nil可以一个为nil一个为record类型 其它情况下必须左右类型完全一致 RelExp左右两边必须全为int或string AssignExp:t1:=t2 如果t1是简单变量并且在vEnv中查得它是LoopVarEntry,则报错不能给循环变量赋值如果t2是void类型则出错 如果t2不能强制转换成t1则出错 CallExp 如果在vEnv里查不到函数名或者它不是FuncEntry (包括StdFuncEntry) 则报错:函数未定义 然后逐个检查形参和实参是否匹配(用AssignExp的方法检查),遇到不匹配则报错. 在遍历形参链表的时候,可能遇到链表空或有剩余的情况,此时分别报告实参过多或不足的错误 RecordExp 先在tEnv中查找类型是否存在,若否或非记录类型报告未知记录类型错误 然后逐个检查记录表达式和记录类型域的名字是否相同 然后逐个检查记录表达式和记录类型域的类型是否匹配 (用AssignExp方法检查) 在遍历记录类型链表的时候,可能遇到链表空或有剩余的情况,此时分别报告域过多或不足的错误ArrayExp 先在tEnv中查找类型是否存在,若否或非数组类型报告未知记录类型错误 再检查数组范围是否为整数,若否报错 再用AssignExp的方法检查tEnv中的数组类型和实际类型是否匹配,若否报告类型匹配错误IfExp 如果测试条件的表达式不返回整数,报告测试条件错误(Tiger中非0为真,0为假) 如果缺少else子句,且then子句有返回值,报错如果不缺少else 子句,检查then 和else 的返回值是否匹配(采用AssignExp 的方法,只是都返回nil被认为是合法的)WhileExp如果测试条件不是整数,报告测试条件错误如果循环体有返回值,则报错(while循环体不能有返回值)注意这里不需要使Begin/EndScope注意进/出循环使要调用newLoop 和exitLoop (详见break 表达式)ForExp如果初始值和终止值不是整数类型,则报错用BeginScope进入vEnv新的符号表 (循环内部用)为帧分配循环变量的Access把循环变量添加到vEnv的LoopVarEntry项目中用EndScope退出vEnv的符号表注意进/出循环使要调用newLoop 和exitLoop (详见break 表达式)BreakExp设一个堆栈,进入循环推入一个Label, 退出循环弹出一个Label,如果堆栈为空时出现break语句则报告错误,关于栈的操作由以下函数完成:translate.loopExit (堆栈)void translate.newLoop (入栈)void translate.exitLoop (出栈)boolean translate.isInLoop (测试是否在堆栈中)newLoop和exitLoop在翻译for和while语句时成对使用这样做的优点是在以后翻译成IR 树时可以利用这个堆栈LetExp无需错误检查,只需按如下步骤进行:vEnv和tEnv分别用BeginScope进入新的符号表翻译定义部分 (letin 之间), 用bine2stm将IR 树结点连接翻译体部分 (inend 之间)vEnv和tEnv用EndScope返回到原符号表如果体部分为空或者没有返回值,用bine2stm将定义和体部分连接如果体部分不空或有返回值,用bine2exp 将定义和体部分连接,把体部分的返回值和类型作为最终的返回值和类型SeqExp无需错误检查,因为它是若干个已经检查过的表达式的链分别将每个子表达式进行翻译,用 bine2stm函数将它们的IR树结点连接起来在翻译最后一个表达式时:如果它的类型是VOID,则仍用combine2stm 将它们的IR 树结点连接起来,并返回VOID 作为返回类型否则,用bine2exp 将它们的IR 树结点连接并返回最后一个表达式的值和类型作为返回值和返回类型SimpleVar先检查vEnv, 若没找到变量名或类型不是VarEntry则报告变量未定义SubscriptVar如果它除去下标部分后的类型不是数组类型,则报错若下标部分不是int类型报错FieldVar若除去域部分后不是记录类型,则报错然后逐个查找记录的域,如果没有一个匹配当前域变量的域,则报错NameTy检查tEnv,若没有发现类型,则报告未知类型错误ArrayTy检查tEnv,若没有发现类型,则报告未知类型错误,否则返回转换后的ARRAY 类型RecordTy检查该记录类型每个域的类型在tEnv中是否存在,若否,则报告未知类型错误若全部正确,则最后返回转换后的RECORD 类型下面是声明的检查,在这个阶段可以不需要返回值VarDec如果有显式的类型声明,按AssignExp的方法检查是否类型匹配若无显式的类型声明且初始值为nil,则报错,因为只有记录类型可以用nil初始化若无初始值,报错,因为Tiger语言所有的变量声明必须有初始化如果没有以上错误,则为变量在帧上分配空间把变量作为VarEntry添加到vEnv中变量声明不采用块机制,而是在任何地方都直接覆盖TypeDec1 Tiger 语言的类型声明采用块机制(见第二部分),所以要先在一个声明块中检查否有重复的声明(而在不同的块中可以有重复的声明的,新的将冲掉旧的),若有,报告重定义错误(具体实现时可采用HashSet类)2 接下来翻译出实际的Type 类型 (Typedec.ty.translate 方法) ,再从tEnv 中查找出NAME类型,将实际的Type类型绑定到NAME类型3 检测循环定义问题 (见4.3)4 如果以上均正确,添加类型到tEnv中FunctionDec函数声明同样采用块机制. 对于函数声明块中的每个声明,做以下检查15:1 同类型声明类似,先检查声明块中是否有重复的声明2 还要检查是否与标准函数冲突,可以通过扫描vEnv 中的StdFuncEntry 实现,若有报错3 然后检查参数列表,与记录类型RecordTy的检查完全相同,得到RECORD 类型的形参列表4 接着检查函数返回值,如果没有返回值则设置成void5 无误后,为函数创建新层,将函数作为FuncEntry添加到vEnv中然后再重新扫描一遍声明,如果某函数不是标准函数,则做以下操作15:1 用BeginScope进入vEnv的一张子表(函数内部用),并转移到新层2 将函数参数存入子表3 翻译函数体, 并用ProcEntryExit给函数体加上关于函数调用的指令4 检查函数体的返回类型是否和声明部分匹配,若否则报错5 用EndScope退出子表,转移到当前层4.5 问题解决4.5.1 循环定义问题Env中有一个类型为LoopEnv的变量loopEnv,这是用来判断当前的Semant翻译状态是否处于循环体中。实现的原理与词法分析中处理嵌套注释的方法类似但更为复杂,考虑如下一种情况。Function aWhile()Function bWhile().xxxx如果简单的按处理嵌套注释的方法,在xxxx初的loop值仍然大于零,意味着仍处于循环内。可是实际上,如果xxxx是break则此处会有一个错误。造成这个错误的原因是函数间有不同的作用域,b的作用域屏蔽了a,在xxxx处是看不到a的循环的。处理办法是LoopEnv中维护一个StackStack成员s。外层的stack表示作用域,内层的stack表示是否有循环。当进入新的作用域时,push一个空的stack到外层的stack中去,作用域结束时则pop此stack。遇到循环开始时在内层stack中push一个Label,循环结束就pop这个Label。这样的话,当前处在循环体中的条件就变成了外层stack的最顶层不为空。4.5.2 类型的循环定义在Tiger语言中类型的循环定义是不被允许的,如下列语法:type a1=a2 type a2=a3 type a3=a4 type a4=a1是错误的。为了检查出循环定义错误,可以用NAME类型中的isLoop成员函数来判断:public boolean isLoop() Type b = binding;boolean any;binding = null;if (b = null)any = true;else if (b instanceof NAME)any = (NAME) b).isLoop();elseany = false;binding = b;return any;5. 中间代码生成结合一些和函数调用有关的活动记录,在通过了语义检查之后,本模块将抽象语法生成树翻译为中间表示树(IRTree)。55.1 Frame包这个包主要包含以下3个类:Frame定义了抽象的程序帧结构,用于存放函数参数,返回地址,寄存器,栈指针,帧指针返回值等重要信息。Access用于描述那些存放在帧中或是寄存器中的形式参数和局部变量,也是抽象数据类型。AccessList将Access串成链表。5.2 Mips包这个包包含4个类:MipsFrame具体描述了用于Mips机的帧信息,派生自Frame.Frame。主要任务为进行初始化寄存器、新建帧、分配Access及函数调用处理(procEntryExit1)。InFrame派生自Access,表示存放在帧中的变量。InReg派生自Access,表示存放在寄存器中的变量。因此两者的exp和expFromStack方法的实现是不同的。Codegen代码生成器,用于把IRTree节点转换为InstrList,将在生成汇编指令时用到。图5.1展示了以上两个包中主要的类关系图。图5.1 Mips包和Frame包的类图5.3 Level类Level是用来描述静态连接用的数据结构,它被封装在Translate.Level中。Level总是和Frame绑定在一起的。Level描述了函数的静态信息,而Frame描述函数的动态信息 Level类的主要类成员:Level parent上一级的层Frame.Frame frame对应的帧结构AccessList fomals 函数调用的参数(第一个为静态链接)。静态链接主要是在翻译变量和函数调用时需要用到。5.4 Tree包Tree包定义了中间树的节点,这是一种抽象的机器语言,它无需太多地考虑机器特性的细节就可以对目标机的操作进行表达。IRTree的节点可以分成Expr派生出来的和Stm派生出来的,这两者的主要区别在于Expr有而Stm没有返回值。他们的关系如图5.2-5.3所示。图5.2 Expr派生类图图5.3 Stm派生类图5.5 Translate包这个包中的类可以分为几个部分(例如上面提过的Level类也属于这个包),最主要的是Expre及其派生类。这些类是IRTree的“代理建造者”。Translate不直接生成树的具体结点,而是先生成这些代理类,由它们通过方法unEx,unCx 或unNx来生成具体的结点。这三个方法即Expre类的三种方法,表示分别转换到Ex,Cx和Nx。Ex为有返回值的表达式,Nx为无返回值的表达式,Cx表示一个判断条件,有真假两个出口。因此这三种方法的返回值分别为Tree.Expr,Tree.Stm和Tree.Stm。这些类的关系如图5.4所示。图5.4 Expre派生类图另一部分和Frag类有关。一个Frag类可能是一个字符串或一个函数块,因此派生出DataFrag和ProcFrag。DataFrag中包含标号和字符数据;函数块为ProcFrag, 其中有函数体 (Tree.Stm) 和其Frame。每个Frag都包含一个指向下一个Frag的指针,因此可以形成段链表。在翻译过程中,段总是不断增大的,段链表被私有地维护在Translate类中,它提供了AddFrag和GetResult两个接口用于添加段和取回整个段链表。图5.5 Frag派生类图5.6 具体翻译过程翻译情况IR 树结果整型常数 valueCONST (value)字符串常数 valueNAME (label)nil变量EX(CONST(0)变量表达式 translate.ExpExp运算表达式 left oper rightEX(BINOP (binop, left, right)字符串运算 left oper rightRELCX(OPER, EX (COMP) , EX (0)其它关系运算 left oper rightRELCX (OPER, LEFT, RIGHT)赋值运算 lvalue=exNX(MOVE (lvalue, ex)TransCallExpEX(CALL(NAME(func_name), args)库函数调用TransExtCallExpEX ( EXTERNAL_CALL )stm的连接 e1, e2NX(SEQ(NX(E1), NX(E2)exp的连接 e1, e2EX(ESEQ(NX(E1), EX(E2)transRecordExpEX(ESEQ(SEQ(MOVE(TEMP(addr),alloc),init),TEMP(addr)transArrayExpEX(alloc)if, while, forIfExp, WhileExp, ForExpbreakNX (JUMP (LABEL)简单变量EX(MEM (BINOP (PLUS, TEMP(FP), CONST(OFFSET)下标变量 varidxEX(MEM(BINOP(BINOP.PLUS, EX(VAR),BINOP(MUL,EX(IDX),CONST(WORDSIZE)域变量 varnumEX(MEM(BINOP(BINOP.PLUS, EX(VAR) , CONST(NUM*WORDSIZE)翻译函数体procEntryExit这个表格给出了大致的翻译方案,具体实现以代码为准。5.7 问题解决5.7.1 ProcEntryExit函数族在本设计中用到了四个ProcEntryExit函数,它们分别是:Translate:ProcEntryExit为函数体加上返回值的信息, 并把IR树结点加入段中Frame: ProcEntryExit1在函数体前加上保存fp,ra,Callee-save和参数,并计算新fp,然后在函数体后恢复被保存的寄存器Frame: ProcEntryExit2函数体经其处理后保持不变,仅仅增加一条空指令Frame: ProcEntryExit3主要为函数体分配帧空间,并为其设置函数体标号。4个ProcEntryExit的执行顺序为:ProcEntryExit (translate.java) 中调用ProcEntryExit1emitProc中 (Main.java) 中调用ProcEntryExit3这样最终生成的关于函数体的汇编代码为:1) 设置函数体标号2) 计算 $SP, 分配帧空间3) 保存原 $FP4) 计算新 $FP ($fp=$sp-帧空间+4 bytes)5) 保存 $RA6) 保存 Callee-Saved 寄存器7) 保存参数 $A0$A38) 函数体9) 将函数体返回值写入 $RV10) 恢复 Callee-Saved 寄存器11) 恢复 $RA12) 恢复 $FP13) 恢复 $SP, 将$SP 加上相应的帧空间14) 跳转到返回地址其中1,2,13,14由ProcEntryExit3完成,9由ProcEntryExit完成,其余由ProcEntryExit3完成。5.7.2 规范化从已经得到的IR 树出发,规范化过程将帮助完成下面的工作:AIR 树被写成一个没有SEQ和ESEQ 结点的规范树表B根据该表划分基本块,每个基本块中不包含内部跳转和标号C基本块被顺序放置,所有的CJUMP 都跟有false标号由于这部分的代码在实现框架中已经提供所以我们不需要知道任何细节,只需将提供的Canon 文件夹复制,对于以上三步,只需在最后装配时调用下面的接口就可以了。Canon.Canon.linearize (Tree.Stm s)Canon.BasicBlocks. BasicBlocks(Tree.StmList stms)Canon.TraceSchedule(BasicBlocks b)6. 汇编指令选择66.1 常用MIPS汇编指令sw reg, addr 将寄存器reg保存到内存地址addr中lw reg, addr 将内存地址addr中的内容保存到寄存器reg中li reg, imm 将立即值imm保存到寄存器reg中la reg, addr 将地址addr (而不是其中的内容) 保存到寄存器reg 中move reg1, reg2将寄存器reg2 移动到寄存器reg1中jal label 无条件转移到label, 返回地址 (下一指令) 存于$Ra寄存器jr reg 无条件转移到reg中所保存的地址, 返回地址存于$Rasubu reg1,reg2,CONST 将reg2 的值减去CONST后放入reg1addu reg1,reg2,CONST 将reg2 的值加上CONST后放入reg1beq reg, src, label 当reg=src时跳转到labelbge reg, src, label 当reg=src时跳转到labelbgt reg, src, label 当regsrc时跳转到labelble reg, src, label 当reg=src时跳转到labelblt reg, src, label 当reg 活性分析 - 生成干扰图 根据干扰图分配寄存器(着色算法)77.1 流图的生成FlowGraph.AssembleFlowGroup封装了一个面向汇编指令的流图结构,在这个类中每个结点代表一个汇编指令,边为可能的控制转移。该类还提供了一个构造函数,可以输入InstrList对象来生成流图。public AssemFlowGraph(InstrList instrs) represent = new Hashtable();Dictionary labels = new Hashtable();for (InstrList i = instrs; i != null; i = i.tail)

温馨提示

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

评论

0/150

提交评论