您好,欢迎访问三七文档
当前位置:首页 > 临时分类 > 2015广工编译原理课程设计报告
课程设计课程名称___编译原理__________题目名称___PL/0编译器的扩充__学生学院___计算机学院_________专业班级_计算机科学与技术13(9)学号学生姓名指导教师___林志毅________________2016年1月2日一、已完成的内容:(1)扩充赋值运算:*=和/=(2)扩充语句(Pascal的FOR语句)FOR变量:=表达式STEP表达式UNTIL表达式Do语句(3)增加类型:①字符类型;②实数类型。(4)增加注释;多行注释由/*和*/包含,单行注释为//二、实验环境与工具(1)计算机及操作系统:PC机,Windows7(2)程序设计语言:C++(3)使用软件BorlandC++Builder6.0(4)教学型编译程序:PL/0三、具体实现:1.扩充赋值运算:*=和/=(1)语法树(2)修改GetSym()方法(写出修改的代码)elseif(CH=='*'){GetCh();if(CH=='='){SYM=TIMESBECOMES;GetCh();}elseSYM=TIMES;}elseif(CH=='/'){GetCh();if(CH=='='){SYM=SLASHBECOMES;GetCh();}(3)修改STATEMENT()方法(写出修改的代码)caseIDENT:i=POSITION(ID,TX);if(i==0)Error(11);变量*=表达式elseif(TABLE[i].KIND==VARIABLE||TABLE[i].KIND==FLOATTYPE){/*ASSIGNMENTTONON-VARIABLE*/GetSym();if(SYM==BECOMES||SYM==TIMESBECOMES||SYM==SLASHBECOMES||SYM==PLUSBECOMES||SYM==MINUSBECOMES){RELOP=SYM;if(SYM!=BECOMES){//若为除等于(或其他类似符号)则先把符号左边的变量值放入栈中GEN(LOD,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);}GetSym();}elseError(13);EXPRESSION(FSYS,LEV,TX);if(RELOP==TIMESBECOMES){GEN(OPR,0,4);}elseif(RELOP==SLASHBECOMES){GEN(OPR,0,5);}elseif(RELOP==PLUSBECOMES){GEN(OPR,0,2);}elseif(RELOP==MINUSBECOMES){GEN(OPR,0,3);}GEN(STO,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);}(4)运行测试(测试的PL0源码扩充单词的测试并贴运行结果截图)PL0源码:PROGRAMEX01;VARA,B,C,D;BEGINA:=16;A/=2;WRITE(A);//结果为8B:=4;B*=2;WRITE(B);//结果为8C:=6;C+=2;WRITE(C);//结果为8D:=10;D-=2;WRITE(D);//结果为8END.(5)运行结果:(6)出现的问题及解决开始时在实现/=和*=操作时,*=的实现很顺利,而/=却一直没有得到理想的结果,通过与同学的讨论得知代码中除号指令的解析中,其实为除余操作,于是将%改为/,但是结果还是错误,经过调试发现是两个相除的数在栈中的位置相反了,正确的状态应该是除数位于次栈顶,而被除数位于栈顶。解决:在调用EXPRESSION函数解析/=右边表达式前,先将其左边变量的值放入栈中。2.扩充语句(Pascal的FOR语句)FOR变量:=表达式STEP表达式UNTIL表达式Do语句(1)语法图(2)修改GetSym()方法(写出修改的代码)此处无修改,FOR、STEP、UNTIL及DO等关键字已放置关键字数组中,通过该数组便可识别。(3)修改STATEMENT()方法(写出修改的代码)caseFORSYM:GetSym();STATEMENT(SymSetUnion(SymSetNew(STEPSYM),FSYS),LEV,TX);//处理for后面的赋值语句CX3=CX;GEN(JMP,0,0);//用于第一次执行for语句时跳过step语句CX1=CX;//记录step后语句的代码位置if(SYM==STEPSYM){GetSym();STATEMENT(SymSetUnion(SymSetNew(UNTILSYM),FSYS),LEV,TX);//处理step后面的表达式}elseError(8);if(SYM==UNTILSYM){CODE[CX3].A=CX;//回填第一次进入for循环时的直接跳转地址GetSym();}elseError(8);CONDITION(SymSetAdd(DOSYM,FSYS),LEV,TX);//处理条件语句if(SYM==DOSYM){GetSym();}elseError(8);CX2=CX;GEN(JPC,0,0);//条件跳转,栈顶若为非真,则跳转到参数三位置,该位置待回填STATEMENT(FSYS,LEV,TX);//处理do后面内容GEN(JMP,0,CX1);//执行完for语句内的语句则重新跳回step处CODE[CX2].A=CX;//回填条件跳转break;(4)运行测试PL0源码:PROGRAMEX01;VARA,SUM;BEGINSUM:=0;FORA:=1STEPA+=1UNTILA=100DO//求1~100的和SUM+=A;WRITE(SUM);//结果为5050END.(5)运行结果:(6)出现的问题及解决实现FOR循环的前提是理解表达式处理函数及语句处理函数,关键是处理好跳转关系,例如第一次进入FOR循环时,生成FOR后面的表达式后应该有一个直接跳转跳过STEP语句进入UNTIL的条件判断;而调用CONDITION处理UNTIL后的条件语句后,便有一个条件跳转跳到STEP后的表达式代码位置。由于有了之前IF...ELSE...的参考及大致理解相关函数,因此实现时没出现太大问题。3.增加类型:①字符类型;②实数类型。(1)在GetSym中增加字符型及实数型数据的识别elseif(CH=='\''){GetCh();NUM=CH;GetCh();if(CH=='\''){SYM=CHARACTER;GetCh();}elseError(8);}elseif(CH='0'&&CH='9'){/*NUMBER*/K=0;NUM=0;SYM=NUMBER;do{NUM=10*NUM+(CH-'0');K++;GetCh();}while(CH='0'&&CH='9');if(CH=='.'){//实现小数点后的识别i=0;M=0;GetCh();while(CH='0'&&CH='9'){//以下获取小数点后的值J=0;M=(CH-'0')*0.1;while(Ji){M*=0.1;J++;}NUM=NUM+M;i++;GetCh();}if(iLMAX)Error(30);//LMAX为小数点后数字最大度fprintf(FOUT,%f,NUM);}(2)修改Block中的方法运行测试if(SYM==CHARSYM){GetSym();do{CharDeclaration(LEV,TX,DX);while(SYM==COMMA){GetSym();CharDeclaration(LEV,TX,DX);}if(SYM==SEMICOLON)GetSym();elseError(5);}while(SYM==IDENT);}if(SYM==FLOATSYM){GetSym();do{FloatDeclaration(LEV,TX,DX);while(SYM==COMMA){GetSym();DoubleDeclaration(LEV,TX,DX);}if(SYM==SEMICOLON)GetSym();elseError(5);}while(SYM==IDENT);}(3)修改STATEMENT中的方法caseIDENT:GetSym();i=POSITION(ID,TX);if(i==0)Error(11);elseif(TABLE[i].KIND==CHARTYPE||TABLE[i].KIND==VARIABLE||TABLE[i].KIND==FLOATTYPE){/*ASSIGNMENTTONON-VARIABLE*/if(SYM==BECOMES||SYM==TIMESBECOMES||SYM==SLASHBECOMES||SYM==PLUSBECOMES||SYM==MINUSBECOMES){RELOP=SYM;if(SYM!=BECOMES){//若为除等于(或其他类似)。。则先把符号左边的变量值放入栈中GEN(LOD,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);}GetSym();}elseError(13);EXPRESSION(FSYS,LEV,TX);if(RELOP==TIMESBECOMES){GEN(OPR,0,4);}elseif(RELOP==SLASHBECOMES){GEN(OPR,0,5);}elseif(RELOP==PLUSBECOMES){GEN(OPR,0,2);}elseif(RELOP==MINUSBECOMES){GEN(OPR,0,3);}GEN(STO,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);}else{Error(12);i=0;}break;caseWRITESYM://根据不同类型进行相应输出GetSym();if(SYM==LPAREN){do{GetSym();EXPRESSION(SymSetUnion(SymSetNew(RPAREN,COMMA),FSYS),LEV,TX);i=POSITION(ID,TX);switch(TABLE[i].KIND){caseCHARTYPE:GEN(OPR,0,17);break;caseFLOATTYPE:GEN(OPR,0,18);break;default:{GEN(OPR,0,14);}}}while(SYM==COMMA);if(SYM!=RPAREN)Error(SBNUM);elseGetSym();}GEN(OPR,0,15);break;/*WRITESYM*/(4)修改FACTOR中的方法(包含字符的识别处理)while(SymIn(SYM,FACBEGSYS)){if(SYM==IDENT){i=POSITION(ID,TX);if(i==0)Error(11);elseswitch(TABLE[i].KIND){caseCONSTANT:GEN(LIT,0,TABLE[i].VAL);break;caseVARIABLE:GEN(LOD,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);break;casePROCEDUR:Error(21);break;caseFLOATTYPE:GEN(LOD,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);break;caseCHARTYPE:GEN(LOD,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);break;}GetSym();}elseif(SYM==NUMBER){if(NUMAMAX){Error(31);NUM=0;}GEN(LIT,0,NUM);GetSym();//将表达式中的数字置于栈顶}elseif(SYM==LPAREN){//左括号GetSym();EXPRESSION(SymSetAdd(RPAREN,FSYS)
本文标题:2015广工编译原理课程设计报告
链接地址:https://www.777doc.com/doc-4310822 .html