编译原理 预测分析 源代码c 语言

原文链接:

https://blog.csdn.net/gj_007/article/details/79587673

本文对了原贴代码做了如下改变和改进:
1.文法变为如下:

在这里插入图片描述
2.当分析字符串为空时,若栈内不为空仍可继续判断栈内字符是否可为空从而接受该字符串
3.出错信息显示,哪个字符无法匹配
4.注释命名更加清晰
注:预测分析表手动填写,非程序计算得来,这样很局限但是简单

代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<dos.h>

char analyse[10];	//分析栈
char remain[10];	//剩余串
char vt[10] = { '+','-','~','*','/','(',')','i','#'};//终结符
char vn[10] = { 'E','G','T','S','F' };				//非终结符
typedef struct shiZi				//产生式
{
	char begin;						//左边字符 
	char array[5];					//右边字符串 
	int length;						//右边字符个数
}shiZi;
shiZi e, t, g2, g3, g1, s2, s3, s1, f2, f1; //10个产生式 
shiZi table[10][10];	//定义预测分析表

void printStack();	//输出分析栈
void printRemain();	//输出剩余串

int j = 0, b = 0, top = 0;	
int l;				//l为输入串长度

int main(){ 
	int m, n, k = 0, flag = 0, finish = 0;
	char ch, x;
	shiZi now;   //目前使用的产生式 
	e.begin = 'E';
	strcpy(e.array, "TG");
	e.length = 2;
	g1.begin = 'G';
	strcpy(g1.array, "+TG");
	g1.length = 3;
	g2.begin = 'G';
	strcpy(g2.array, "-TG");
	g2.length = 3;
	g3.begin = 'G';
	g3.array[0] = '~'; 
	g3.length = 1;
	t.begin = 'T';
	strcpy(t.array, "FS");
	t.length = 2;
	s1.begin = 'S';
	strcpy(s1.array, "*FS");
	s1.length = 3;
	s2.begin = 'S';
	strcpy(s2.array, "/FS");
	s2.length = 3;
	s3.begin = 'S';
	s3.array[0] = '~'; 
	s3.length = 1;
	f1.begin = 'F';
	strcpy(f1.array, "(E)");
	f1.length = 3;
	f2.begin = 'F';
	f2.array[0] = 'i';
	f2.length = 1;
	
	//初始化分析表
	for (m = 0; m <= 4; m++)
		for (n = 0; n <= 8; n++)
			table[m][n].begin = 'n';
						
	//手动填写分析表
	table[0][5] = e; table[0][7] = e;
	table[1][0] = g1; table[1][1] = g2; table[1][2] = table[1][6] = table[1][8] = g3;
	table[2][5] = t; table[2][7] = t;
	table[3][0] = table[3][1] = table[3][2] = table[3][8] = s3; table[3][4] = s2; table[3][3] = s1; 
	table[4][5] = f1; table[4][7] = f2;
	
	printf("请输入要分析的字符串(以'#'结尾):");
	//读入字符串 
	do
	{
		scanf("%c", &ch);
		if ((ch != 'i') && (ch != '+') && (ch != '*') && (ch != '(') && (ch != ')') && (ch != '/') && (ch != '#'))
		{
			printf("输入串中有非法字符\n");
			exit(1);
		}
		remain[j] = ch;
		j++;	//字符串长度
	}while (ch != '#');
	
	l = j;
	ch = remain[0];	//当前字符
	analyse[top] = '#';
	analyse[++top] = 'E';	//文法开始符号'E'进栈 
	printf("步骤\t\t分析栈\t\t剩余字符\t\t所用产生式\n");
	
	do{
		x = analyse[top--];//当前栈顶字符
		printf("%d", k++);
		printf("\t\t");
		
		for (j = 0; j <= 8; j++)
			if (x == vt[j])		//如果是终结符
			{
				if (x == '#' && ch != '#'){  //没有输入字符但栈内仍有字符 ,则继续判断栈内字符是否可为空 
					flag = 0;
					break;
				}
				else{						
					flag = 1;	//进入终结符的判断 
					break;
				}				
			}
		if (flag == 1)
		{
			if (x == '#' && ch == '#')
				finish = 1;//结束
			if (x == ch){
				printStack();
				printRemain();
				if(x == '#' && ch == '#'){   //特殊情况,栈内、字符串全为'#'
					printf("结束\n\n");	
					printf("合法字符串!");
				}									
				else{	//其他情况:字符匹配 
					printf("%c匹配\n", ch);
				ch = remain[++b];  //next字符 
				flag = 0; 
				}									
			}
			else{ 
				printStack(); 
				printRemain();
				printf("%c无法匹配\n\n", ch);/*输出出错终结符*/
				printf("非法字符串!"); 
				
				exit(1); 
			}	
		}
		
		else{					//非终结符
			for (j = 0; j <= 4; j++)
				if (x == vn[j])
				{
					m = j;      //分析表中匹配某一非终结符,行 
					break;
				}
			for (j = 0; j <= 8; j++)
				if (ch == vt[j])
				{ 
					n = j;		//分析表中匹配某一字符,列 
					break;
				}
				
			now = table[m][n];
			
			if (now.begin != 'n')	//有产生式 
			{
				printStack();
				printRemain();
				
				printf("%c->", now.begin); //输出所用的产生式
				for (j = 0; j<now.length; j++)
					printf("%c", now.array[j]);
				printf("\n");
				
				for (j = (now.length - 1); j >= 0; j--) //产生式逆序入栈
					analyse[++top] = now.array[j];
				if (analyse[top] == '~')	//为空则不进栈
					top--;     //指向下一个字符 
			}
			
			else{
				printStack();
				printRemain();
				printf("%c无法匹配\n", x);	//输出无法匹配的非终结符
				printf("非法字符串!");
				
				exit(1);
			}		
		}
	}while (finish == 0);	
}

void printStack()
{
	int a;
	for(a=0; a <= top+1; a++)
		printf("%c", analyse[a]);   //输出栈内元素 
	printf("\t\t");
}

void printRemain()
{
	int j;
	for (j = 0; j<b; j++)
		printf(" ");	//对齐 
	for (j = b; j <= l; j++)
		printf("%c", remain[j]); 	//输出剩余字符串 
	printf("\t\t\t");
}

运行示例:
在这里插入图片描述

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值