编译原理PL0课设报告.docx

上传人:b****6 文档编号:15432554 上传时间:2023-07-04 格式:DOCX 页数:46 大小:675.14KB
下载 相关 举报
编译原理PL0课设报告.docx_第1页
第1页 / 共46页
编译原理PL0课设报告.docx_第2页
第2页 / 共46页
编译原理PL0课设报告.docx_第3页
第3页 / 共46页
编译原理PL0课设报告.docx_第4页
第4页 / 共46页
编译原理PL0课设报告.docx_第5页
第5页 / 共46页
编译原理PL0课设报告.docx_第6页
第6页 / 共46页
编译原理PL0课设报告.docx_第7页
第7页 / 共46页
编译原理PL0课设报告.docx_第8页
第8页 / 共46页
编译原理PL0课设报告.docx_第9页
第9页 / 共46页
编译原理PL0课设报告.docx_第10页
第10页 / 共46页
编译原理PL0课设报告.docx_第11页
第11页 / 共46页
编译原理PL0课设报告.docx_第12页
第12页 / 共46页
编译原理PL0课设报告.docx_第13页
第13页 / 共46页
编译原理PL0课设报告.docx_第14页
第14页 / 共46页
编译原理PL0课设报告.docx_第15页
第15页 / 共46页
编译原理PL0课设报告.docx_第16页
第16页 / 共46页
编译原理PL0课设报告.docx_第17页
第17页 / 共46页
编译原理PL0课设报告.docx_第18页
第18页 / 共46页
编译原理PL0课设报告.docx_第19页
第19页 / 共46页
编译原理PL0课设报告.docx_第20页
第20页 / 共46页
亲,该文档总共46页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

编译原理PL0课设报告.docx

《编译原理PL0课设报告.docx》由会员分享,可在线阅读,更多相关《编译原理PL0课设报告.docx(46页珍藏版)》请在冰点文库上搜索。

编译原理PL0课设报告.docx

编译原理PL0课设报告

 

课程设计

 

班级:

21301

学号:

1361080108

姓名:

马瑞泽

 

XX

一.课程设计目的

在分析理解一个教学型编译程序(如PL/0)的基础上,对其词法分析程序、语法分析程序和语义处理程序进行部分修改扩充。

达到进一步了解程序编译过程的基本原理和基本实现方法的目的。

二.课程设计要求

1.基本内容

(1)扩充赋值运算:

+=和-=

(2)扩充语句(Pascal的FOR语句):

①FOR<变量>:

=<表达式>TO<表达式>DO<语句>

②FOR<变量>:

=<表达式>DOWNTO<表达式>DO<语句>

其中,语句①的循环变量的步长为2,

语句②的循环变量的步长为-2。

2.选做内容

(1)增加运算:

++和--。

(2)增加类型:

①字符类型;②实数类型。

(3)扩充函数:

①有返回值和返回语句;②有参数函数。

(4)增加一维数组类型(可增加指令)。

(5)其他典型语言设施。

3.本人在课程设计中已实现的功能

(1)增加单词:

保留字ELSE,FOR,TO,DOWNTO,REPEAT,UNTIL,RETURN

运算符+=,-=,++,--

(2)修改单词:

不等号#改为<>

(3)增加条件语句的ELSE子句

(4)扩充赋值运算:

+=和-=

(5)扩充语句

①FOR<变量>:

=<表达式>TO<表达式>DO<语句>

②FOR<变量>:

=<表达式>DOWNTO<表达式>DO<语句>

(6)增加运算:

++和--(包括前后++、--运算)

(7)增加一维数组类型

(8)其他典型语言设施:

REPEAT语句UNTIL语句

三.课程设计环境与工具

(1)计算机及操作系统:

PC机,Win7

(2)实现工具:

VC++6.0,C语言

(3)教学型编译程序:

PL/0

四.结构设计说明

1)PL/0编译程序的结构图

2)PL/0编译程序的过程或函数的功能表

