⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 word.cpp

📁 一个词法分析程序,用来实现一个简单编译器的词法分析,功能详见<<编译原理>>.
💻 CPP
字号:
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#define v -1  //为某些类数据成员赋初值
#define LEN sizeof(char)

int outweizhi=0;//用来实现最终的动态插入
//此结构是为了建立一个表格
typedef struct keywords{
	int xuhao;
	char str[20];
	int type;
}word;
//初始化该表格
word item[40]={{1,"int",1},{2,"char",1},{3,"float",1},{4,"void",1},{5,"const",1},
{6,"if",1},{7,"else",1},{8,"then",1},{9,"repeat",1},{10,"until",1},{11,"read",1},
{12,"write",1},{13,"end",1},{14,"main",1},{15,"+",4},{16,"-",4},{17,"*",4},{18,"/",4},
{19,"%",4},{20,"?",4},{21,":",5},{22,">",4},{23,"<",4},{24,"==",4},{25,">=",4},{26,"<=",4},
{27,"::",4},{28,"(",5},{29,")",5},{30,"[",5},{31,"]",5},{32,"{",5},{33,"}",5},{34,",",5},
{35,";",5},{36,"'",5},{37,"\"",5},{38,"=",4},{39,"++",4},{40,"--",4}};
//此结构是为了建立一个标识符表
typedef struct expresswords{
	int xuhao;
	char str[20];
}ew;
ew id[100];
//此结构是为了建立一个常数表
typedef struct changshu{
	int xuhao;
	char str[20];
}cs;
cs ci[100];
//此结构是为最终生成outfile.txt文件赋值
typedef struct shuchu{
	int type;
	int position;
}out;
out op[200];

class procedure
{
public:
	procedure(char * str);
	procedure judge(FILE *fp,procedure p);
	char * initstring(procedure p);
	char * institute(char * str,int i,char c);
	int research(char * str,procedure p);
	void biaoshifu(char *str,procedure p);
	void changshu(char * str,procedure p);
    void fuzhi(int type,int position); 
	procedure deal0(procedure p);
	procedure deal1(procedure p);
	procedure deal2(procedure p);
	char * Convert(int a,char * s);
	void output(char * pt,procedure p);
	void makefile(procedure p);
	void lexical(procedure p);
	void release(procedure p);
	~procedure();
private:
	int type,flag,line,position,weizhi,error;
	char ch;
    FILE * fp,* outfp;
};

procedure::procedure(char * str):line(1),position(0),weizhi(0)
{//构造函数,用来将类的数据成员初始化
	type=v;
	flag=v;
	error=0;
	fp=fopen(str,"r");
	ch=fgetc(fp);
	outfp=fopen("outfile.txt","w");
}

inline procedure procedure::judge(FILE *fp,procedure p)
{//来初步产生每个单词的类型
	if(p.ch==EOF) return p;
	while(p.ch==10 || p.ch==' ')//若是换行符或空格,文件指针后移
    {if(p.ch==10) line++;p.ch=fgetc(p.fp);}
    if((p.ch>64 && p.ch<91)||(p.ch>96 && p.ch<123)) p.type=0;//标识符或关键字
	else
	{
    if(p.ch>47 && p.ch<58)  p.type=1;//常数
	else p.type=2;//其它单词
	}
	return p;
}

inline char * procedure::initstring(procedure p)
{//将单词首字母初始化为一个字符串
   	char *str;
	str=(char *)malloc(2*LEN);
	*str=p.ch;
	*(str+1)='\0';
	return str;
}

inline char * procedure::institute(char * str,int i,char c)
{//若当前字符是满足条件,则将此字符扩充进字符串str
    str=(char *)realloc(str,i*LEN);
	*(str+i-2)=c;
	*(str+i-1)='\0';
	return str;
}

inline int procedure::research(char * str,procedure p)
{   //用来在特殊符号表中查找单词是否在其中
	int i,f=0,s;
	word * pointer,* current;
	pointer=item;//指针指向关键字表首地址
	for(i=0;i<40;i++,pointer++)
	if(!strcmp(str,pointer->str)) 
	{f=1;current=pointer;s=i;}//若找到相应的字符串,将f置1
    if(f==1) 
	{
		printf("第%d行 %s :(1,%d),关键字表中.\n",line,current->str,current->xuhao);
        p.fuzhi(1,current->xuhao);
	}
	return f;
}

