一、待分析的源程序
VAR X,Y:INTEGER;
A,B,C,D:INTEGER;
BEGIN
X:=12;
Y:=4;
A:=X+Y;//加法
B:=X-Y;//减法
C:=X*Y;
D:=X/Y;
IF C>D
THEN C:=A;
ELSE C:=B
END
二、单词表
符号 | 类别 |
---|---|
begin | 1 |
end | 2 |
if | 3 |
then | 4 |
else | 5 |
while | 6 |
do | 7 |
var | 8 |
integer | 9 |
标识符 | 10 |
整数 | 11 |
, | 12 |
: | 13 |
; | 14 |
:= | 15 |
> | 16 |
< | 17 |
>= | 18 |
<= | 19 |
= | 20 |
+ | 21 |
- | 22 |
* | 23 |
/ | 24 |
( | 25 |
) | 26 |
<> | 27 |
三、词法分析器
#include<stdio.h>
#include<ctype.h>
#include<string.h>
#include<stdlib.h>
#define USUAL 20 //普通二元式行数
#define MAX 10000 //二元式最大行数
#define MAXLEN 8 //标识符最大识别长度
#define MAXNUM "65535" //整数最大数值
struct dual
{
int dual_type;//类别码
union{
char text[20];//值
int num[10];
}lexeme;
int x,y;//行号,列号
}DUAL[MAX];
/*保存单词表二元式的结构体*/
struct str{
char *idstr;//字符串
int type;//类型号
};
struct str Keyword[USUAL];
struct str Separator[USUAL];
struct str Operation[USUAL];
FILE *fpout;
long num=0;
int wrong=0;
int errorno=0;
/**********************************
初始化单词类型表
***********************************/
void init()
{
char *key[]={"","begin","end","if","then","else","while","do","var","integer"};//关键字
char *separator[]={"",",",":",";",":=","(",")"};//分隔符
char *operation[]={"",">","<",">=","<=","=","+","-","*","/","<>"};//运算符
int i;
for(i=1;i<=9;i++)
{
Keyword[i].idstr = key[i];
Keyword[i].type = i;
}
for(i=1;i<=6;i++)
{
Separator[i].idstr= separator[i];
Separator[i].type = i+11;
if(i==5)
Separator[i].type = 25;
if(i==6)
Separator[i].type = 26;
}
for(i=1;i<=10;i++)
{
Operation[i].idstr = operation[i];
Operation[i].type = i+15;
if(i==10)
Operation[i].type = 27;
}
}
/**********检索关键字*********/
int set_key(char *keyword)
{
int i;
for(i=1;i<=9;i++)
{
if(strcmp(Keyword[i].idstr,keyword)==0)
break;
}
if(i<=9) return Keyword[i].type;
else return 0;
}
/**********判断是否为字母*********/
int Letter(char c)
{
if(((c<='z')&&(c>='a')) || ((c>='A')&&(c<='Z')))
return 1;
else return 0;
}
/*********判断是否是数字*********/
int Digital(char ch)
{
if((ch>='0')&&(ch<='9'))
return 1;
else return 0;
}
/*********判断是否是分隔符*********/
int set_sep(char *ch)
{
int i;
for(i=1;i<=6;i++)
{
if(strcmp(Separator[i].idstr,ch) == 0)
return Separator[i].type;
}
return 0;
}
/*********判断是否为运算符*********/
int set_ope(char *ch)
{
int i;
for(i=1;i<=10;i++)
{
if(strcmp(Operation[i].idstr,ch) == 0)
return Operation[i].type;
}
return 0;
}
void lex_analysis()
{
char ch;
char filename[30];
char array[20];
int row=1;//行号
int clum=1;//列号
int j=0;
FILE *fpin;
printf("请输入待词法分析的源文件名(包含路径):");
scanf("%s",filename);
fpin=fopen(filename,"r");
if(fpin==NULL)
{
printf("打开源文件出错!");
}
ch=fgetc(fpin);
while(ch != EOF)
{
while(ch == '\n')//换行处理,行数加一
{
row++;
clum=1;
ch=fgetc(fpin);
}
while(ch==' '||ch=='\t')
{
clum++;
ch=fgetc(fpin);
}
if(Letter(ch))
{
int t=0;
DUAL[num].x=row;//行
DUAL[num].y=clum;//列
while(Letter(ch)||(Digital(ch)))
{
if((ch<='Z')&&(ch>='A')) ch=ch+32;//忽略大小写
array[j++]=ch;
DUAL[num].lexeme.num[t]=clum;//字符所在列
ch=fgetc(fpin);
if(j>=MAXLEN)
wrong=1;
clum++;
t++;
}
if(ch!=EOF)
fseek(fpin,-1L,SEEK_CUR);//输入指针回退一个字符
array[j]='\0';
j=0;
if(set_key(array) != 0)//如果字符串为关键字
{
int i;
for(i=0;i<t;i++)
{
DUAL[num].lexeme.text[i]=array[i];
}
DUAL[num].lexeme.text[t]='\0';
DUAL[num].dual_type=set_key(array);
}else{
int i;
for(i=0;array[i]!='\0';i++)
DUAL[num].lexeme.text[i]=array[i];
DUAL[num].dual_type=10;
}
if(wrong)//标识符超过8个
{
errorno++;
printf("\n错误为:");
printf("%s\t(%d)",array,row);
}
wrong=0;
num++;
}
else if(Digital(ch))
{
int t=0;
DUAL[num].x=row;//行
DUAL[num].y=clum;//列
while(Digital(ch))
{
array[j++]=ch;
DUAL[num].lexeme.num[t]=clum;
ch=fgetc(fpin);
clum++;
t++;
}
if(ch!=EOF)
fseek(fpin,-1L,SEEK_CUR);//输入指针回退一个字符
array[j]='\0';
j=0;
int i;
for(i=0;array[i]!='\0';i++)
DUAL[num].lexeme.text[i]=array[i];
DUAL[num].dual_type=11;
if(strlen(array)>5)
wrong=1;
if(strlen(array)==5)
{
if(strcmp(array,MAXNUM)>0)
wrong=1;
}
if(wrong)
{
errorno++;
printf("\n整数值大于65535错误在:");
printf("%s\t(%d)",array,row);
}
wrong=0;
num++;
}
else if(ch=='/')//判断是除法还是注释
{
array[j]=ch;
ch=fgetc(fpin);
if(ch='/')//为行注释
{
ch=fgetc(fpin);
while(ch!='\n')
ch=fgetc(fpin);
row++;
}
else if(ch=='*')//为可跨行注释
{
int count;
ch=fgetc(fpin);
while(count!=2)
{
count=0;
while(ch!='*')
{
if(ch == '\n')
row++;
ch=fgetc(fpin);
}
count++;
ch=fgetc(fpin);
if(ch == '/')
count++;
else
ch=fgetc(fpin);
}
}
else if((ch!='*')&&(ch!='/'))//为除法
{
DUAL[num].x=row;
DUAL[num].y=clum;
DUAL[num].lexeme.text[0]=ch;
DUAL[num].dual_type=24;
num++;
fseek(fpin,-1L,SEEK_CUR);//输入指针回退一个字符
}
}
else
{
array[0]=ch;
DUAL[num].x=row;//行
DUAL[num].y=clum;//列
ch=fgetc(fpin);//再读入下一个字符,用来判断是否为双字符
clum++;
if(ch != EOF)
{
array[1]=ch;
array[2]='\0';
if((set_sep(array)==0)&&(set_ope(array)==0))//为单字符或其他非法字符
{
array[1]='\0';
if(set_sep(array))//是否为分隔符
{
DUAL[num].dual_type=set_sep(array);
DUAL[num].lexeme.text[0]=array[0];
fseek(fpin,-1L,SEEK_CUR);//输入指针回退一个字符
num++;
}
if(set_ope(array))//是否为运算符
{
DUAL[num].dual_type=set_ope(array);
DUAL[num].lexeme.text[0]=array[0];
fseek(fpin,-1L,SEEK_CUR);//输入指针回退一个字符
num++;
}
if((set_sep(array)==0) && (set_ope(array)==0))//非法字符
{
printf("\n存在非法字符,错误在:");
printf("%s/t%d",array,row);
fseek(fpin,-1L,SEEK_CUR);//输入指针回退一个字符
errorno++;
}
}else //为双字符
{
DUAL[num].lexeme.num[0]=clum-1;
DUAL[num].lexeme.num[1]=clum;
if(set_sep(array))//是否为分隔符
{
DUAL[num].dual_type=set_sep(array);
DUAL[num].lexeme.text[0]=array[0];
DUAL[num].lexeme.text[1]=array[1];
num++;
}
if(set_ope(array))//是否为运算符
{
DUAL[num].dual_type=set_ope(array);
DUAL[num].lexeme.text[0]=array[0];
DUAL[num].lexeme.text[1]=array[1];
num++;
}
}
}
else
fseek(fpin,-1L,SEEK_CUR);//输入指针回退一个字符
}
ch=fgetc(fpin);
memset(array,'\0',20);
}
printf("\nThere are %d error(s)\n",errorno);
}
void Load()
{
int i=0;
printf("二元式流为:\n");
fpout=fopen("token.txt","w");
for(i=0;i<num;i++)
{
fprintf(fpout,"%s\t\t\t%d\t\t%d\t%d\n",DUAL[i].lexeme.text,DUAL[i].dual_type,DUAL[i].x,DUAL[i].y);
printf("%s\t\t\t%d\t\t%d\t%d\n",DUAL[i].lexeme.text,DUAL[i].dual_type,DUAL[i].x,DUAL[i].y);
}
fclose(fpout);
}
void main()
{
init();
lex_analysis();
Load();
}