过程或函数名

简要功能说明

pl0

主程序

error

出错处理,打印出错位置和错误编码

getsym

词法分析,读取一个单词

getch

漏掉空格,读取一个字符

gen

生成目标代码,并送入目标程序区

test

测试当前单词符号是否合法

block

分程序分析处理过程

enter

登录名字表

position(函数)

查找标识符在名字表中的位置

constdeclaration

常量定义处理

vardeclaration

变量说明处理

listode

列出目标代码清单

statement

语句处理

expression

表达式处理

term

项处理

factor

因子处理

condition

条件处理

interpret

对目标代码的解释执行程序

base(函数)

通过静态链求出数据区的基地址

3)PL/0编译程序的总体流程图

N

N

Y

Y

4)词法分析

词法分析是编译的第一个阶段,它的主要任务是从左向右逐个字符地对源程序进行扫描,产生一个个单词序列用于语法分析。

PL/0词法分析程序GETSYM的功能是为语法分析提供单词用的,是语法分析的基础,把输入的字符串形式的源程序分割成一个个单词符号。

经过词法分析程序分析出来的单词,对语言固有的单词只给出类别存放在全程变量SYM中,而对用户定义的单词(标识符或常数)既给出类别又给值,其类别放在SYM中,值放在全程变量ID或全程变量NUM中,全部单词种类由编译程序定义的纯量类型SYMBOL给出,称为语法词汇表。

词法分析器的分析过程:

调用GETSYM时,它通过GETCH过程从源程序中获得一个字符。

如果这个字符是字母,则继续获取字符或数字,最终可以拼成一个单词,查保留字表,如果查到为保留字,则把SYM变量赋成相应的保留字类型值;如果没有查到,则这个单词应是一个用户自定义的标识符(可能是变量名、常量名或是过程的名字),把SYM置为IDENT,把这个单词存入ID变量。

查保留字表时使用了二分法查找以提高效率。

如果Getch获得的字符是数字,则继续用Getch获取数字,并把它们拼成一个整数或实数,然后把SYM置为INTEGER,并把拼成的数值放入NUM变量。

如果识别出其它合法的符号(比如:

赋值号、大于号、小于等于号等),则把SYM则成相应的类型。

如果遇到不合法的字符,把SYM置成NUL。

词法分析程序GETSYM将完成下列任务:

(1)滤空格

(2)识别保留字(3)识别标识符

(4)拼数(5)拼复合词(6)输出源程序

5)

语法分析

PL/0编译程序的语法分析采用了自顶向下的递归的子程序法。

语法分析同时也根据程序的语义生成相应三元代码,并提供了出错处理的机制。

语法分析主要由分程序分析过程(BLOCK)、常量定义分析过程(ConstDeclaration)、变量定义分析过程(Vardeclaration)、语句分析过程(Statement)、表达式处理过程(Expression)、项处理过程(Term)、因子处理过程(Factor)和条件处理过程(Condition)构成。

这些过程在结构上构成一个嵌套的层次结构。

除此之外,还有出错报告过程(Error)、代码生成过程(Gen)、测试单词合法性及出错恢复过程(Test)、登录名字表过程(Enter)、查询名字表函数(Position)以及列出类PCODE代码过程(Listcode)作过语法分析的辅助过程。

由PL/0的语法图可知:

一个完整的PL/0程序是由分程序和句号构成的。

因此,本编译程序在运行的时候,通过主程序中调用分程序处理过程block来分析分程序部分(分程序分析过程中还可能会递归调用block过程),然后,判断最后读入的符号是否为句号。

如果是句号且分程序分析中未出错,则是一个合法的PL/0程序,可以运行生成的代码,否则就说明源PL/0程序是不合法的,输出出错提示即可。

6)语义分析

PL/0的语义分析主要进行以下检查:

(1)是否存在标识符先引用未声明的情况;

(2)是否存在己声明的标识符的错误引用;

(3)是否存在一般标识符的多重声明。

7)中间代码生成

目标代码类pcode是一种假想栈式计算机的汇编语言。

自己添加覆盖了

OPR014栈顶值输出至屏幕(字符型)

OPR015栈顶值输出至屏幕(整数型)

OPR016栈顶值输出至屏幕(实数型)

OPR017屏幕输出换行

OPR018从命令行读入一个字符输入置于栈顶

OPR019从命令行读入一个整数输入置于栈顶

OPR020从命令行读入一个实数输入置于栈顶

8)语法错误处理

PL/0编译程序对语法错误的处理采用两种办法:

(1)对于一些易于校正的错误,如丢了逗号、分号等,指出出错的位置,加以校正,继续进行分析。

(2)对于难于校正的错误,给出错误的位置与性质,跳过后面一些单词,直到下一个可以进行正常语法分析的语法单位。

错误类型如下

0过程开始部分说明不正确

1常数说明中"="写成":

="

2常数说明中"="后应为整数或实数或字符

3常数说明中的标识符后应是"="

4const,var,procedure后应为标识符

5漏掉了","或";"

6过程说明后的符号不正确(应该是语句开始符,或过程定义符)

7应是语句开始符

8程序体内语句部分的后跟符不正确

9程序结尾丢了句号"."

10语句间漏了";"

11标识符未说明

12赋值语句中,赋值号左部标识符属性应是变量

13变量后不能是此符号

14call后应为标识符

15call后标识符属性应为过程

16条件语句中丢了"then"

17丢了"end"或";"

18while型循环语句丢了"do"

19语句后的符号不正确

20应为关系运算符

21表达式内标识符属性不能是过程

22表达式中漏掉右括号"("

23因子后的非法符号

24表达式的开始符不能是此符号

31数越界

补充说明了:

32read或write语句括号中的标识符不是变量

33read或write语句缺少右括号")"

34read或write语句缺少左括号"("

35read或write括号里应为变量

自己增加了:

45++或--后面应为变量

46repeat缺少until

47for语句错误

48for语句缺少do

49类型值不匹配

50类型无法转换

51只有整数能++或--

52类型不正确

五.设计过程

(一)实验内容

1.增加单词:

保留字ELSE,FOR,TO,DOWNTO,REPEAT,UNTIL,RETURN

运算符+=(PLUSBK),-=(MINUSBK),++(INC),--(DEC)

首先要扩展SYMBOL,在此基础上再进行其它细节的修改。

要添加的SYMBOL为:

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,TOSYM,DOWNTOSYM,REPEATSYM,UNTILSYM,RETURNSYM,PLUSBK,MINUSBK,INC,DEC

}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","ELSE","FOR",

"TO","DOWNTO","REPEAT","UNTIL","RETURN","PLUSBK","MINUSBK","INC”"DEC"};

其中黑斜体为新加入的SYMBOL。

再将"ELSE","FOR","TO","DOWNTO",,"REPEAT","UNTIL","RETURN","PLUSBK","MINUSBK","INC",

"DEC"关键字加到KWORD和将相应的SYM加到WSYM,按字母顺序排列。

以及修改NEQ后如下

void__fastcallTForm1:

:

ButtonRunClick(TObject*Sender){

for(CH='';CH<='^';CH++)SSYM[CH]=NUL;

strcpy(KWORD[1],"BEGIN");strcpy(KWORD[2],"CALL");

strcpy(KWORD[3],"CONST");strcpy(KWORD[4],"DEC");

strcpy(KWORD[5],"DO");strcpy(KWORD[6],"DOWHILE");

strcpy(KWORD[7],"DOWNTO");strcpy(KWORD[8],"ELSE");

strcpy(KWORD[9],"END");strcpy(KWORD[10],"FOR");

strcpy(KWORD[11],"IF");strcpy(KWORD[12],"INC");

strcpy(KWORD[13],"MINUSBK");strcpy(KWORD[14],"ODD");

strcpy(KWORD[15],"PLUSBK");strcpy(KWORD[16],"PROCEDURE");

strcpy(KWORD[17],"PROGRAM");strcpy(KWORD[18],"READ");

strcpy(KWORD[19],"REPEAT");strcpy(KWORD[20],"RETURN");

strcpy(KWORD[21],"THEN");strcpy(KWORD[22],"TO");

strcpy(KWORD[23],"VAR");strcpy(KWORD[24],"UNTIL");

strcpy(KWORD[25],"WHILE");strcpy(KWORD[26],"WRITE");

WSYM[1]=BEGINSYM;WSYM[2]=CALLSYM;

WSYM[3]=CONSTSYM;WSYM[4]=DEC;

WSYM[5]=DOSYM;WSYM[6]=DOWHILESYM;

WSYM[7]=DOWNTOSYMs;WSYM[8]=ELSESYM;

WSYM[9]=ENDSYM;WSYM[10]=FORSYM;

WSYM[11]=IFSYM;WSYM[12]=INCSYM;

WSYM[13]=MINUSBK;WSYM[14]=ODDSYM;

WSYM[15]=PLUSBK;WSYM[16]=PROCSYM;

WSYM[17]=PROGSYM;WSYM[18]=READSYM;

WSYM[19]=REPEATSYM;WSYM[20]=RETURNSYM;

WSYM[21]=THENSYM;WSYM[22]=TOSYM;

WSYM[23]=VARSYM;WSYM[24]=UNTILSYM;

WSYM[25]=WHILESYM;WSYM[26]=WRITESYM;

SSYM['+']=PLUS;SSYM['-']=MINUS;

SSYM['*']=TIMES;SSYM['/']=SLASH;

SSYM['(']=LPAREN;SSYM[')']=RPAREN;

SSYM['=']=EQL;SSYM[',']=COMMA;

SSYM['.']=PERIOD;SSYM[';']=SEMICOLON;

因为关键字增加到了26个,所以令constNORW=26;

SYMBOL由原来的33个值扩展为目前的44个值,SYMOUT也由原来的33个元素扩展为目前的44个元素.我用个SYMMAX来记录SYMBOL值的个数,所以,除了Error函数中可能出现的作为参数的“33”不被替换为“44”外,其余的“33”均用“SYMMAX”来替换。

SYMBOL扩展完毕。

2.修改单词:

不等号#改为<>

只要修改GetSym()函数。

当编译器检测到当前字符为“〈”时,接着检测下一个字符,如果是“〉”,则使SYM=NEQ。

代码修改如下:

if(CH=='<')

{

GetCh();

if(CH=='='){SYM=LEQ;GetCh();}

else

if(CH=='>'){SYM=NEQ;GetCh();}//增加<>为不等于号;

elseSYM=LSS;

}

3.增加条件语句的ELSE子句

该条件语法描述图如下:

语句

只要在STATEMENT修改如下代码:

caseIFSYM:

GetSym();

CONDITION(SymSetUnion(SymSetNew(THENSYM,DOSYM),FSYS),LEV,TX);

if(SYM==THENSYM)GetSym();

elseError(16);

CX1=CX;GEN(JPC,0,0);

STATEMENT(SymSetUnion(SymSetNew(ELSESYM),FSYS),LEV,TX);

if(SYM!

=ELSESYM)CODE[CX1].A=CX;

//如果程序中没有else语句,执行JPC时跳到此地址

else{//添加ELSE语句

GetSym();

CX2=CX;

GEN(JMP,0,0);//跳过else语句

CODE[CX1].A=CX;

//如果程序中有else语句,执行JPC时跳到此地址

STATEMENT(FSYS,LEV,TX);

CODE[CX2].A=CX;//执行完then语句后跳出

}

break;

ELSE子句扩充完毕。

(二)课程设计内容

1.增加运算符+=,-=,++,--

a)词法分析

1)在GetSym()中完成INC(++)、PLUSBK(+=)的词法分析,代码修改如下:

elseif(CH=='+'){

GetCh();

if(CH=='='){//增加+=

SYM=PLUSBK;

GetCh();

}

elseif(CH=='+'){//增加++

SYM=INC;

GetCh();

}

elseSYM=PLUS;

}

2)在GetSym()中完成DEC(--)、MINUSBK(-=)的词法分析,代码修改如下:

elseif(CH=='-'){

GetCh();

if(CH=='='){//增加-=

SYM=MINUSBK;

GetCh();

}

elseif(CH=='-'){//增加--

SYM=DEC;

GetCh();

}

elseSYM=MINUS;

}

b)扩充后++和后--操作

存在INC和DEC操作的语法图有如下两个:

根据以上语法图,我们只要对语句处理程序和因子处理程序进行修改添加,即可实现增加后INC和后DEC操作,首先对语句处理程序STATEMENT进行如下修改:

CaseIDENT:

i=POSITION(ID,TX);

if(i==0)Error(11);

else

if(TABLE[i].KIND!

=VARIABLE){/*ASSIGNMENTTONON-VARIABLE*/

Error(12);i=0;

}

GetSym();

if(SYM==BECOMES)

{

GetSym();

EXPRESSION(FSYS,LEV,TX);

if(i!

=0)GEN(STO,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);

}

elseif(SYM==INC)//语句中的++运算

{if(i!

=0)GEN(LOD,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);

GEN(LIT,0,1);

GEN(OPR,0,2);

if(i!

=0)GEN(STO,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);

GetSym();

}

elseif(SYM==DEC)//语句中的--运算

{if(i!

=0)GEN(LOD,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);

GEN(LIT,0,1);

GEN(OPR,0,3);

if(i!

=0)GEN(STO,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);

GetSym();

}

在接受到SYM=IDENT后,如果SYM为INC,则主要执行这四条指令:

GEN(LOD,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR)将IDENT的值放到栈顶,

GEN(LIT,0,1);将常数1放到栈顶,

GEN(OPR,0,2)次栈顶加栈顶,

GEN(STO,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);将栈顶内容保存到IDENT中。

这样就完成了语句中的++运算。

如果SYM为DEC,则主要执行这四条指令:

GEN(LOD,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR)将IDENT的值放到栈顶,

GEN(LIT,0,1);将常数1放到栈顶,

GEN(OPR,0,3)次栈顶减栈顶,

GEN(STO,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);将栈顶内容保存到IDENT中。

这样就完成了语句中的--运算。

其次,再对因子处理程序FACTOR修改如下:

if(SYM==IDENT){

i=POSITION(ID,TX);

if(i==0)Error(11);

else

switch(TABLE[i].KIND){

caseCONSTANT:

GEN(LIT,0,TABLE[i].VAL);GetSym();break;

caseVARIABLE:

GEN(LOD,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);

GetSym();

if(SYM==INC||SYM==DEC)//因子中的++和--运算

{

GEN(LIT,0,1);

if(SYM==INC)GEN(OPR,0,2);//如果为INC,则加1

elseGEN(OPR,0,3);//否则减一

GEN(STO,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);//将栈顶送入变量单元

GEN(LOD,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);//将变量送入栈顶

GetSym();

}

break;

casePROCEDUR:

Error(21);break;

}

}

这样,对后INC和后DEC操作就扩充完成

c)扩充前++和前--操作

存在前INC和前DEC操作的语法图有如下两个:

首先将

STATBEGSYS[INC]=1;

STATBEGSYS[DEC]=1;

FACBEGSYS[INC]=1;

FACBEGSYS[DEC]=1;

其次根据以上语法图,我们只要对语句处理程序和因子处理程序进行修改添加,即可实现增加前INC和前DEC操作,首先对语句处理程序STATEMENT进行如下修改:

caseINC:

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 求职职场 > 简历

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2