编译原理实验报告——词法分析器(内含源代码)

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

编译原理实验(一)——词法分析器
一.实验描述
运行环境:vc++2008
对某特定语言A ,构造其词法规则。

该语言的单词符号包括:
1
2状态转换图
3程序流程:
词法分析作成一个子程序,由另一个主程序调用,每次调用返回一个单词对应的二元组,输出标识符表、常数表由主程序来完成。

二.实验目的
通过动手实践,使学生对构造编译系统的基本理论、编译程序的基本结构有更为深入的理解和掌握;使学生掌握编译程序设计的基本方法和步骤;能够设计实现编译系统的重要环节。

同时增强编写和调试程序的能力。

三.实验任务
编制程序实现要求的功能,并能完成对测试样例程序的分析。

四.实验原理
char set[1000],str[500],strtaken[20];//set[]存储代码,strtaken[]存储当前字符char sign[50][10],constant[50][10];//存储标识符和常量
定义了一个Analyzer类
class Analyzer{
public:
Analyzer(); //构造函数 ~Analyzer(); //析构函数
int IsLetter(char ch); //判断是否是字母,是则返回 1,否则返回 0。

int IsDigit(char ch); //判断是否为数字,是则返回 1,否则返回 0。

void GetChar(char *ch); //将下一个输入字符读到ch中。

void GetBC(char *ch); //检查ch中的字符是否为空白,
若是,则调用GetChar直至ch进入一个非空白字符。

void Concat(char *strTaken, char *ch); //将ch中的字符连接到strToken之后。

int Reserve(char *strTaken); //对strTaken中的字符串查找保留字表,若是一个保留字返回它的数码,否则返回0。

void Retract(char *ch) ; //将搜索指针器回调一个字符位置,将ch置为空白字符。

void input();//向存放输入结果的字符数组输入一句语句。

void display();//输出一些程序结束字符显示样式
int analyzerSubFun();//词法分析器子程序,为了实现词法分析的主要功能。

五.代码实现
// cifa.cpp : 定义控制台应用程序的入口点。

//
#include"stdafx.h"
#include"stdio.h"
#include"string.h"
#include"iostream"
using namespace std;
char set[1000],str[500],strtaken[20];//set[]存储代码,strtaken[]存储当前字符
char sign[50][10],constant[50][10];//存储标识符和常量
//int Words[500][10];
char ch;//当前读入字符
int sr,to=0;//数组str, strtaken 的指针
int st=0,dcount=0;
int id=0;
static int line=1;
int h,l;
typedef struct Words /*放置二元组*/
{
int num;
char letters[20];
}DS;
DS Words[500];
typedef struct words
{
char word[20];
int type;
}WORDS;
WORDS words[]={
{"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}
};
typedef struct keytable /*放置关键字*/ {
char name[20];
int kind;
}KEYTABLE;
KEYTABLE keyword[]={ /*设置关键字*/
{"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},
};
void openfile() /*打开文件*/
{
cout<<"____________________________________________________"<<endl;
cout<<" 词法分析器 "<<endl;
cout<<"____________________________________________________"<<endl;
cout<<"请在本程序根目录下寻找以.txt”为结尾的文件作为词法分析对象,输入文件名"<<endl;
FILE *fp;
char a,filename[10];
int n=0;
gets(filename);
if((fp=fopen(filename,"r"))==NULL)
{
printf("cannot open file.\n");
//exit(0);
}
else
while(!feof(fp)) /*文件不结束,则循环*/
{
a=getc(fp); /*getc函数带回一个字符,赋给a*/
set[n]=a; /*文件的每一个字符都放入set[]数组中*/
n++;
}
fclose(fp); /*关闭文件*/
set[n-1]='\0';
void reflesh() /*清空strtaken数组*/
{
to=0; /*全局变量to是strtaken的指示器*/
strcpy(strtaken," ");
}
void pre1() /*预处理程序*/
{
int i,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]=' '; /*把注释的内容换成空格,等待第二步预处理*/ }
else if(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');
}
void pre2() /*预处理程序*/
int j=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';
}
char GetChar() /*把字符读入全局变量ch中,指示器sr前移*/
{
ch=str[sr];
sr++;
return(str[sr-1]);
}
void GetBC() /*开始读入符号,直至第一个不为空格*/
{
while(ch==' ')
{
ch=GetChar();
}
}
void Concat() /*把ch中的字符放入strtaken[]*/
{
strtaken[to]=ch;
to++; /*全局变量to是strtaken的指示器*/
strtaken[to]='\0';
}
int IsLetter() /*判断是否为字母*/
{
if((ch>='a' && ch<='z')||(ch>='A' && ch<='Z'))
return(1);
else return(0);
}
int IsDigit() /*判断是否为数字*/
{
if(ch>='0' && ch<='9')
return(1);
else return(0);
}
int Reserve() /*对strtaken中的字符串查找保留字表,若是则返回它的编码,否则返回-*/ {
int i,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);
}
void Retract() /*指示器sr回调一个字符位置,把ch置为空*/
{
sr--;
ch=' ';
}
int InsertId()
{
int i,k;
for(i=0;i<id;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);
}
int InsertConst()
{
int i,k;
for(i=0;i<st;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);
}
void analysis()
{
int value;
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();
}
else if(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(int c0=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(int c1=24;c1<=25;c1++)
{
if(stricmp(strtaken,words[c1].word)==0)
{
Words[dcount].num=words[c1].type;
dcount++;
}
}
//printf(" %s",strtaken);
//getchar();
reflesh();
break;
}
else if(ch=='<' || ch=='>' || ch=='!')
{
Concat(); /*判断是否为<=,>=,!=的情况*/
GetChar();
if(ch=='=')
Concat();
else
Retract();
for(int c2=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<<"Error in "<<h<<"行"<<l<<"列"<<endl;
//getchar();
break;
}
}
GetChar();
GetBC();
}
cout<<"输出二元组:"<<endl;
for(int d_i=0;d_i<dcount;d_i++)
cout<<Words[d_i].num<<" "<<Words[d_i].letters<<endl;
cout<<endl;
cout<<"输出标识符:"<<endl;
for(int sign_i=0;sign_i<id;sign_i++)
cout<<sign_i<<" "<<sign[sign_i]<<endl;
cout<<endl;
cout<<"输出常量:"<<endl;
for(int const_i=0;const_i<st;const_i++)
cout<<const_i<<" "<<constant[const_i]<<endl;
cout<<endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
openfile();
analysis();
printf("Analysis is finished!");
getchar();
return 0;
}
测试结果
测试语句为:Program example ;
var int j,m,n;
Begin /*there is * a
/ comment*/ i:=2;
j:=6;
m:=3; //there is a comment
n:=j+m;
If n>=3 and n<5
then j:=j-1;
end .
结果截图:
六.总结
我在这次词法分析器的设计过程中学到了很多东西,其中最大的收获是对于编译原理中的词法分析这一过程理解的更加清楚明了。

其次,是在使用c++编程的能力有所提高。

当然,在该词法分析器设计中也有一些不足的地方,比如能识别的关键字有限,并不能识别所有的关键字,识别不出字符常量等。

分析结果输出方式为:用一个存放结果的字符串数组,并用指针指向它,输出结果正确,但是输出结果比较乱。

不过总的来说,这次实验达到了其初衷,实现了规定的功能。

八.致谢词:
感谢xxx老师对我们的悉心教导以及提供我们这样一个学以致用的机会。

通过这一阶段对编译原理课程的学习,特别是通过这次对于词法分析器的编程实践,我对于编译原理中的词法分析这一过程理解的更加清楚明了,收获很大。

相关文档
最新文档