一、实验目的和要求
设计、编写、调试一个具体的词法分析程序,加深对词法分析原理的理解。
二、算法描述
先将文件a.txt按字符顺序读入,先判断读入的字符ch是否为数字,字母。如果是,再判断key是否为0如果是,判断是否为数字,如果是数字,将temp设为1,如果不是temp保持0;如果key不为0,判断temp是否为1,如果为1,说明这个单词是数字开头,要检测单词后面是否会出现字母,出现报错。如果读入的字符ch是换行或回车,要将行数lineNum++,然后将word_temp[]数组的值复制到word[].w中,将key置为0;如果读入的是空格或tab键,将word_temp[]数组的值复制到word[].w中,将key置为0;如果ch的值为':'或'>'或'<'将ch放入word_temp[]数组中,并判断下一个ch是否为'=',是将ch放入word_temp[]数组中,将word_temp[]数组的值复制到word[].w中。 最后将word[]数组的所有值输出。程序运行结束。三、代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
/*
code类别表:
1 : 关键字
2 : 标识符
3 : 常量
4 : 运算符
5 : 对应的是界符中元素的位置
*/
typedef struct Word
{
int num;//词所属类型 SYM
char w[20];//词的标识识别符的值 ID
int lineNum;
}Word;
char ktt[42][20]=
{
"begin","call","const","do","end","if","odd","procedure",
"read","then","var","while","write",",",";",":","(",")","[","]",
"{","}","+","-","*","/","=","<",">","<=",">=",":=","0","1","2","3",
"4","5","6","7","8","9"
}; //SYM用户关键字,运算符,界符
int main()
{
char ch,word_temp[20]="" ; //缓存区
int i=0,j=0,k=0,key=0,chioce,temp=0, lineNum=1,WordTemp=0;
FILE *fp;
Word word[100];
printf("1:输入源程序保存成文件\n");
printf("2:打开文件进行词法分析\n");
fp=fopen("a.txt","r");
if(!fp)
{
printf("文件打开失败\n");
exit(1);
}
// 源文件输出
printf("源程序如下:\n");
while((ch=fgetc(fp))!=EOF)
{
putchar(ch);
}
fclose(fp);
// 重新打开文件,进行词法分析
printf("\n词法分析结果如下:\n");
fp=fopen("a.txt","r");
if(!fp)
{
printf("文件打开失败\n");
exit(1);
}
while((ch=fgetc(fp))!=EOF)
{
if((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')||(ch>='0'&&ch<='9'))
{
if(!key){
if(ch>='0'&&ch<='9'){
temp = 1;
}
}
else{
if(temp){
if((ch>='a'&&ch<='z') || (ch>='A'&&ch<='Z')){
printf("\n\n发现错误,错误出现在%d行---->", lineNum);
WordTemp=1;
}
}
}
word_temp[key++]=ch;//连续几个字母,数字的连成单词
word_temp[key]='\0';
continue;
}
else
{ if(strcmp(word_temp,"")!=0)
{
strcpy(word[i].w,word_temp); //将单词拷贝到结构数组中
word[i].lineNum = lineNum;
strcpy(word_temp,"");
key=0; //回到临时数组的开始位置
if(WordTemp){
printf("%s错误,不能以数字加字母的方式命名标识符\n\n\n",word[i].w);
WordTemp=0;
}
i++; //结构数组的下标加1
temp=0;
}
if(ch==' '||ch==10||ch==13||ch==' ')//去掉空格、回车和tab键
{
// 换行,回车,所在行数增加
if(ch=='\n'){
lineNum++;
}
continue;
}
else
{
word_temp[0]=ch;
if(word_temp[0]==':'||word_temp[0]=='>'||word_temp[0]=='<')
{
ch=fgetc(fp);
if(ch=='=')
{
word_temp[1]=ch;
word_temp[2]='\0';
}
}else{
word_temp[1]='\0';
}
strcpy(word[i].w,word_temp);//将非字母数字符号拷贝到结构数组中
word[i].lineNum = lineNum;
strcpy(word_temp,"");
key=0;//回到临时数组的开始位置
i++;
}
}
}
for(j=0;j<i;j++)
{
for(k=0;k<43;k++)
{
if((strcmp(word[j].w,ktt[k]))==0)
{
if(k>=0&&k<13)
word[j].num=1;//保留字
else if(k>=13&&k<21)
word[j].num=5;//分隔符
else if(k>=21&&k<32)
word[j].num=4;//运算符
else if(k>=32&&k<43)
word[j].num=3;//数字
break;
}
else
word[j].num=2;//变量
}
}
printf("code类别表:\n");
printf("1 : 关键字 \n");
printf("2 : 标识符\n");
printf("3 : 常量\n");
printf("4 : 运算符 \n");
printf("5 : 对应的是界符中元素的位置\n");
for(j=0;j<i;j++)//按格式要求打印输出
{
printf("类别:%d, 单词:'%s', 所在行数:%d\n",word[j].num,word[j].w,word[j].lineNum);
}
fclose(fp);
return 0;
}
// a.txt文件
const a=10;
var b,c;
procedure p;
begin
c:=b+a;
end;
begin
read(b);
while b#0 do
begin
call p;
write(2*c);
read(b);
end;
var 4a = 5;
end.