编译原理实验报告词法分析器内含源代码.docx
《编译原理实验报告词法分析器内含源代码.docx》由会员分享,可在线阅读,更多相关《编译原理实验报告词法分析器内含源代码.docx(24页珍藏版)》请在冰豆网上搜索。
编译原理实验报告词法分析器内含源代码
编译原理实验
(一)
——词法分析器
一.实验描述
运行环境:
vc++2008
对某特定语言A,构造其词法规则。
该语言的单词符号包括:
1该程序能识别的单词符号及类别说明表
单词
类别
PROGRAM
0
NOT
1
BEGIN
2
IF
3
END
4
THEN
5
VAR
6
ELSE
7
INT
8
WHILE
9
AND
10
DO
11
OR
12
标识符
13
常数
14
+
15
-
16
(
17
)
18
19
;
20
=
21
<
22
>
23
*
24
**
25
>=
26
<=
27
!
=
28
2状态转换图
3程序流程:
词法分析作成一个子程序,由另一个主程序调用,每次调用返回一个单词对应的二元组,输出标识符表、常数表由主程序来完成。
二.实验目的
通过动手实践,使学生对构造编译系统的基本理论、编译程序的基本结构有更为深入的理解和掌握;使学生掌握编译程序设计的基本方法和步骤;能够设计实现编译系统的重要环节。
同时增强编写和调试程序的能力。
三.实验任务
编制程序实现要求的功能,并能完成对测试样例程序的分析。
四.实验原理
charset[1000],str[500],strtaken[20];//set[]存储代码,strtaken[]存储当前字符
charsign[50][10],constant[50][10];//存储标识符和常量
定义了一个Analyzer类
classAnalyzer{
public:
Analyzer();//构造函数~Analyzer();//析构函数
intIsLetter(charch);//判断是否是字母,是则返回1,否则返回0。
intIsDigit(charch);//判断是否为数字,是则返回1,否则返回0。
voidGetChar(char*ch);//将下一个输入字符读到ch中。
voidGetBC(char*ch);//检查ch中的字符是否为空白,
若是,则调用GetChar直至ch进入一个非空白字符。
voidConcat(char*strTaken,char*ch);//将ch中的字符连接到strToken之后。
intReserve(char*strTaken);//对strTaken中的字符串查找保留字表,若是一个保留字返回它的数码,否则返回0。
voidRetract(char*ch);//将搜索指针器回调一个字符位置,将ch置为空白字符。
voidinput();//向存放输入结果的字符数组输入一句语句。
voiddisplay();//输出一些程序结束字符显示样式
intanalyzerSubFun();//词法分析器子程序,为了实现词法分析的主要功能。
五.代码实现
//cifa.cpp:
定义控制台应用程序的入口点。
//
#include"stdafx.h"
#include"stdio.h"
#include"string.h"
#include"iostream"
usingnamespacestd;
charset[1000],str[500],strtaken[20];//set[]存储代码,strtaken[]存储当前字符
charsign[50][10],constant[50][10];//存储标识符和常量
//intWords[500][10];
charch;//当前读入字符
intsr,to=0;//数组str,strtaken的指针
intst=0,dcount=0;
intid=0;
staticintline=1;
inth,l;
typedefstructWords/*放置二元组*/
{
intnum;
charletters[20];
}DS;
DSWords[500];
typedefstructwords
{
charword[20];
inttype;
}WORDS;
WORDSwords[]={
{"program",0},
{"not",1},
{"begin",2},
{"end",3},
{"if",4},
{"then",5},
{"var",6},
{"else",7},
{"int",8},
{"while",9},
{"and",10},
{"do",11},
{"or",12},
{"+",15},
{"-",16},
{"(",17},
{")",18},
{",",19},
{";",20},
{"=",21},
{"<",22},
{">",23},
{"*",24},
{"**",25},
{">=",26},
{"<=",27},
{"!
=",28}
};
typedefstructkeytable/*放置关键字*/
{
charname[20];
intkind;
}KEYTABLE;
KEYTABLEkeyword[]={/*设置关键字*/
{"program",0},
{"not",1},
{"begin",2},
{"end",3},
{"if",4},
{"then",5},
{"var",6},
{"else",7},
{"int",8},
{"while",9},
{"and",10},
{"do",11},
{"or",12},
};
voidopenfile()/*打开文件*/
{
cout<<"____________________________________________________"<cout<<"词法分析器"<cout<<"____________________________________________________"<cout<<"请在本程序根目录下寻找以.txt”为结尾的文件作为词法分析对象,输入文件名"<FILE*fp;
chara,filename[10];
intn=0;
gets(filename);
if((fp=fopen(filename,"r"))==NULL)
{
printf("cannotopenfile.\n");
//exit(0);
}
else
while(!
feof(fp))/*文件不结束,则循环*/
{
a=getc(fp);/*getc函数带回一个字符,赋给a*/
set[n]=a;/*文件的每一个字符都放入set[]数组中*/
n++;
}
fclose(fp);/*关闭文件*/
set[n-1]='\0';
}
voidreflesh()/*清空strtaken数组*/
{
to=0;/*全局变量to是strtaken的指示器*/
strcpy(strtaken,"");
}
voidpre1()/*预处理程序*/
{
inti,a,b,n=0;
do
{
if(set[n]=='/'&&set[n+1]=='*')
{
a=n;/*记录第一个注释符的位置*/
while(!
(set[n]=='*'&&set[n+1]=='/'))
{
if(set[n]=='\n')
line++;
n++;
}
b=n+1;/*记录第二个注释符的位置*/
for(i=a;i<=b;i++)/**/
set[i]='';/*把注释的内容换成空格,等待第二步预处理*/
}
elseif(set[n]=='/'&&set[n+1]=='/')
{
a=n;/*记录第一个注释符的位置*/
while(!
set[n]=='\n')
n++;
b=n+1;/*记录第二个注释符的位置*/
for(i=a;i<=b;i++)/**/
set[i]='';/*把注释的内容换成空格,等待第二步预处理*/
}
n++;
}while(set[n]!
='\0');
}
voidpre2()/*预处理程序*/
{
intj=0;
sr=0;/*全局变量sr是str[]的指示器*/
do
{
if(set[j]==''||set[j]=='\n')
{
while(set[j]==''||set[j]=='\n')/*扫描到有连续的空格或换行符*/
{if(set[j]=='\n')line++;
j++;
}
str[sr]='';/*用一个空格代替扫描到的连续空格和换行符放入str[]*/
sr++;
}
else
{
str[sr]=set[j];/*若当前字符不为空格或换行符就直接放入str[]*/
sr++;
j++;
}
}while(set[j]!
='\0');
str[sr]='\0';
}
charGetChar()/*把字符读入全局变量ch中,指示器sr前移*/
{
ch=str[sr];
sr++;
return(str[sr-1]);
}
voidGetBC()/*开始读入符号,直至第一个不为空格*/
{
while(ch=='')
{
ch=GetChar();
}
}
voidConcat()/*把ch中的字符放入strtaken[]*/
{
strtaken[to]=ch;
to++;/*全局变量to是strtaken的指示器*/
strtaken[to]='\0';
}
intIsLetter()/*判断是否为字母*/
{
if((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z'))
return
(1);
elsereturn(0);
}
intIsDigit()/*判断是否为数字*/
{
if(ch>='0'&&ch<='9')
return
(1);
elsereturn(0);
}
intReserve()/*对strtaken中的字符串查找保留字表,若是则返回它的编码,否则返回-*/
{
inti,k=0;
for(i=0;i<=12;i++)
{
if(stricmp(strtaken,keyword[i].name)==0)
{k=1;
Words[dcount].num=keyword[i].kind;
strcpy(Words[dcount].letters,"-");
dcount++;
return(keyword[i].kind);
}
}
if(k!
=1)
return(-1);
}
voidRetract()/*指示器sr回调一个字符位置,把ch置为空*/
{
sr--;
ch='';
}
intInsertId()
{
inti,k;
for(i=0;i{
k=strcmp(strtaken,sign[i]);
if(k==0)
return(i);
}
strcpy(sign[id],strtaken);/*插入标识符*/
Words[dcount].num=13;
strcpy(Words[dcount].letters,strtaken);
id++;dcount++;
return(id-1);
}
intInsertConst()
{
inti,k;
for(i=0;i{
k=strcmp(strtaken,constant[i]);
if(k==0)
return(i);
}
strcpy(constant[st],strtaken);/*插入常数*/
Words[dcount].num=14;
strcpy(Words[dcount].letters,strtaken);
st++;dcount++;
return(st-1);
}
voidanalysis()
{
intvalue;
reflesh();/*清空strtaken数组*/
pre1();/*预处理,使注释内容换成单个空格,放回set[]中*/
pre2();/*预处理,使set[]中连续的空格置换成单个空格,并把set[]的内容放到str[]中*/
sr=0;
GetChar();/*把字符读入全局变量ch中,指示器sr前移*/
GetBC();/*读取第一个字符*/
while(ch!
='\0')/*当不等于结束符,继续执行*/
{
if(IsLetter())//标识符和关键字判定
{
while(IsLetter()||IsDigit())/*若第一个是字符,继续读取,直到出现空格*/
{
Concat();
GetChar();/*把字符读入全局变量ch中,指示器sr前移*/
}
Retract();/*指示器sr回调一个字符位置,把ch置为空*/
value=Reserve();/*对strtaken中的字符串查找保留字表,若是则返回它的编码,否则返回-*/
if(value==-1)/*如果返回值是-,那就是标识符,把它输出*/
{
InsertId();/*插入标识符*/
}
reflesh();
}
elseif(IsDigit())
{
while(IsDigit())/*否则,若第一个是数字,继续读取,直到出现空格*/
{
Concat();/*把ch中的字符放入strtaken[]*/
GetChar();
}
Retract();/*指示器sr回调一个字符位置,把ch置为空*/
InsertConst();/*插入常数,返回类型为int*/
//printf("%s",strtaken);
//getchar();
reflesh();
}
else
switch(ch)/*否则,若是下面的符号*/
{
case'+':
case'-':
case'(':
case')':
case',':
case';':
case'=':
case'<':
case'>':
Concat();
for(intc0=15;c0<=23;c0++)
{
if(stricmp(strtaken,words[c0].word)==0)
{
Words[dcount].num=words[c0].type;
dcount++;
}
}
reflesh();
break;
default:
if(ch=='*')/*如果是"*"符号,继续读取下一个*/
{
Concat();/*判断是否为"**"的情况*/
GetChar();
if(ch==strtaken[0])
Concat();
else
Retract();
for(intc1=24;c1<=25;c1++)
{
if(stricmp(strtaken,words[c1].word)==0)
{
Words[dcount].num=words[c1].type;
dcount++;
}
}
//printf("%s",strtaken);
//getchar();
reflesh();
break;
}
elseif(ch=='<'||ch=='>'||ch=='!
')
{
Concat();/*判断是否为<=,>=,!
=的情况*/
GetChar();
if(ch=='=')
Concat();
else
Retract();
for(intc2=26;c2<=28;c2++)
{
if(stricmp(strtaken,words[c2].word)==0)
{
Words[dcount].num=words[c2].type;
dcount++;
}
}
reflesh();
break;
}
else
{h=ch/line;
l=ch%line;
cout<<"Errorin"<//getchar();
break;
}
}
GetChar();
GetBC();
}
cout<<"输出二元组:
"<for(intd_i=0;d_icout<cout<cout<<"输出标识符:
"<for(intsign_i=0;sign_icout<cout<cout<<"输出常量:
"<for(intconst_i=0;const_icout<cout<}
int_tmain(intargc,_TCHAR*argv[])
{
openfile();
analysis();
printf("Analysisisfinished!
");
getchar();
return0;
}
测试结果
测试语句为:
Programexample;
varintj,m,n;
Begin/*thereis*a
/comment*/i:
=2;
j:
=6;
m:
=3;//thereisacomment
n:
=j+m;
Ifn>=3andn<5
thenj:
=j-1;
end.
结果截图:
六.总结
我在这次词法分析器的设计过程中学到了很多东西,其中最大的收获是对于编译原理中的词法分析这一过程理解的更加清楚明了。
其次,是在使用c++编程的能力有所提高。
当然,在该词法分析器设计中也有一些不足的地方,比如能识别的关键字有限,并不能识别所有的关键字,识别不出字符常量等。
分析结果输出方式为:
用一个存放结果的字符串数组,并用指针指向它,输出结果正确,但是输出结果比较乱。
不过总的来说,这次实验达到了其初衷,实现了规定的功能。
八.致谢词:
感谢xxx老师对我们的悉心教导以及提供我们这样一个学以致用的机会。
通过这一阶段对编译原理课程的学习,特别是通过这次对于词法分析器的编程实践,我对于编译原理中的词法分析这一过程理解的更加清楚明了,收获很大。