课程设计课程名称___编译原理__________题目名称___PL/0编译器的扩充__学生学院___计算机学院_________专业班级_计算机科学与技术13(9)学号学生姓名指导教师___林志毅________________2016年1月2日一、已完成的内容:(1)扩充赋值运算:*=和/=(2)扩充语句(Pascal的FOR语句)FOR<变量>:=<表达式>STEP<表达式>UNTIL<表达式>Do<语句> (3)增加类型:①字符类型;②实数类型。
VARIABLE*/GetSym();if(SYM==BECOMES||SYM==TIMESBECOMES||SYM==SLASHBECOMES||SYM==PLUSBECOMES||SYM==MINUSBECOMES){RELOP=SYM;if(SYM!=BECOMES){TABLE[i].;}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].,TABLE[i].;}(1)运行测试(测试的PL0源码扩充单词的测试并贴运行结果截图)PL0源码:PROGRAMEX01;VARA,B,C,D;BEGINA:=16;A/=2;(2)WRITE(A);运行结果:(3)出现的问题及解决开始时在实现/=和*=操作时,*=的实现很顺利,而/=却一直没有得到理想的结果,通过与同学的讨论得知代码中除号指令的解析中,其实为除余操作,于是将%改为/,但是结果还是错误,经过调试发现是两个相除的数在栈中的位置相反了,正确的状态应该是除数位于次栈顶,而被除数位于栈顶。
解决:在调用EXPRESSION函数解析/=右边表达式前,先将其左边变量的值放入栈中。
1.扩充语句(Pascal的FOR语句)FOR<变量>:=<表达式>STEP<表达式>UNTIL<表达式>Do<语句>(1)语法图(2)修改GetSym()方法(写出修改的代码)此处无修改,FOR、STEP、UNTIL及DO等关键字已放置关键字数组中,通过该数组便可识别。
(3)修改STATEMENT()方法(写出修改的代码)caseFORSYM:GetSym();(4)STATEMENT(SymSetUnion(SymSetNew(STEPSYM),FSYS),LEV,TX);=CX;=CX;运行结果:(5)出现的问题及解决实现FOR循环的前提是理解表达式处理函数及语句处理函数,关键是处理好跳转关系,例如第一次进入FOR循环时,生成FOR后面的表达式后应该有一个直接跳转跳过STEP语句进入UNTIL的条件判断;而调用CONDITION处理UNTIL后的条件语句后,便有一个条件跳转跳到STEP后的表达式代码位置。
由于有了之前IF...ELSE...的参考及大致理解相关函数,因此实现时没出现太大问题。
2.增加类型:①字符类型;②实数类型。
(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=='.'){IND==CHARTYPE||TABLE[i].KIND==VARIABLE||TABLE[i].KIND==F LOATTYPE){/*ASSIGNMENTTONON-VARIABLE*/if(SYM==BECOMES||SYM==TIMESBECOMES||SYM==SLASHBECOMES ||SYM==PLUSBECOMES||SYM==MINUSBECOMES){RELOP=SYM;if(SYM!=BECOMES){TABLE[i].;}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].,TABLE[i].;}else{Error(12);i=0;}break;caseWRITESYM: IND){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*/(2)修改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].,TABLE[i].;break;casePROCEDUR:Error(21);break;caseFLOATTYPE:GEN(LOD,LEV-TABLE[i].,TABLE[i].;break;caseCHARTYPE:GEN(LOD,LEV-TABLE[i].,TABLE[i].;break;}GetSym();}elseif(SYM==NUMBER){if(NUM>AMAX){Error(31);NUM=0;}GEN(LIT,0,NUM);GetSym();LEV;TABLE[TX].=DX;DX++;break;caseFLOATTYPE:TABLE[TX].=LEV;TABLE[TX].=DX;DX++;break;(3)在Interpret指令OPR中增加字符输出和实数输出case17:Form1->printcs(S[T]);fprintf(FOUT,"%c\n",S[T]);(4)T--;运行结果:(5)出现的问题及解决字符型的实现主要问题是在赋值、字符表达式的处理及输出三个方面。
赋值刚开始没有思路,之后借鉴VAR型的赋值,才清楚需要使用到栈这个媒介进入赋值:先把字符值放入栈中,在将栈顶值传给字符型变量。
而字符表达式的处理在Factor里进行识别处理。
关于输出则需要在WRITESYM的识别处理中进行类型判断采取不同输出方式,并需新建一条指令专门用于字符输出实数型的实现主要问题为:1、数据获取:小数点后的值的获取需要用到循环帮助实现;2、变量更改:在没有引入实数型前,用来模拟栈的数组类型为int型,而引入后,则需要将其更改为实数型,在程序中与栈值有关的那些变量类型也同样改为实数型。
(1)增加注释;多行注释由/*和*/包含,单行注释为运行结果(2)出现问题及解决刚开始就认为注释功能的实现比较容易,但是在实现过程还是出现不少问题。
我的思路是在getSym方法中使用循环滤去注释的内容,过程不断调用getCh读取下一个字符。
在循环处理注释结束后需要调用自身GetSym,因为上次调用的GetSym方法都用于处理注释了。
然而/**/这种情况却一直有报19号错误,经过查找发现该情况的循环执行完后,当前CH为符号’/’,而不是’/’后的字符,因此需要在调用GetSym前先调用getCh以便获取下一个新字符用于GetSym中的switch判断。
//不存在此情况,其循环结束CH为注释结束的下一字符。
二、心得经过了一周多的奋战,此次课程设计的实现过程让我收获颇多,同时也让我意识到自己在编码过程中的不足。
在没做课程设计之前,我对代码编译的实现过程和对PL0代码的体系结构都很陌生,而当一步一步从实现/=等、for循环、注释及增加类型等功能后,我对代码编译过程有了一个整体而深入的认识。
在实现的过程中,虽然出现很多问题,但是通过自己的思考和请教同学都能得到解决。
在实现的过程中,我发现自己在考虑功能的实现方面不够全面仔细,例如字符型的增加,我只考虑到了字母这一种字符型,而没有考虑其他符号也为字符型,因此先前字符的识别我是通过判别当前SYM是否为ident型且其字符串长度是否为1这两个条件进行识别出来的。
当完成过后才发现该方法存在缺陷,才在GetSym里面另起分支进行识别处理。
这也提醒我以后考虑问题应当尽量周全。
源码下载地址:。