📄 单词的词法分析程序设计.cpp
字号:
#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
#define N 256//每行至多256个字符
#define n 20 //每个单词至多20个字符
char line[N];//存放每一行字符的数组
char word[n];//存放一个单词的数组
int i;int j;//分别用于控制每个单词和每行字符数组时的计数
char mark;char ch;//分别为单词种类标记和当前分析字符
int wordlen,linelen,count;//分别为单词长度,每行字符长度,以及行数
FILE *sp,*rp;//文件指针,分别指向源文件和目标文件
char *keyword[13]={"CONST","VAR","PROCEDURE","BEGIN","END","ODD","IF","THEN","CALL","WHILE","DO","READ","WRITE"};
char type[6]={'k','v','m','c','b'};//单词种类,k为关键字,v为标志符,m为运算符,c为常数,b为界限符
int IsKeyword(char *word)//判断是否为关键字
{
int comkey=0;
for(int i=0;i<13;i++)
{if(strcmp(word,keyword[i])==0)//与关键字数组进行比较,有符合的则为关键字
comkey=1;}
return comkey;
}
void clear(char *array,int length)//清除数组中内容,以免出现因为单词(或每行)长短不一无法完全覆盖而造成的错误.
{
for(int i=0;i<length;i++)
{array[i]='\0';}//将数组清空(用于单词数组和每行字符数组的清空)
}
int IsMath()//判断当前字符是否为运算符
{
if(ch=='+'||ch=='-'||ch=='*'||ch=='/'||ch=='='||ch=='<'||ch=='>'||ch==':')
return 1;
else return 0;
}
int IsBound()//判断当前字符是否为界限符
{
if(ch==','||ch=='.'||ch==';'||ch=='('||ch==')')
return 1;
else return 0;
}
void write(char *word,char mark,FILE *ofile)//设置输出格式为(单词,类别)
{
fputc('(',ofile);
fputs(word,ofile);//单词
fputc(',',ofile);
fputc(mark,ofile);//类别
fputc(')',ofile);
}
int readline(FILE *fp)//读一行字符,存储在数组line[N]中
{
char str;
int len=0;//len为此行字符个数
str=fgetc(fp);//从文件中获取一个字符
while(!feof(fp) && str!='\n')//当遇到换行符或是文件结束时停止读入.
{
line[len]=str;
str=fgetc(fp);
len++;
}
linelen=len;
if(feof(fp))//文件结束
return 0;
else
return 1;
}
void error(int etype)//出现错误时,根据错误类型,显示相应出错信息,并作相应处理.
{
if(etype==1)
{
if(!isspace(ch)&&ch!='\n'&&ch!='\t')
{cout<<"第"<<count<<"行出现无效字符"<<ch<<endl;}
j=j+1;ch=line[j];//跳过无效字符
}
else if(etype==2)
cout<<"第"<<count<<"行指数形式错误"<<endl;
}
void Alpha()//单词开始字符为字母时
{ i=0;//每执行一次,则处理了一个单词,i置0,以下同上.
while(isalpha(ch) || isdigit(ch))
{
word[i]=ch;
i++;j++;
ch=line[j];
}
if (IsKeyword(word))//为关键字时
{mark=type[0];}
else//为一般标志符时
{mark=type[1];}
write(word,mark,rp);
wordlen=i;
clear(word,wordlen);
}
void Digit()//当前字符为数字时
{
i=0;int eyes;
do{
word[i++]=ch;
ch=line[++j];
}while(isdigit(ch));
if(ch=='.')//小数时
{
word[i++]=ch;
ch=line[++j];
if(!isdigit(ch)){eyes=1;}//前面已有小数点(.),则后面紧跟着的字符必须是数字,否则为错误形式.
while(isdigit(ch))
{ word[i++]=ch;
ch=line[++j]; }
}
if(ch=='e'||ch=='E')//指数时
{ word[i++]=ch;
ch=line[++j];
if(ch=='-')
{word[i++]=ch;ch=line[++j];}
if(!isdigit(ch)){eyes=1;}//如果有E(e),说明是指数形式,E(e)后面必须为数字,否则为错误形式.
while(isdigit(ch))
{ word[i++]=ch;
ch=line[++j];}
}
if(eyes==1){error(2);}//如果有错误,则调用出错函数处理
mark=type[3];
write(word,mark,rp);
wordlen=i;
clear(word,wordlen);
}
void Math()//单词开始字符为运算符时
{ i=0;
word[i] =ch;
if(ch=='+'||ch=='-'||ch=='*'||ch=='/'||ch=='=')
{
mark=type[2];wordlen=1;
}
else if(ch=='>')//当为'>'时,可能为'>',也能为'>='
{ j=j+1;
ch=line[j];
if(ch=='=')//为'>="时,单词长度为2,将'='和'>'合并为一个单词.
{mark=type[2];word[1]=ch;wordlen=2;}
else//为'>'时,单词长度为1,'>'后面的字符不属于该单词,属于后面单词,用j=j-1,退出,使后面的字符进入下一轮判断.
{mark=type[2];wordlen=1;;}
}
else if( ch=='<')//有'<'和'<="两种情况,与'>'类似.
{ j=j+1;
ch=line[j];
if(ch=='=')
{mark=type[2];word[1]=ch;wordlen=2;}
else
{mark=type[2];wordlen=1;j=j-1;}
}
else if(ch==':')
{
j=j+1;
ch=line[j];
if(ch=='=')//赋值符':='
{mark=type[2];word[1]=ch;wordlen=2;}
else//界限符':'
{mark=type[4];wordlen=1;j=j-1;}
}
j=j+1;
ch=line[j];
write(word,mark,rp);
clear(word,wordlen);
}
void Bound()//单词开头为界限符时.
{
i=0;
word[i]=ch;
mark=type[4];
write(word,mark,rp);
wordlen=1;
clear(word,wordlen);
j=j+1;
ch=line[j];
}
void main()
{
char sourcefile[20],resultfile[20];//存入输入,输出文件名
cout<<"请输入需进行词法分析的文件名:";
gets(sourcefile);
cout<<"请输入词法分析后得到的输出文件名:";
gets(resultfile);
sp=fopen(sourcefile,"r");//以"读"形式打开源文件,以读入文件进行分析.
rp=fopen(resultfile,"w");//以"写"形式打开目标文件,以将词性分析结果写入
if(!sp)//源文件不存在
{cout<<"对不起,你输入的源文件不存在!";
exit(0);}
else
{
while(readline(sp))//每执行一次循环,完成一行字符的处理操作,直到文件结束
{
j=0;count++;//每完成一行,j置0,行数增加
ch=line[0];//读入一行中第一个字符
do{//对当前字符进行类别判断,进入不同的子程序分支.
if(isalpha(ch)) {Alpha();}//为字母时
else if(isdigit(ch)){ Digit();}//为数字时
else if(IsMath()) {Math();}//为运算符时
else if(IsBound()) {Bound();}//为界限符时
else if(ch=='#') exit(0);//为结束符时,退出
else {error(1);}//其他时字符进行错误处理.
}while(j<linelen);//处理直到每行结束
clear(line,linelen);//一行字符处理完成后,对此行字符数组进行清除处理.以免影响下一行字符.
fputc('\n',rp);//每在目标文件中写完一行字符的分析结果,则进行换行,使目标文件与源文件行行对应.
}
}
fclose(sp);//分析完成,关闭文件
fclose(rp);
cout<<"词法分析成功!结果保存在:"<<resultfile<<endl;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -