⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 accidanaly.c

📁 手工编制词法分析系统
💻 C
字号:
#include "AccidAnaly.h"

////////////////////////////// 以下是主模块 /////////////////////////////////
void main(void)
{
	char temp='a';

	InitAll();			//初始化
//-------------------------------------------------------------------------//
	printf("\n	您需要改变data.c文件中的源程序吗(Y/N):");
	while ((temp != 'Y')&&(temp != 'y')&&
		   (temp != 'N')&&(temp != 'n'))
	{
		temp = getchar();
		getchar();
	}

	if ( (temp=='y') || (temp=='Y') )
	{
		printf("\n	请输入您的源程序:\n");
		if ( !InputData() )
			exit(1);
	}
	temp='a';
//-------------------------------------------------------------------------//
	while ( !AccidAnaly() )
	{
		printf("\n	您的输入不正确,请检查并再次输入您的源程序:\n");
		if ( !InputData() )
			exit(1);
	}
//-------------------------------------------------------------------------//
	printf("\n	您需要输出TwoElem.c文件中的二元式吗(Y/N):");
	while ((temp != 'Y')&&(temp != 'y')&&
		   (temp != 'N')&&(temp != 'n'))
	{
		temp = getchar();
		getchar();
	}

	if ( (temp=='y') || (temp=='Y') )
	{
		PrintTElem();
	}
	temp='a';
//--------------------------------------------------------------------------//
	printf("\n	您需要输出SymTable.c文件中的符号表吗(Y/N):");
	while ((temp != 'Y')&&(temp != 'y')&&
		   (temp != 'N')&&(temp != 'n'))
	{
		temp = getchar();
		getchar();
	}

	if ( (temp=='y') || (temp=='Y') )
	{
		PrintTable();
	}
//--------------------------------------------------------------------------//
	printf("\n	源程序分析结束,谢谢使用!\n");	
}

void InitAll(void)
{
	int i=0;
	
	//设置单字符符号
	for (i=0; i<=255; i++)
	{
		OBSym[i] = nul;
	}
	OBSym['+'] = plus;
	OBSym['-'] = minus;
	OBSym['*'] = times;
	OBSym['/'] = slash;
	OBSym['('] = lparen;
	OBSym[')'] = rparen;
	OBSym['='] = eql;
	OBSym[','] = comma;
	OBSym[';'] = semicolon;
	OBSym['.'] = period;

	//清空扫描缓冲区
	for (i=0; i<SCANBUFF; i++)
	{
		scanbuffer[i] = '\0';
	}

	//清空符号表
	for (i=0; i<MAXSYMTAB; i++)
	{
		table[i].name[0] = '\0';
	}
}

///////////////////////////////以下是源程序输入模块//////////////////////////////////

///////////////////////功能:把从键盘输入程序代码存入文件data.c中。////////////////////

///////////////////////正常结束则返回TURE,非正常结束则返回ERROR。////////////////////

int InputData(void)
{
	char buffer[120];

	if ( !(fp_data=fopen("data.c", "wb")) )		//打开文件
	{
		printf ("cannot open file!");
		return ERROR;
	}

	while (1)
	{
		gets( buffer );					//从键盘接收字符串
		if ( !buffer[0] )	break;		//判断输入是否结束
		fputc('\n', fp_data);			//在文件中输入换行符
		fputs(buffer, fp_data);			//将字符串输入文件
		
	}
	fclose(fp_data);

	return OK;
}


/////////////////////////////////////以下是词法分析模块///////////////////////////////////

////////////功能:从文件Data.c中读取源程序,经词法分析器分析后产生用二元式表示的单词符号串。

///////////将该二元式序列存入文件TwoElem.c中。词法分析器在一边读取数据时,要一边填写符号表。

///////将符号表存入文件SymTable.c中。并根据用户的要求,决定是否输出TwoElem和SymTable中的值。

//////返回值为TURE表示源程序经分析后没错,若为ERROR则表示源程序有错,并打印错误类型和行号

int AccidAnaly(void)
{
	int ErrorNum=0;			//错误类型号
	int ErrorFlag=TRUE;		//错误标识  OK表示无错,ERROR表示有错
//-------------------------------------------------------------------
	if (!(fp_data=fopen("data.c", "rb")))	//打开文件data.c
	{
		printf ("cannot open file!");
		return ERROR;
	}
	fgetc(fp_data);				//过滤掉第一个换行符
//-------------------------------------------------------------------
	if (!(fp_TwoElem=fopen("TwoElem.c", "wb")))	//打开文件TwoElem.c
	{
		printf ("cannot open file!");
		return ERROR;
	}
//-------------------------------------------------------------------
	while ( ErrorNum=GetSym() )
	{
		if ( !(Error(ErrorNum)) )	//如果单词符号获取有错,则调用出错处理程序
		{
			ErrorFlag = ERROR;
		}
		if ( ErrorNum==4 )			//无结束符.
		{
			return ERROR;
		}
		ch =' ';
	}
//-------------------------------------------------------------------
	fclose(fp_data);			//关闭源程序文件
	fclose(fp_TwoElem);			//关闭二元式文件

	return ErrorFlag;
}

