目标代码生成器.docx
- 文档编号:12285882
- 上传时间:2023-04-17
- 格式:DOCX
- 页数:13
- 大小:58.07KB
目标代码生成器.docx
《目标代码生成器.docx》由会员分享,可在线阅读,更多相关《目标代码生成器.docx(13页珍藏版)》请在冰豆网上搜索。
目标代码生成器
目标代码生成器
实验报告
实验课名称:
编译原理实验
实验名称:
目标代码生成器实验
班级:
学号:
姓名:
时间:
2016-4-30
一、问题描述
代码生成器着重考虑两个问题:
一是如何使生成的目标代码较短;另一个是如何充分利用计算机的寄存器,减少目标代码中访问存储单元的次数。
这两个问题直接影响代码的执行速度。
其中基本问题:
所有代码生成器都要面对何种中间代码输入,(是逆波兰式,四元式,还是三元式?
等问题)何种代码做为目标程序,选择适当的代码指令,最优的寄存器分配方案,和计算顺序等基本问提
二、数据结构设计
逆波兰式→目标代码,采用堆栈。
charx1,x2;/*从语义栈中弹出俩个操作数,用于判断与运算*/
x2=SEM.top();/*SEM.top记得后面要加(),否则没有值!
!
!
*/
cout< SEM.pop(); x1=SEM.top(); cout< SEM.pop(); 三、算法设计 代码生成算法: 对每个四元式: i: A: =BopC,依次执行: 1.以四元式: i: A: =BopC为参数,调用函数过程GETREG(i: A: =BopC),返回一个寄存器R,用作存放A的寄存器。 2.利用AVALUE[B]和AVALUE[C],确定B和C现行值的存放位置B’和C’。 如果其现行值在寄存器中,则把寄存器取作B’和C’ 3.如果B’≠R,则生成目标代码: LDR,B’ opR,C’ 否则生成目标代码opR,C’ 如果B’或C’为R,则删除AVALUE[B]或AVALUE[C]中的R。 4.令AVALUE[A]={R},RVALUE[R]={A}。 5.若B或C的现行值在基本块中不再被引用,也不是基本块出口之后的活跃变量,且其现行值在某寄存器Rk中,则删除RVALUE[Rk]中的B或C以及AVALUE[B]或AVALUE[C]中的Rk,使得该寄存器不再为B或C占用。 寄存器分配: GETREG(i: A: =BopC)返回一个用来存放A的值的寄存器 (1)如果B的现行值在某个寄存器Ri中,RVALUE[Ri]中只包含B,此外,或者B与A是同一个标识符,或者B的现行值在执行四元式A: =BopC之后不会再引用,则选取Ri为所需要的寄存器R,并转4; (2)如果有尚未分配的寄存器,则从中选取一个Ri为所需要的寄存器R,并转4; (3)从已分配的寄存器中选取一个Ri为所需要的寄存器R。 最好使得Ri满足一下条件: 占用Ri的变量的值也同时存放在该变量的贮存单元中,或者在基本块中要在最远的将来才会引用到或不会引用到。 对RVALUE[Ri]中每一变量M,如果M不是A,或者如果M是A又是C,但不是B并且B也不在RVALUE[Ri]中,则 1)如果AVALUE[M]不包含M,则生成目标代码STRi,M 2)如果M是B,或者M是C但同时B也在RVALUE[Ri]中,则令AVALUE[M]={M,Ri},否则令AVALUE[M]={M} 3)删除RVALUE[Ri]中的M (4)给出R,返回。 中间代码 目标代码 RVALUE AVALUE T: =A-B LDR0,A R0含有T T在R0中 SUBR0,B U: =A-C LDR1,A R0含有T T在R0中 SUBR1,C R1含有U U在R1中 V: =T+U ADDR0,R1 R0含有V V在R0中 R1含有U U在R0中 D: =V+U ADDR0,R1 R0含有D D在R0中 图1.1设计流程图 程序代码: #include #include #include #include #include usingnamespacestd; /*************************************** *数据结构* *逆波兰式→目标代码* ***************************************/ /********************************************* *目标代码指令: LD,ST,ADD,SUB,MUL,DIV* *相应的数值: 1,2,3,4,5,6* *数据段开始: 设置为a-z;单个寄存器* *acc为寄存器标志: 为0表示为空,非0,被占用* *********************************************/ chartemp=’a’-1;/*临时变量a-z*/ stack ints;/*栈指针*/ typedefstruct { intop;/*操作符对应的数值*/ charrt;/*单个寄存器*/ charnum;/*操作数*/ }ObjType; ObjTypeOB[40];/*目标代码区*/ into_pt=0;/*区指针*/ intacc;/*寄存器标志*/ charblexp[40];/*逆波兰式区*/ /************************************* *代码区* *************************************/ /************************************* *函数声明* *************************************/ intisop(char);/*判断操作符是否是+-/**/ voidbuild(char);/*根据操作符生成目标代码函数*/ voidB_O();/*生成算法*/ char*OpString(int);/*操作符转化成字符显示*/ voiddisplay();/*显示目标代码*/ /************************************* *判断当前操作符是否是运算符* *如果是返回相应的正数(3-6)* *否则返回零* *************************************/ intisop(charch) { if(ch==’+’) return3; elseif(ch==’-‘) return4; elseif(ch==’*’) return5; elseif(ch==’/’) return6; else return0; } /********************************************* *目标代码生成表生成目标代码* *********************************************/ /***************************目标代码生成表 *操作符WSEM[s-1]即x1SEM[s]即x2accOBJ* *+-/*X1X20LDR,X1;WR,X2;* *+-/*X1X2K! =0T=NEWT;STR,T;LDR,X1;WR,X2;* *+-/*RXs-1WR,X;* *+*XRsWR,X;* */-XRsT=NEWT;STR,T;LDR,X;WR,T;* *******************************************************************/ voidbuild(charch) { charx1,x2;/*从语义栈中弹出俩个操作数,用于判断与运算*/ x2=SEM.top();/*SEM.top记得后面要加(),否则没有值! ! ! */ cout< SEM.pop(); x1=SEM.top(); cout< SEM.pop(); if(acc==0)/*如果寄存器没被占用,直接生成运算指令*/ { OB[o_pt].op=1;/*装载SEM[S-1]即x1到寄存器R*/ OB[o_pt].rt=’R’; OB[o_pt].num=x1; o_pt++; OB[o_pt].op=isop(ch);/*生成对应的运算指令*/ OB[o_pt].rt=’R’; OB[o_pt].num=x2; o_pt++; } elseif(x1! =’R’&&x2! =’R’&&acc! =0) /*x1和x2都不是寄存器的值,且寄存器被占用*/ { temp++;/*申请一个临时变量,在执行代码生成过程中,由操作系统生成, 这个是模拟*/ OB[o_pt].op=2;/*将寄存器的值移出到临时变量*/ OB[o_pt].rt=’R’; OB[o_pt].num=temp; SEM.pop();/*将临时变量压入语义栈*/ SEM.push(temp); o_pt++; OB[o_pt].op=1;/*装载操作数*/ OB[o_pt].rt=’R’; OB[o_pt].num=x1; o_pt++; OB[o_pt].op=isop(ch);/*生成运算指令*/ OB[o_pt].rt=’R’; OB[o_pt].num=x2; o_pt++; } elseif(x1==’R’&&x2! =’R’&&acc==(s-1))/*SEM[s-1]即x1为寄存器的值而x2是操作数且acc为s-1,说明寄存器现在的值为x1*/ { OB[o_pt].op=isop(ch);/*直接生成运算指令,因为此时的寄存器中已经存在一个操作数*/ OB[o_pt].rt=’R’; OB[o_pt].num=x2; o_pt++; } elseif(x1! =’R’&&x2==’R’&&acc==s&&(isop(ch)==3||isop(ch)==5)) /*寄存器的值在SEM[s]即x2,如果操作符为+**/ { OB[o_pt].op=isop(ch);/*直接生成运算指令*/ OB[o_pt].rt=’R’; OB[o_pt].num=x1; o_pt++; } elseif(x1! =’R’&&x2==’R’&&acc==s&&(isop(ch)==4||isop(ch)==6)) /*如果是-/,则需要调换一下位置*/ { temp++;/*生成临时变量,用于存储下寄存器值*/ OB[o_pt].op=2; OB[o_pt].rt=’R’;/*不需要压栈,因为马上就要用到*/ OB[o_pt].num=temp; o_pt++; OB[o_pt].op=1;/*装载x1如寄存器*/ OB[o_pt].rt=’R’; OB[o_pt].num=x1; o_pt++; OB[o_pt].op=isop(ch);/*利用临时变量生成运算指令*/ OB[o_pt].rt=’R’; OB[o_pt].num=temp; o_pt++; } else/*出错处理*/ { cout<<”不符合目标代码生成条件,出错! ”< exit(0); } SEM.push(‘R’);/*将寄存器’R’压栈,用于下次判断,而不是寄存器的值*/ s--; return; } /****************************** *生成算法* ******************************/ voidB_O() { inti=0;/*置初始值s=0,acc=0,i=0*/ charch;/*当前处理字符*/ s=0;/*s为栈顶指示*/ acc=0; while(blexp[i]! =’\0’)/*逆波兰式区还没处理完*/ { ch=blexp[i++];/*取当前处理字符*/ if(isalnum(ch))/*是操作数,入栈*/ { SEM.push(ch); s++; } elseif(isop(ch))/*是操作符,生成指令*/ { build(ch); acc=s;/*acc标志到栈顶,因为R入栈了,指示R的位置用,是个技巧*/ } else/*字符不符合要求,出错处理*/ { cout<<”逆波兰式内字符有错! ”< exit(0); } } } /***************************************** ●将操作指令的数值转换成相应的字符串* *****************************************/ char*OpString(inti) { switch(i) { case1: return“LD”; case2: return“ST”; case3: return“ADD”; case4: return“SUB”; case5: return“MUL”; case6: return“DIV”; default: cout<<”操作符有错! ”< exit(0); } } /******************************* *显示目标代码* *******************************/ voiddisplay() { inti; cout<<”==============目标代码==========”< for(i=0;i { cout< } } intmain() { cout<<”逆波兰式生成目标代码”< cout<<”请输入逆波兰式: ”< gets(blexp); B_O(); display(); return1; } 四、界面设计 程序包含输入提示功能和输出提示功能。 五、运行测试与分析 (1)运行程序,显示提示,如图1.2所示。 图1.2启动界面 (2)数据结果输出。 如图1.3所示。 图1.3数据结果输出界面 六、实验收获与思考 在设计的时候,我在网络中搜索了一些有用的资源。 寄存器描述数组RVALUE,用来动态记录各寄存器的使用信息,RVALUE[R]={A,B},同时,变量地址描述数组AVALUE,动态记录各变量现行值的存放位置,AVALUE[A]={R1,R2,A}。 从而,我总结出了一个代码生成算法。 再结合课上所学与之前实验课程编译的程序完成了目标代码生成实验。 教师评分: 教师签字:
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 目标 代码 生成器