📄 word.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 + -