int GetSym(void)
{
	//获得一个单词符号,返回值为0表示源程序分析结束,为1表示没错,>1表示出错类型号
	
	int ErrorNum=TRUE;
	
	while ( ch==' ')
	{
		ErrorNum = Getch();			//获得一个非空字符
		if (ErrorNum!=OK)	
			return ErrorNum;
	}

	if ( (('A'<=ch)&&(ch<='Z')) || (('a'<=ch)&&(ch<='z')) )
	{
		ErrorNum = state_CharStr();				//进入基本字标识符处理状态
		ch = ' ';
	}
	else if ( ('0'<=ch)&&(ch<='9') )
	{
		ErrorNum = state_Number();				//进入常数处理状态
	}
	else if ( (ch=='+') || (ch=='-') || (ch=='*') || (ch=='/') || (ch=='=') ||
			  (ch==':') || (ch=='(') || (ch==')') || (ch==',') || (ch==';') || (ch=='.'))
	{
		ErrorNum = state_OptBoud();				//进入运算符界符处理状态
	}
	else if ( ch=='	' )
	{
	}
	else
	{
		ErrorNum = 5;							//否则置出错类型号5
	}

	return ErrorNum;
}

int Getch(void)
{
	//从扫描缓冲区中获得一个非空字符,返回值为OK表示正常返回,否则为错误类型号

	if ( scanbuffer[start] == '\n' || scanbuffer[start] == '\0')
	{
		if ( feof(fp_data) )
		{
			printf("\n	文件已空!");
			return 4;			//错误类型号4,无结束符号
		}
		else
		{
			fgets(scanbuffer, 120, fp_data);	//从文件fp_data中读取一行字符到扫描缓冲区
			line++;				//行数增一
			start = 0;			//置扫描指针
		}
	}
	else
	{
		ch = scanbuffer[start];
		start++;
	}

	return OK;
}

int state_CharStr()			//基本字和标示符处理
{
	int i=0;
	int Adr=0;
	int error=OK;

	token[i++] = ch;
	while ( (('A'<=scanbuffer[start])&&(scanbuffer[start]<='Z')) || 
			(('a'<=scanbuffer[start])&&(scanbuffer[start]<='z')) ||
			(('0'<=scanbuffer[start])&&(scanbuffer[start]<='9')) )
	{
		if ( i<MAXSYMNUM ) 
		{
			token[i++] = scanbuffer[start++];
		}
		else
		{
			start++;
		}
	}
	token[i] = '\0';

	for (i=0; i<KEYWORDS; i++)			//判断是否为关键字
	{
		if ( !(strcmp(KeyWord[i], token)) )		break;
	}

	if ( i<KEYWORDS )
	{
		BackUp = KwSym[i];
		SaveTElem( KwSym[i], 0 );
	}
	else
	{
		error = LoadTable( &Adr );
		if ( OK == error )
		{
			SaveTElem( ident, Adr );
		}
		else
		{
			//Error( error ); 
			return ERROR;
		}
	}

	return OK;
}

int state_Number()			//常数处理
{
	int i=0;
	int error=OK;
	int Adr=0;

	token[i++] = ch;
	while ( ('0'<=scanbuffer[start])&&(scanbuffer[start]<='9') )
	{
		if ( i<4 ) 
		{
			token[i++] = scanbuffer[start++];
		}
		else
		{
			while ( ('0'<=scanbuffer[start])&&(scanbuffer[start]<='9') )	//跳过该字符
			{
				start++;
			}
			return 3;		//错误类型号3,越界
		}
	}
	token[i] = '\0';

	Num = IntegerConversion(0, --i);
	error = LoadTable( &Adr );
	if ( OK == error )
	{
		SaveTElem( number, Adr );
	}
	else
	{
	//	Error( error );
		return ERROR;
	}

	return OK;
}

int IntegerConversion(int begine, int end)			//整数转换
{
	int i;
	int temp=0;
	int integer=0;

	for(i=begine; i<=end; i++)
	{
		temp = token[i] - 48;
		integer = integer*10 +temp;
	}
	return integer;
}