void procedure::biaoshifu(char *str,procedure p)
{   //用来处理标识符单词
	int i,f=0;
	ew * pointer,* current,* point;
	if(p.error!=1)
	{//先查找标识符表中是否已经存在该单词,用f置位来表示
	pointer=id;
    for(i=0;i<100;i++,pointer++)
	if(!strcmp(str,pointer->str)) 
	{f=1;current=pointer;}
    if(f==1)  
	{//若f为1,则表明已在标识符表中
		printf("第%d行 %s :(2,%d),已在标识符表中.\n",line,current->str,current->xuhao+1);
		p.fuzhi(2,current->xuhao+1);
	}
	else 
	{//若f不为1,则需要将此单词追加到标识符表中
	point=id+position;
	point->xuhao=position;
	strcpy(point->str,str);
    printf("第%d行 %s :(2,%d),插入标识符表中.\n",line,str,position+1);
    p.fuzhi(2,position+1);
	position++;
	}
	}
	else//若标识符不符词法规则,出错处理
    printf("第%d行:输入形式不符合词法规则,数字与字母不可在一块,请纠正.\n",line);
}

procedure procedure::deal0(procedure p)
{//用来处理标识符或关键字单词
	char c;
	int i=2,f;
	char *str=initstring(p);//先将单词首字符初始化为字符串形式
	c=fgetc(p.fp);
	while(((c>64 && c<91)||(c>96 && c<123)) || (c>47 && c<58) || c=='_')
	{//若当前字符是字母,数字或下划线,则将此字符扩充进字符串str
		if(c>47 && c<58) p.flag=0; //0表示此单词是标识符.
		++i;
		str=institute(str,i,c);
		c=fgetc(p.fp);
	}
	p.ch=c;
	f=research(str,p);//查找此单词是否为关键字
	if(f!=1) { p.flag=0; biaoshifu(str,p);}//f若不为1,则表明是标识符
	return(p);
}

void procedure::changshu(char * str,procedure p)
{   //用来处理常数单词
	int i,f=0;
    cs * pointer,* current,* point;
	if(p.error==1)//若错误标志为1,则出错处理  
	printf("第%d行:输入形式不符合词法规则,数字与字母不可在一块,请纠正.\n",line);
	else
	{//先查找标识符表中是否已经存在该单词,用f置位来表示
	pointer=ci;
	for(i=0;i<100;i++,pointer++)
	if(!strcmp(str,pointer->str))
	{f=1;current=pointer;}
	if(f==1) 
	{//若f为1,则表明已在常数表中
		printf("第%d行 %s :(3,%d),已在常数表中.\n",line,current->str,current->xuhao+1);
		p.fuzhi(3,current->xuhao+1);
	}
	else 
	{//若f不为1,则需要将此单词追加到标识符表中
	point=ci+weizhi;
	point->xuhao=weizhi;
	strcpy(point->str,str);
	printf("第%d行 %s :(3,%d),插入常数表中.\n",line,str,++weizhi);
	p.fuzhi(3,weizhi);
	}
	}
}

inline void procedure::fuzhi(int type,int position)
{//用来将二元组有关信息赋值至输出结构体数组中
	out * pointer;
	pointer=op;
	pointer=pointer+outweizhi;
	pointer->type=type;
	pointer->position=position;
	outweizhi++;
}


procedure procedure::deal1(procedure p)
{//用来处理常数单词
    char c;
	int i=2;
	char *str=initstring(p);//先将单词首字母初始化为一个字符串
	p.error=0;//先将错误标志置为0
	c=fgetc(p.fp);
	while((c>47 && c<58) || c=='.' || c=='e' || c=='E')
	{//若当前字符为数字,小数点或e,则将此字符添加到字符串中
		++i;
		str=institute(str,i,c);
		c=fgetc(p.fp);
//		fseek(fp,-1,1);
	}
	p.ch=c;
	if((p.ch>64 && p.ch<91)||(p.ch>96 && p.ch<123)) 
	p.error=1;//若常数后紧跟一个字母,则此数字出错.
    changshu(str,p);//调用一个函数用来查找已经建立的常数表中是否有此常数
	return p;
}

procedure procedure::deal2(procedure p)
{//只要用于处理除关键字,标识符,常数之外的其它单词.
	char c;
	int i=2,f=0;
	char *str=initstring(p);//先将单词首字母初始化为一个字符串
	word * pointer,* current;
	pointer=item;
	c=fgetc(p.fp);
    switch(p.ch)
	{//主要用来处理双目运算符,从而将其作为一个单词分离出来
	case '=':
		if(c=='=') {str=institute(str,++i,c);f=1;}break;
	case '>':
		if(c=='=') {str=institute(str,++i,c);f=1;}break;
    case '<':
		if(c=='=') {str=institute(str,++i,c);f=1;}break;
	case '+':
		if(c=='+') {str=institute(str,++i,c);f=1;}break;
	case '-':
		if(c=='-') {str=institute(str,++i,c);f=1;}break;
	default:
		break;
	}//f用来标识此此单词是否为,双目运算符
	if(f==1) p.ch=fgetc(p.fp);
	else p.ch=c;
	for(i=0;i<40;i++,pointer++)
	if(!strcmp(str,pointer->str)) 
	{f=1;current=pointer;}
	if(f==1)
	{//f用来标识此单词是否在特殊符号表中
	if(current->type==4)   
	{
		printf("第%d行 %s :(4,%d),运算符表中.\n",line,str,current->xuhao);
		p.fuzhi(4,current->xuhao);
	}
	if(current->type==5)   
	{
		printf("第%d行 %s :(5,%d),界符表中.\n",line,str,current->xuhao);
		p.fuzhi(5,current->xuhao);
	}
	}//接下来是出错处理
    else printf("第%d行 %s :不符合词法分析格式,请纠正.\n",line,str);
	return p;
}

char * procedure::Convert(int a,char * s)
{//以下函数是为了将一个数字转化为一个字符串
    int i,t;
    char c[10];
    if(a>=10000) printf("error\n");
    c[9]='\0';
    i=9;
    do{i--;
    t=a%10;
    a=a/10;
    t=t+'0';
    c[i]=t;}while(a!=0);
    strcpy(s,&c[i]);
    return s;
}

void procedure::output(char * pt,procedure p)
{//用来将一个数字字符串输入文件file.txt中
       int j=0;
	   while(*pt!='\0')
	   {fputc(*pt,p.outfp);pt++;}
}

void procedure::makefile(procedure p)
{//每调用一次,即可将一个二元组输入至file.txt中
	out * pointer;
	pointer=op;
	char s1[10],s2[10];//分别存放类型号和内部码值
	for(int i=0;i<outweizhi;i++,pointer++)
	{
	   p.Convert(pointer->type,s1);
	   p.Convert(pointer->position,s2);
	   fputc('<',p.outfp);
	   p.output(s1,p);
	   fputc(',',p.outfp);
	   p.output(s2,p);
       fputc('>',p.outfp);
	   fputc('\n',p.outfp);
	}
}

void procedure::lexical(procedure p)
{  //词法分析程序的主干
    p=judge(p.fp,p);
	do{
	if(p.type==0)  p=deal0(p);//用来将以ch开头的关键字或标识符的单词分离程序.
	else
	{
	if(p.type==1)  p=deal1(p);//用来将以ch开头的数字的单词分离程序.
    else p=deal2(p);//用来处理以ch开头的其它单词分离程序.
	}
	p=judge(p.fp,p);
	}while(!feof(p.fp));
	p.makefile(p);//用来生成文件outfile.txt
    p.release(p);
}

void procedure::release(procedure p)
{//此函数是为了释放最终的文件指针
	fclose(p.fp);
	fclose(p.outfp);
}

procedure::~procedure()
{
}

void main()
{
   char name[20]="file.txt";//name字符数组用来存放已建立要分析文件的文件名
   procedure p(name);//利用构造函数将对象初始化
   printf("***********这是词法分析程序,分析文件file.txt已建立,分析格式如下************\n");
   printf("第几行 单词的字符串形式 :二元组(类型号,表中位置),备注:已在表中还是插入表中.\n");
   printf("*****************分析最终结果相应也生成一文件outfile.txt*******************\n");
   printf("------------------------------分析结果如下--------------------------------\n");
   p.lexical(p); //调用词法分析程序
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -