编译原理实验.docx

上传人:b****8 文档编号:10575291 上传时间:2023-02-21 格式:DOCX 页数:66 大小:209.68KB
下载 相关 举报
编译原理实验.docx_第1页
第1页 / 共66页
编译原理实验.docx_第2页
第2页 / 共66页
编译原理实验.docx_第3页
第3页 / 共66页
编译原理实验.docx_第4页
第4页 / 共66页
编译原理实验.docx_第5页
第5页 / 共66页
点击查看更多>>
下载资源
资源描述

编译原理实验.docx

《编译原理实验.docx》由会员分享,可在线阅读,更多相关《编译原理实验.docx(66页珍藏版)》请在冰豆网上搜索。

编译原理实验.docx

编译原理实验

实验一词法扫描器设计

一实验目的

通过设计调试词法分析程序,实现从源程序中分出各种单词的方法;加深对课堂教学的理解;提高词法分析方法的实践能力。

二实验内容

设计一个简单的类C语言的词法扫描器。

三实验要求

(一)程序设计要求

(1)根据附录给定的文法,从输入的类C语言源程序中,识别出各个具有独立意义的单词,即关键字、标识符、常数、运算符、分隔符五大类;文法见最后附录。

(2)提供源程序输入界面;

(3)词法分析后可查看符号表和TOKEN串表;

(4)保存符号表和TOKEN串表(如:

文本文件);

(5)遇到错误时可显示提示信息,然后跳过错误部分继续进行分析。

(二)实验报告撰写要求

(1)系统功能(包括各个子功能模块的功能说明);

(2)开发平台(操作系统、设计语言);

(3)设计方案;

1)主数据流图;

2)主要子程序的流程框图(若有必要);

3)模块结构图;

4)主要数据结构:

符号表、TOKEN串表等。

(4)具体设计过程(包括主控程序、各个功能模块的具体实现)。

四实验总结

 

附录:

类C语言的词法文法

idLetter

int10Numint10|Num

OP+|-|*|/|>|<|=|(|)|;|‘|==|>=|<=|!

=

Keywordif|then|else|while|do

Lettera|b|c|d|e|f|g|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z

Num0|1|2|3|4|5|6|7|8|9|ε

Letter|Num

 

一.设计内容

1.根据附录给定的文法,从输入的类C语言源程序中,识别出各个具有独立意义的单词,即关键字、标识符、常数、运算符、分隔符五大类;文法见最后附录。

2.源程序保存在文件中。

3.词法分析后可查看符号表和TOKEN串表;

4.保存符号表和TOKEN串表(如:

文本文件);

二.详细设计

1.首先根据题目要求对要进行词法分析的单词符号进行编码。

单词符号

种别编码

单词符号

种别编码

main

1

[

17

int

2

]

18

char

3

{

19

if

4

}

20

else

5

21

for

6

:

22

while

7

23

ID

8

24

NUM

9

25

=

10

>=

26

+

11

<=

27

-

12

==

28

*

13

29

/

14

15

16

2.在本实验中,将需要出来的文法符号分为几类:

(1)关键字:

在本实验中对关键字分别进行存储,在判断是否为标识符前首先对关键字进行识别。

(2)标识符:

标识符处理函数识别标识符。

正则定义为:

(3)运算符:

运算符包括

=+-*/()[]{},;><>=<===!

=等,需单独写函数进行识别。

关系运算符需根据下图进行识别:

(4)数字:

在本例中仅识别整数。

digit=1|2|3|4|5|6|7|8|9

Digit=0|1|2|3|4|5|6|7|8|9

Digit=digitDigit*

3.扫描器

扫描器作为独立的子程序,首先进行扫描剔除无用的换行和连续的空格,对处理后的代码进行分析。

三.模块划分和实现

1.数据结构

(1)ModulClass存储划分好的词法单元的分类,存储有单元的名称和单元的标号,与上面的表格中的信息一致。

在程序开始时需要首先将分类信息读取然后填充表格

classModulClass//存储词法单元的分类

{

public:

stringstrID;//单元名字

intnumber;//单元编号

};

ModulClassmodulclass[ModulClass_size];

(2)Codeclass存储在程序识别过程中识别到的词法单元

classCodeClass//存储识别过程中识别的词法单元

{

public:

stringcode;//名字

intnumber;//编号

};

CodeClasscodeclass[CodeClasss_size];

2.预处理模块readcode()函数

(1)代码存储在code.txt中,用C++流读取文件内容,相关代码如下。

ifstreaminfile("code.txt",ios:

:

in);

if(!

infile)

{

cout<<"无法打开代码文件!

"<

exit(-1);

}

infile.getline(temp,1000,EOF);

temp[strlen(temp)]='\0';

(2)去除换行符号

for(i=0;i

{

if(temp[i]=='\n')

strtemp+="";

else

strtemp+=temp[i];

}

(3)去除多余的空格符号,将多个空格连续的压缩成一个

for(j=0;j<=strtemp.length();)

{

if(strtemp[j]=='')

{

while(strtemp[++j]=='')

{}

strcode+='';//处理空格,将多个连续的空格压缩成一个

continue;

}

else

{

strcode+=strtemp[j];

j++;

}

}

cout<<"消去空格和换行符处理结果"<

3.文法输入模块init_class()

该模块将表格中的文法符号通过文件读取的方式读取到实现建立好的对象数组中,方便以后进行查询操作。

核心代码如下:

while(!

(in_class.eof()))

{

in_class>>modulclass[i].strID;

in_class>>modulclass[i].number;

i++;

}

4.判断是否为标识符

intis_key_ID(intforward,intback)//判断是否是标识符

该函数判断读入的是否为标识符,根据标识符判断的正则表达式进行识别,若非标识符则输出错误,若识别则将该标识符的字符串和种别码进行保存。

需建立两个指针,forwawrd指针和back指针,首先forward指针移动,back指针则指向标识符的第一个字符的位置,直到识别完毕。

关键代码如下:

while(++forward)//扫描字符串,返回idtemp,保存forward

{

if(((strcode[forward]>=65)&&(strcode[forward]<=89))||((strcode[forward]>=97)&&(strcode[forward]<=122)))//下一个是字母

temp[++len]=strcode[forward];

elseif((strcode[forward]>=48)&&(strcode[forward]<=57))//下一个是数字

temp[++len]=strcode[forward];

else

{

forward--;

break;

}

}

5.判断匹配关键字

判断该字符串符合标识符的文法之后,需事先判断该标识符是否是系统预留的关键字。

booliskey=false;//判断是否是key

codeclass[num_class].code=idtemp;//保存词法单元code属性

for(inti=0;i

{

if(idtemp==modulclass[i].strID)//完全匹配:

是关键字

{

codeclass[num_class].number=modulclass[i].number;

iskey=true;

break;

}

}

if(!

iskey)//如果不是关键字,即为ID

{

codeclass[num_class].number=8;//ID的编号为8

}

num_class++;

6.判断是否是数字

函数:

is_number(intforward,intback)

需建立两个指针,forwawrd指针和back指针,首先forward指针移动,back指针则指向标识符的第一个字符的位置,直到识别完毕。

若是数字则保存,指针回退一个字符。

否则宣布错误信息。

while(++forward)//扫描字符串,返回idtemp,保存forward

{

if((strcode[forward]>=48)&&(strcode[forward]<=57))//下一个是数字

temp[++len]=strcode[forward];

else

{

forward--;

break;

}

}

7.判断是否是relop符号

分为两种情况:

由一个字符组成和由两个字符组成

(1)仅有一个字符组成

if(temp[1]!

='=')//该运算符仅有一个字符

{

forward--;//回退指针

//保存词法单元

switch(temp[0])

{

case'<':

codeclass[num_class].code="L";//保存词法单元code属性

codeclass[num_class].number=25;//ID的编号

break;

case'>':

codeclass[num_class].code="G";//保存词法单元code属性

codeclass[num_class].number=24;//ID的编号

break;

case'=':

codeclass[num_class].code="=";//保存词法单元code属性

codeclass[num_class].number=10;//ID的编号

}

num_class++;

}

(2)由两个字符组成

else//由两个字符构成,第二个为‘=’

{

//保存词法单元

switch(temp[0])

{

case'<':

codeclass[num_class].code="LE";//保存词法单元code属性

codeclass[num_class].number=27;//relop的编号

break;

case'>':

codeclass[num_class].code="GE";//保存词法单元code属性

codeclass[num_class].number=26;//relop的编号

break;

case'=':

codeclass[num_class].code="EQ";//保存词法单元code属性

codeclass[num_class].number=28;//relop的编号

break;

case'!

':

codeclass[num_class].code="NE";//保存词法单元code属性

codeclass[num_class].number=29;//relop的编号

}

num_class++;

}

returnforward;//返回当前扫描的位置

}

8.词法单元扫描器

扫描器维持两个指针,forward指针和back指针,同时获取扫描区域的总长度。

根据back指针指向的字符的属性,判断该词法单元的种类,然后根据种类跳转到相应的识别函数中去,观察该函数能否被识别,若能够被识别则保存该词法单元,跳转道下一个词法单元,否则输出错误信息。

voidscanner()

{

inti;

intforward=0,back=0;//维持两个指针

intlenth=strcode.length();//扫描区域的总长度

chartemp;

num_class=0;//记录识别出词法单元的个数方便存储

while(forward<=strcode.length()-1)//开始扫描

{

temp=strcode[forward];

if(((temp>=65)&&(temp<=89))||((temp>=97)&&(temp<=122)))//判断是否是标识符或关键字

{

back=forward;

forward=is_key_ID(forward,back);//识别该标识符或ID,存入相应的词法单元,返回当前扫描位置forward指针

forward++;

back=forward;//继续扫描下一个字符

continue;

}

elseif((temp>=48)&&(temp<=57))//判断是否是数字

{

back=forward;

forward=is_number(forward,back);

forward++;

back=forward;

continue;

}

elseif((temp=='+')||(temp=='-')||(temp=='*')||(temp=='/')||(temp=='(')||(temp==')')||(temp=='[')||(temp==']')||(temp=='{')||(temp=='}')||(temp==',')||(temp==':

')||(temp==';'))//判断是否是符号

{

back=forward;

for(i=0;i

{

if(modulclass[i].strID[0]==temp)

{

codeclass[num_class].number=modulclass[i].number;

codeclass[num_class].code=modulclass[i].strID;

break;

}

}

num_class++;//增加词法单元个数

forward++;

back=forward;

continue;

}

elseif((temp=='<')||(temp=='=')||(temp=='>')||(temp=='!

'))//判断是否是relop比较运算符

{

back=forward;

forward=is_relop(forward,back);

forward++;

back=forward;

continue;

}

elseif(temp=='')//空格

{

forward++;

back=forward;

continue;

}

else

{

forward++;

back=forward;

}

}//while

}

9.将产生的词法单元写入文件

依次将生成的对象写入文件即可。

ofstreamoutfile;

outfile.open("词法分析结果.txt");

for(i=0;i

{

outfile<

outfile<

cout<

cout<

}

outfile.close();

四.实验结果

1.class文件的内容如下,存放预先设定好的词法单元

2.code文件代码如下,存放要识别的程序源代码

3.图为程序运行结果,为识别后的词法单元

五.实验总结

本次实验中词法分析相关代码均由我一人独立编写。

理论联系实际的过程中比较坎坷,首先必须明白词法分析的过程,明白词法单元的识别过程,然后才能设计自己的程序。

但书本知识和程序仍然有一定的差距,在设计过程中必须按照步骤一步一步进行设计,按照标准的模块进行划分。

同时模块的划分必须合理,尽量减少模块间的联系,对今后调试程序有很大帮助。

同时通过这次实验我明白了正则文法的作用,在学习形式语言的时候一直疑惑文法的体系和正规文法的用处,在本次实验中我体会到了正则文法的威力,正则文法可以很好的被计算机高级语言编程识别,而其他文法则没有这种优势。

 

附录:

源代码

//词法分析器BaiChenjia

#include"iostream"

#include"string"

#include"math.h"

#include"fstream"

#defineModulClass_size29

#defineCodeClasss_size100

usingnamespacestd;

stringstrcode;//存储处理过后的代码

intnum_class=0;//记录识别出的词法单元的个数

classModulClass//存储词法单元的分类

{

public:

stringstrID;//单元名字

intnumber;//单元编号

};

ModulClassmodulclass[ModulClass_size];

 

classCodeClass//存储识别过程中识别的词法单元

{

public:

stringcode;//名字

intnumber;//编号

};

CodeClasscodeclass[CodeClasss_size];

 

intreadcode()//读取要处理的代码

{

inti,j;

chartemp[1000];

strcode="";

stringstrtemp="";//存储代码

ifstreaminfile("code.txt",ios:

:

in);

if(!

infile)

{

cout<<"无法打开代码文件!

"<

exit(-1);

}

infile.getline(temp,1000,EOF);

temp[strlen(temp)]='\0';

infile.close();

for(i=0;i

{

if(temp[i]=='\n')

strtemp+="";

else

strtemp+=temp[i];

}

strtemp[i]='\0';

for(j=0;j<=strtemp.length();)

{

if(strtemp[j]=='')

{

while(strtemp[++j]=='')

{}

strcode+='';//处理空格,将多个连续的空格压缩成一个

continue;

}

else

{

strcode+=strtemp[j];

j++;

}

}

cout<<"消去空格和换行符处理结果"<

return0;

}

voidinit_class()//对文法规定的标识符、数字、符号等进行分类,写入modulclass对象中

{

inti;

ifstreamin_class;

in_class.open("class.txt");

if(!

in_class)

{

cout<<"无法打开代码文件!

"<

exit(-1);

}

i=0;

while(!

(in_class.eof()))

{

in_class>>modulclass[i].strID;

in_class>>modulclass[i].number;

i++;

}

in_class.close();

/*for(i=0;i

cout<

}

intis_key_ID(intforward,intback)//判断是否是标识符

{

stringidtemp="";

chartemp[100];

memset(temp,0,100);

intlen=0;//记录该标识符或ID的长度-1

temp[0]=strcode[back];

while(++forward)//扫描字符串,返回idtemp,保存forward

{

if(((strcode[forward]>=65)&&(strcode[forward]<=89))||((strcode[forward]>=97)&&(strcode[forward]<=122)))//下一个是字母

temp[++len]=strcode[forward];

elseif((strcode[forward]>=48)&&(strcode[forward]<=57))//下一个是数字

temp[++len]=strcode[forward];

else

{

forward--;

break;

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

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

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1