编译原理之词法分析器

博客主要围绕源程序分析展开,给出了待分析的源程序,包含变量定义、赋值及运算等语句,还提及了单词表和词法分析器,聚焦于信息技术领域的程序分析相关内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、待分析的源程序

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

二、单词表

符号类别
begin1
end2
if3
then4
else5
while6
do7
var8
integer9
标识符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();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值