您好,欢迎访问三七文档
当前位置:首页 > 临时分类 > 广工2014编译原理课程设计报告
课程设计课程名称编译原理题目名称PL/0编译器的扩充学生学院计算机学院专业班级计算机科学与技术12(4)学号3112005901学生姓名柏石先指导教师李杨程序功能完成情况测试用例全面程度学生对所编程序熟悉程度报告格式是否与要求相符报告内容是否准确、全面2014年12月28日一、实验目的与要求基本内容(成绩范围:“中”、“及格”或“不及格”)(1)扩充赋值运算:*=和/=(2)扩充语句(Pascal的FOR语句):FOR变量:=表达式STEP表达式UNTIL表达式Do语句选做内容(成绩评定范围扩大到:“优”和“良”)(1)增加类型:①字符类型;②实数类型。(2)增加注释;注释由/*和*/包含;(3)扩充函数:①有返回值和返回语句;②有参数函数。(4)增加一维数组类型(可增加指令)。(5)其他典型语言设施。二、实验环境与工具1、源语言:PL/0语言,PL/0语言是PASCAL语言的子集,它的编译程序是一个编译解析执行系统,后缀名为.PL0;2、目标语言:生成文件后缀为*.COD的目标代码3、实现平台:BorlandC++Builder64、运行平台:Windows8.1三、设计概述1、结构设计说明(1)PL/0编译系统的结构框架出错处理函数表格管理函数PL/0源程序目标代码生成程序程序目标代码生成程序程序目标代码生成程序程序目标代码生成程序程序目标代码生成程序程序源语言:源语言是基于C语言写的PL/0编译程序——PL0语言(可以看成Pascal语言的子集)目标语言:假想的栈式计算机计算语言,即类PCODE指令代码。指令格式如下:fla其中f代表功能码,l表示层次差,a的含意对不同的指令有所区别。具体的指令功能表:LIT0a将常数值取到栈顶,a为常数值LODla将变量值取到栈顶,a为偏移量,l为层差STOla将栈顶内容送入某变量单元中,a为偏移量,l为层差CALla调用过程,a为过程地址,l为层差INT0a在运行栈中为被调用的过程开辟a个单元的数据区JMP0a无条件跳转至a地址JPC0a条件跳转,当栈顶布尔值非真则跳转至a地址,否则顺序执行OPR00过程调用结束后,返回调用点并退栈OPR01栈顶元素取反OPR02次栈顶与栈顶相加,退两个栈元素,结果值进栈OPR03次栈顶减去栈顶,退两个栈元素,结果值进栈OPR04次栈顶乘以栈顶,退两个栈元素,结果值进栈OPR05次栈顶除以栈顶,退两个栈元素,结果值进栈OPR06栈顶元素的奇偶判断,结果值在栈顶OPR07OPR08次栈顶与栈顶是否相等,退两个栈元素,结果值进栈OPR09次栈顶与栈顶是否不等,退两个栈元素,结果值进栈OPR010次栈顶是否小于栈顶,退两个栈元素,结果值进栈OPR011次栈顶是否大于等于栈顶,退两个栈元素,结果值进栈OPR012次栈顶是否大于栈顶,退两个栈元素,结果值进栈OPR013次栈顶是否小于等于栈顶,退两个栈元素,结果值进栈OPR014栈顶值输出至屏幕OPR015屏幕输出换行OPR016从命令行读入一个输入置于栈顶四、设计分析(一)扩充赋值运算:*=和/=需要增加2个运算符*=和/=,用下面表格定义的SYM代替运算符*=/=SYM表示TIMESBECOMESSLASHBECOMES*=和/=的语法描述图:(二)扩充语句(Pascal的FOR语句)因为在Pascal中的FOR语句描述为:FOR变量:=表达式STEP表达式UNTIL表达式DO语句所以增加FOR,STEP,UNTIL,DOFOR语句语法描述图为:五、程序设计1)增加所需要的保留字和运算符,实现*=和/=,以及FOR语句,应该增加TIMESBECOMES,SLASHBECOMES,FOR,STEP,UNTIL,DO。注:因为要求课设和之前实验的内容合并在一起,所以保留了课程实验已经添加的保留字和运算符,之前的已经添加了的不再赘述。具体实现的语句如下所示:typedefenum{NUL,IDENT,NUMBER,PLUS,MINUS,TIMES,SLASH,ODDSYM,EQL,NEQ,LSS,LEQ,GTR,GEQ,LPAREN,RPAREN,COMMA,SEMICOLON,PERIOD,BECOMES,BEGINSYM,ENDSYM,IFSYM,THENSYM,WHILESYM,WRITESYM,READSYM,DOSYM,CALLSYM,CONSTSYM,VARSYM,PROCSYM,PROGSYM,ELSESYM,FORSYM,STEPSYM,UNTILSYM,RETURNSYM,TIMESBECOMES,SLASHBECOMES,ANDSYM,ORSYM,NOTSYM}SYMBOL;这里需要考虑需要增加保留字的个数,以及如何命名,再将新增的保留字添加对应的保留字的集合中。具体实现的语句如下所示:char*SYMOUT[]={NUL,IDENT,NUMBER,PLUS,MINUS,TIMES,SLASH,ODDSYM,EQL,NEQ,LSS,LEQ,GTR,GEQ,LPAREN,RPAREN,COMMA,SEMICOLON,PERIOD,BECOMES,BEGINSYM,ENDSYM,IFSYM,THENSYM,WHILESYM,WRITESYM,READSYM,DOSYM,CALLSYM,CONSTSYM,VARSYM,PROCSYM,PROGSYM,ELSESYM,FORSYM,STEPSYM,UNTILSYM,RETURNSYM,TIMESBECOMES,SLASHBECOMES,ANDSYM,ORSYM,NOTSYM};2)将新增的保留字按照字母表升序的方式添加,运算符参照已有的运算符来进行添加,注意好符号与SYM的对应。具体实现的语句如下所示:特别注意点:此处一定要考虑到PLO编译器采用了折半查找算法来进行操作,如果新增的保留字没有按照既定的升序规则来插入,会造成在编译过程中,编译器无法识别某些保留字。strcpy(KWORD[1],BEGIN);strcpy(KWORD[2],CALL);strcpy(KWORD[3],CONST);strcpy(KWORD[4],DO);strcpy(KWORD[5],ELSE);strcpy(KWORD[6],END);strcpy(KWORD[7],FOR);strcpy(KWORD[8],IF);strcpy(KWORD[9],ODD);strcpy(KWORD[10],PROCEDURE);strcpy(KWORD[11],PROGRAM);strcpy(KWORD[12],READ);strcpy(KWORD[13],RETURN);strcpy(KWORD[14],STEP);strcpy(KWORD[15],THEN);strcpy(KWORD[16],UNTIL);strcpy(KWORD[17],VAR);strcpy(KWORD[18],WHILE);strcpy(KWORD[19],WRITE);WSYM[1]=BEGINSYM;WSYM[2]=CALLSYM;WSYM[3]=CONSTSYM;WSYM[4]=DOSYM;WSYM[5]=ELSESYM;WSYM[6]=ENDSYM;WSYM[7]=FORSYM;WSYM[8]=IFSYM;WSYM[9]=ODDSYM;WSYM[10]=PROCSYM;WSYM[11]=PROGSYM;WSYM[12]=READSYM;WSYM[13]=RETURNSYM;WSYM[14]=STEPSYM;WSYM[15]=THENSYM;WSYM[16]=UNTILSYM;WSYM[17]=VARSYM;WSYM[18]=WHILESYM;WSYM[19]=WRITESYM;SSYM['+']=PLUS;SSYM['-']=MINUS;SSYM['*']=TIMES;SSYM['/']=SLASH;SSYM['(']=LPAREN;SSYM[')']=RPAREN;SSYM['=']=EQL;SSYM[',']=COMMA;SSYM['.']=PERIOD;SSYM[';']=SEMICOLON;SSYM['&']=ANDSYM;SSYM['|']=ORSYM;SSYM['!']=NOTSYM;3)特别需要注意的两点,这个是很容易被忽略的地方,就是在完成保留字和运算符的增加以后,一定要对PLO编译器对保留字个数已经单词总数定义进行相应的修改。保留字总数比如说在不添加任何保留字的情况下,PL0编译器的原保留字应该是14个,所以在Unit1.CPP中有定义constNORW=14;/*#OFRESERVEDWORDS*/而在实验中因为新增加保留字5个,故此处应改为:constNORW=19;/*#OFRESERVEDWORDS*/单词总数与保留字总数一样,我们增加完保留字和运算符以后,要修改单词总是,比如原单词总数是33,因为原编译器中并未定义一个常量来进行统一管理,所以需要对所有“i33”的地方进行修改。因为实验中新增加单词10个,故应改为“i43”。如下面代码所示举例:SYMSETSymSetUnion(SYMSETS1,SYMSETS2){SYMSETS=(SYMSET)malloc(sizeof(int)*43);for(inti=0;i43;i++)if(S1[i]||S2[i])S[i]=1;elseS[i]=0;returnS;}特别是这个地方也要更改数目为43,不然会发生异常信息。DECLBEGSYS=(int*)malloc(sizeof(int)*43);STATBEGSYS=(int*)malloc(sizeof(int)*43);FACBEGSYS=(int*)malloc(sizeof(int)*43);for(intj=0;j43;j++){DECLBEGSYS[j]=0;STATBEGSYS[j]=0;FACBEGSYS[j]=0;}体会:在这里的细节导致出现了很多意料不到的问题,很多时候调试了很久才发现,有些地方漏改了,其实可以考虑设置一个全局变量,进行统一修改,不过考虑到对编译器增加全局变量不是很好的一种方式,难免会发生出现可能的篡改,而且不够直观,故只是在原来基础上做出修改。4)新增的运算符需要被编译器识别,必须满足编译器做词法分析时,能够正确得到对应的SYM,因此在GetSym()函数中在相应位置增加相应的运算符分析判断,具体实现如下面所示的语句:elseif(CH=='*'){GetCh();if(CH=='='){SYM=TIMESBECOMES;GetCh();}elseSYM=TIMES;}elseif(CH=='/'){GetCh();if(CH=='='){SYM=SLASHBECOMES;GetCh();}elseSYM=SLASH;}体会:这里是双字符判断,需要注意判别的连贯性,处理不同情况下对于的SYM或者报错方式。5)完成*=和/=的语法分析以后,需要考虑其语义的实现,也就是考虑如何实现语句的处理,这里根据前面设计的语法描述图来进行相应的语句分析。依据语法描述图,首选找到STATEMENT函数中IDENT语句体,即caseIDENT:语句中加入对*=和/=的语句描述。注意这里有三种情况,要考虑到相互不能影响。表达式的分析采用EXPRESSION(FSYS,LEV,TX);语句就行。从指令功能表可知:OPR,0,4代表次栈顶乘以栈顶,退两个栈元素,结果值进栈OPR,0,5代表次栈顶除以栈顶,退两个栈元素,结果值进栈一定要注意是次栈顶对栈顶的操作,所以要注意被除数(被乘数)和除数(乘数)的入栈的先后次序,不可颠倒。caseIDENT:i=POSITION(ID,TX);if(i==0)Error(11);elseif(TABLE[i].KIND!=VARIABLE){/*ASSIGNMENTTONON-VARIABLE*/Error(12);i=0;}GetSym();if(SYM==
本文标题:广工2014编译原理课程设计报告
链接地址:https://www.777doc.com/doc-5097631 .html