int state_OptBoud()			//运算符界符处理
{
	if ( (ch=='+') || (ch=='-') || (ch=='*') || (ch=='/') || (ch=='=') ||
		 (ch=='(') || (ch==')') || (ch==',') || (ch==';') )
	{
		SaveTElem( OBSym[ch], 0);
//		if (ch==';')	BackUp = nul;
	}
	else if (ch==':')
	{
		if ( scanbuffer[start] != '=' )
		{
			return 2;		//错误类型号2
		}
		else
		{
			start++;
			SaveTElem( evaluate, 0 );
		}
	}
	else					//.
	{
		return 0;
	}

	return OK;
}

int SaveTElem(enum Symbol Sym, int adr)			//将二元式存入文件TwoElem.c中
{
	TElem telem;

//	printf("\n%d, %d", Sym, adr);
	telem.category = Sym;
	telem.adr = adr;

	fwrite(&telem, sizeof(TElem), 1, fp_TwoElem);

	return OK;
}

int Error(int ErrorNum)		//出错处理函数
{
	switch (ErrorNum)
	{
	case OK:
		return OK;
		break;
	case 2:
		printf("\n第%d行的赋值运算符错误!", line);
		break;
	case 3:
		printf("\n第%d行的数值越界!", line);
		break;
	case 4:
		printf("\n源程序没有结束符号!", line);
		break;
	case 5:
		printf("\n第%d行引入了非法字符!", line);
		break;
	case 6:
		printf("\n第%d行的某一标识符不能识别!", line);
		break;
	case 7:
		printf("\n源程序中已经存在该过程名!");
		break;
	case 8:
		printf("\n源程序中存在不可知错误!");
		break;
	default:
		break;
	}
	return ERROR;
}

void PrintTElem(void)		//打印二元式序列
{
	TElem telem;

	if ( !(fp_TwoElem=fopen("TwoElem.c", "rb")) )		//打开文件
	{
		printf ("cannot open file!");
	}

	while ( !feof(fp_TwoElem) )
	{
		fread(&telem, sizeof(TElem), 1, fp_TwoElem);
		printf("\n%d,	%d", telem.category , telem.adr);
	}

	fclose(fp_TwoElem);
}

int LoadTable(int* AAdr)			//登录符号表
{	
	//如果登录成功则返回OK,否则返回错误类型号
	if (BackUp == nul)
	{
		return 6;
	}
	else if ( (BackUp == constsym) || (token[0]>='0' && token[0]<='9'))			//常量处理
	{
		return ( DealConst(AAdr) );
	}
//	else if (BackUp == varsym)				//变量处理
//	{
//		return ( DealVar(AAdr) );
//	}
	else if (BackUp == procsym)				//变量处理		
	{
		return ( DealProc(AAdr) );
	}
//	else
//	{
//		return 8;
//	}
	else
	{
		return ( DealVar(AAdr) );
	}

}

int DealConst(int* AAdr)
{
	//参数AAdr所指的单元内容作常量在符号表的地址返回,返回值OK表示正常结束,否则为出错类型号
	if ( token[0]>='0' && token[0]<='9' )
	{
		table[backp].value = Num ;
	}
	else
	{
		strcpy(table[backp].name, token);
		table[backp].kind = constsym;
		Ptable++;
	}

	table[backp].Adr = 0;
	table[backp].level = 0;

	*AAdr = backp;
	return OK;
}

int DealVar(int* AAdr)
{
	//参数AAdr所指的单元内容作变量在符号表的地址返回,返回值OK表示正常结束,否则为出错类型号
	int i=0;

	for (i=0; i<Ptable; i++)
	{
		if ( !strcmp(table[i].name, token) )	break;
	}

	if ( i<Ptable )
	{
		backp = i;
		*AAdr = backp;
	}
	else
	{
		table[Ptable].kind = varsym;
		table[Ptable].level = level;
		strcpy(table[Ptable].name, token);
		table[Ptable].value = 0;
		*AAdr = Ptable;
		backp = Ptable++;
	}
	return OK;
}

int DealProc(int* AAdr)
{
	//参数AAdr所指的单元内容作过程名在符号表的地址返回,返回值OK表示正常结束,否则为出错类型号
	int i=0;

	for (i=0; i<Ptable; i++)
	{
		if ( !strcmp(table[i].name, token) )	break;
	}

	if ( i<Ptable )
	{
		return 7;
	}
	else
	{
		table[Ptable].kind = procsym;
		table[Ptable].level = level;
		strcpy(table[Ptable].name, token);
		table[Ptable].size = 5;
		level++;
		*AAdr = Ptable;
		backp = ++Ptable;
	}
	return OK;
}

void PrintTable(void)		//打印符号表
{
	int i=0;

	for (i=1; i<Ptable; i++)
	{
		puts( table[i].name );
		printf( "	%d	%d	%d	%d	%d \n", table[i].kind, table[i].value, table[i].level, table[i].Adr,table[i].size);
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -