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

📄 ll1grammar.cpp

📁 编译原理部分代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
				first[len++] = '~';
				first[len] = '\0';
			}
		}
	}
	return first;
}
// 获取串的后继符号集合
char* LL1Grammar::FOLLOW(char ch)
{
	int i, j, pos, len;
	char *follow = new char[128];
	char *temp = new char[128];
	strcpy(follow, "\0");
	strcpy(temp, "\0");
	// 若遇见文法的开始符号则首先将'$'加入该非终结符的后继集合中
	if (grammar->production[0].left == ch)
	{
		strcat(follow, "$");
	}
	// 依次扫描文法中所有产生式看有没有形如"A->αBβ"、"A->αB"的匹配项,其中B是该函数的形参
	for (i=0; i<grammar->grammarSize; i++)
	{
		// 若该非终结符在某个产生式的右部则按相应规则计算后继集合
		pos = IsInString(grammar->production[i].right, ch);
		if (pos != -1)
		{
			// 将产生式右部该非终结符以右的字符串复制到临时数组
			strcpy(temp, "\0");
			len = 0;
			for (j=pos+1; grammar->production[i].right[j]!='\0'; j++)
			{
				temp[len++] = grammar->production[i].right[j];
			}
			temp[len] = '\0';
			// 若该非终结符已经在最右端则设置临时数组仅包含空字符'~'
			if (strlen(temp) == 0)
			{
				temp[0] = '~';
				temp[1] = '\0';
			}
			// 若产生式形如"A->αBβ",则把β的开始集合(空字符除外)加入B的后继集合
			strcat(follow, FIRST(temp));
			len = strlen(follow);
			for (j=0; j<len; j++)
			{
				if (follow[j] == '~')
				{
					follow[j] = follow[len-1];
					follow[len-1] = '\0';
					break;
				}
			}
			// 若产生式形如"A->αB",或者形如"A->αBβ"且空字符在β的开始集合中,且A不等于B,则把A的后继集合加入B的后继集合
			if ((IsInString(FIRST(temp), '~') >= 0) && (grammar->production[i].left != ch) )
			{
				strcat(follow, FOLLOW(grammar->production[i].left));
			}
		}
	}
	// 删除follow中重复的字符
	len = strlen(follow);
	for (i=0; i<len-1; i++)
	{
		for (j=i+1; j<len; j++)
		{
			if (follow[i] == follow[j])
			{		
				follow[j] = follow[len-1];
	    		follow[len-1] = '\0';
		    	len--;
			}
		}
	}
	return follow;
}
// 分别输出所有非终结符的开始集合
void LL1Grammar::PutFirst()
{
	int i, j, len = strlen(grammar->nonTerminal);
	char temp[128];
	cout << "\n所有非终结符的开始集合如下" << endl;
	for (i=0; i<len; i++)
	{
		temp[0] = grammar->nonTerminal[i];
		temp[1] = '\0';
		strcpy(temp, FIRST(temp));
		cout << "FIRST(" << grammar->nonTerminal[i] << "): ";
		for (j=0; temp[j]!='\0'; j++)
		{
			cout << temp[j] << " ";
		}
		cout << endl;
	}
}
// 分别输出所有非终结符的后继集合
void LL1Grammar::PutFollow()
{
	int i, j, len = strlen(grammar->nonTerminal);
	char temp[128];
	cout << "\n所有非终结符的后继集合如下" << endl;
	for (i=0; i<len; i++)
	{
		strcpy(temp, FOLLOW(grammar->nonTerminal[i]));
		cout << "FOLLOW(" << grammar->nonTerminal[i] << "): ";
		for (j=0; temp[j]!='\0'; j++)
		{
			cout << temp[j] << " ";
		}
		cout << endl;
	}
}
// 构造LL(1)文法的预测分析表
void LL1Grammar::MakePredictiveParsingTable()
{
	int i, j, row = strlen(grammar->nonTerminal), col = strlen(grammar->terminal);
	char *temp = new char[128];
	strcpy(temp, "\0");
	// 初始化预测分析表对象并为每个元素赋初始值-1
	mTable = new PredictiveParsingTable(row, col);
	for (i=0; i<row; i++)
	{
		for (j=0; j<col; j++)
		{
			mTable->table[i][j] = -1;
		}
	}
	// 由于'符号$'不在终结符数组中且不对应预测分析表中的列属性,则用空字符所在的列存放'$'的相关产生式,若空字符不在终结符数组中则新增一列,完成预测分析表的构造后在改空字符为'$'
	int pos = IsInString(grammar->terminal, '~');
	if (pos == -1)
	{
		pos = strlen(grammar->terminal);
	}
	// 循环分析每个产生式A->α,看它能被加到预测分析表的哪一格
	for (i=0; i<grammar->grammarSize; i++)
	{
		row = IsInString(grammar->nonTerminal, grammar->production[i].left);
		strcpy(temp, FIRST(grammar->production[i].right));
		// 对FIRST(α)中的每个终结符a,将A->α加入到M[A,a]中
		for (j=0; temp[j]!='\0'; j++)
		{
			// 空字符没有必要包含在预测分析表的列属性中
			if (temp[j] != '~')
			{
		     	col = IsInString(grammar->terminal, temp[j]);
		    	// 如果表格中已有产生式存在,则证明出错,结束程序
		    	if (mTable->table[row][col] >= 0)
				{
					cout << "\n在分析表的M[" << grammar->nonTerminal[row] << "," << grammar->terminal[col] << "]项中已有产生式" << grammar->production[mTable->table[row][col]].left << "->" << grammar->production[mTable->table[row][col]].right
						 << "\n和现在要添进M[" << grammar->nonTerminal[row] << "," << grammar->terminal[col] << "]的产生式" << grammar->production[i].left << "->" << grammar->production[i].right << "发生冲突";
		    		cout << "\n输入的文法不是LL(1)文法!" << endl;
		    		getch();
		    		exit(1);
				}
		    	mTable->table[row][col] = i;
			}
		}
		// 若空字符在FIRST(α)中,则对FOLLOW(A)中的每个终结符b以及$(若FOLLOW(A)包括$),将A->α加入到M[A,b]和M[A,$]中;
		if (IsInString(temp, '~') >= 0)
		{
			strcpy(temp, FOLLOW(grammar->production[i].left));
			for (j=0; temp[j]!='\0'; j++)
			{
				col = IsInString(grammar->terminal, temp[j]);
				if (temp[j] == '$')
				{
					col = pos;
				}
				// 如果表格中已有产生式存在,则证明出错,结束程序
				if (mTable->table[row][col] >= 0)
				{
					cout << 
			    	cout << "\n输入的文法不是LL(1)文法!" << endl;
			    	getch();
			    	exit(1);
				}
				mTable->table[row][col] = i;
			}
		}
	}
	// 用'$'替换终结符集合中的'~'或在终结符集合末尾加入'$'
	pos = IsInString(grammar->terminal, '~');
	if (pos >= 0)
	{
		grammar->terminal[pos] = '$';
	}
	else
	{
		int len = strlen(grammar->terminal);
		grammar->terminal[len++] = '$';
		grammar->terminal[len] = '\0';
	}
}
// 输出LL(1)文法的预测分析表
void LL1Grammar::PutPredictiveParsingTable()
{
	int i, j, k;
	cout << "\nLL(1)文法的预测分析表如下" << endl;
	// 声明整型变量productionLen和maxProductionLen来控制表格的输出格式
	int productionLen, maxProductionLen = 1;
	for (i=0; i<grammar->grammarSize; i++)
	{
		if (strlen(grammar->production[i].right) > (unsigned)(maxProductionLen))
		{
			maxProductionLen = strlen(grammar->production[i].right);
		}
	}
	maxProductionLen += 3;
	if (maxProductionLen%2 == 1)
	{
		maxProductionLen++;
	}
	cout << "━━━┯";
	int len = strlen(grammar->terminal)*maxProductionLen/2+strlen(grammar->terminal)-1;
	for (i=0; i<len; i++)
	{
		cout << "━";
	}
	cout << "\n 非终 │";
	len = (len * 2 - 8) / 2;
	for (i=0; i<len; i++)
	{
		cout << " ";
	}
	cout << "输入符号\n      ├";
	len = strlen(grammar->terminal) - 1;
	for (i=0; i<len; i++)
	{
		for (j=0; j<maxProductionLen/2; j++)
		{
			cout << "─";
		}
		cout << "┬";
	}
	for (j=0; j<maxProductionLen/2; j++)
	{
		cout << "─";
	}
	cout << "\n 结符 ";
	len++;
	for (i=0; i<len; i++)
	{
		cout << "│";
		for (j=0; j<maxProductionLen/2-1; j++)
		{
			cout << " ";
		}
		cout << grammar->terminal[i];
		for (j=0; j<maxProductionLen/2; j++)
		{
			cout << " ";
		}
	}
	cout << "\n───";
	for (i=0; i<len; i++)
	{
		cout << "┼";
		for (j=0; j<maxProductionLen/2; j++)
		{
			cout << "─";
		}
	}
	cout << endl;
	for (i=0; i<mTable->nonTerminalNum; i++)
	{
		cout << "  " << grammar->production[i].left << "   ";
		for (j=0; j<(int)(strlen(grammar->terminal)); j++)
		{
			cout << "│";
			if (mTable->table[i][j] >= 0)
			{
				productionLen = strlen(grammar->production[mTable->table[i][j]].right) + 3;
				cout << grammar->production[mTable->table[i][j]].left << "->" << grammar->production[mTable->table[i][j]].right;
				for (k=0; k<maxProductionLen-productionLen; k++)
				{
					cout << " ";
				}
			}
			else
			{
				for (k=0; k<maxProductionLen; k++)
				{
					cout << " ";
				}
			}
		}
		cout << endl;
	}
	cout << "━━━";
	for (i=0; i<len; i++)
	{
		cout << "┷";
		for (j=0; j<maxProductionLen/2; j++)
		{	
			cout << "━";
		}
	}
	cout << endl;
}
// 对输入的表达式进行预测分析
void LL1Grammar::DoPredictiveParsing()
{
	int i;
	// 声明变量pos记录输入串中当前字符的位置
	int pos = 0;
	// 声明变量productionNum记录调用的产生式的序号
	int productionNum = -1;
	// 声明变量row和col用来标识预测分析表中的产生式
	int row = -1, col = -1;
	// 接收输入并在字符串末尾加入符号'$'
	cout << "\n请输入一个表达式进行验证" << endl;
	cin >> input;
	strcat(input, "$");
	// 声明三个整形变量用来控制预测分析过程的输出格式
	int stackLen = 1, inputLen = 1, outputLen = 1;
	stackLen = strlen(grammar->nonTerminal) + strlen(input)/2;
	if (stackLen%2 == 1)
	{
		stackLen++;
	}
	if (stackLen < 4)
	{
		stackLen = 4;
	}
	inputLen = strlen(input);
	if (inputLen < 4)
	{
		inputLen = 4;
	}
	if (inputLen%2 == 1)
	{
		inputLen++;
	}
	for (i=0; i<grammar->grammarSize; i++)
	{
		if (strlen(grammar->production[i].right) > (unsigned)(outputLen))
		{
			outputLen = strlen(grammar->production[i].right);
		}
	}
	outputLen += 4;
	if (outputLen%2 == 1)
	{
		outputLen++;
	}
	// 建立一个栈对象,并将符号'$'和文法的开始符号压入
	LStack *stack = new LStack();
	stack->Push('$');
	stack->Push(grammar->production[0].left);
	cout << "\n文法的预测分析过程如下" << endl;
	for (i=0; i<stackLen/2; i++)
	{
		cout << "━";
	}
	cout << "┯";
	for (i=0; i<inputLen/2; i++)
	{
		cout << "━";
	}
	cout << "┯";
	for (i=0; i<outputLen/2; i++)
	{
		cout << "━";
	}
	cout << "\n 栈 ";
	for (i=0; i<stackLen/2-2; i++)
	{
		cout << "  ";
	}
	cout << "│输入";
	for (i=0; i<inputLen/2-2; i++)
	{
		cout << "  ";
	}
	cout << "│输出";
	for (i=0; i<outputLen/2-2; i++)
	{
		cout << "  ";
	}
	cout << endl;
	for (i=0; i<stackLen/2; i++)
	{
		cout << "─";
	}
	cout << "┼";
	for (i=0; i<inputLen/2; i++)
	{
		cout << "─";
	}
	cout << "┼";
	for (i=0; i<outputLen/2; i++)
	{
		cout << "─";
	}
	cout << endl;
	// 作以下分析直到栈只剩下'$'一个元素
	while ((stack->GetTop() != '$') && (input[pos] != '\0'))
	{
		cout << " ";
		int len = stack->BottomUp();
		for (i=0; i<stackLen-len-1; i++)
		{
			cout << " ";
		}
		cout << "│";
		len = strlen(input);
		PutSuffix(input, pos);
		if (len < 4)
		{
			for (i=0; i<4-len; i++)
			{
				cout << " ";
			}
		}
		cout << "│";
		if (productionNum >= 0)
		{
			cout << grammar->production[productionNum].left << "->" << grammar->production[productionNum].right;
		}
		cout << endl;
		if ((stack->GetTop() >= 'A') && (stack->GetTop() <= 'Z'))
		{
			// 从预测分析表中找出相应的产生式
			row = IsInString(grammar->nonTerminal, stack->GetTop());
			col = IsInString(grammar->terminal, input[pos]);
			if ((row == -1) || (col == -1))
			{
				for (i=0; i<stackLen/2; i++)
				{
					cout << "━";
				}
				cout << "┷";
				for (i=0; i<inputLen/2; i++)
				{
					cout << "━";
				}
				cout << "┷";
				for (i=0; i<outputLen/2; i++)
				{
					cout << "━";
				}
				cout << "\n输入的表达式与文法不符!" << endl;
				getch();
				exit(1);
			}
			productionNum = mTable->table[row][col];
			// 当栈顶是非终结符且在预测分析表中存在对应的产生式,则弹出栈顶让产生式右部逆序进栈,否则出错
			if (productionNum >= 0)
			{
				stack->Pop();
				int len = strlen(grammar->production[productionNum].right);
				for (i=len-1; i>=0; i--)
				{
					if (grammar->production[productionNum].right[i] != '~')
					{
						stack->Push(grammar->production[productionNum].right[i]);
					}
				}
			}
			else
			{
				for (i=0; i<stackLen/2; i++)
				{
					cout << "━";
				}
				cout << "┷";
				for (i=0; i<inputLen/2; i++)
				{
					cout << "━";
				}
				cout << "┷";
				for (i=0; i<outputLen/2; i++)
				{
					cout << "━";
				}
				cout << "\n预测分析失败!请检查错误!" << endl;
				getch();
				exit(1);
			}
		}
		else
		{
			productionNum = -1;
			// 当栈顶是终结符且与输入串的当前字符相同,则弹出栈顶并将输入串的当前字符位置向后移动一位,否则出错
			if (stack->GetTop() == input[pos])
			{
				stack->Pop();
				pos++;
			}
			else
			{
				for (i=0; i<stackLen/2; i++)
				{
					cout << "━";
				}
				cout << "┷";
				for (i=0; i<inputLen/2; i++)
				{
					cout << "━";
				}
				cout << "┷";
				for (i=0; i<outputLen/2; i++)
				{
					cout << "━";
				}
				cout << "\n预测分析失败!请检查错误!" << endl;
				getch();
				exit(1);
			}
		}
	}
	if (input[pos] == '$')
	{
		cout << " $";
		for (i=0; i<stackLen-2; i++)
		{
			cout << " ";
		}
		cout << "│";
		int len = strlen(input);
		PutSuffix(input, pos);
		if (len < 4)
		{
			for (i=0; i<4-len; i++)
			{
				cout << " ";
			}
		}
		cout << "│";
		if (productionNum >= 0)
		{
			cout << grammar->production[productionNum].left << "->" << grammar->production[productionNum].right;
		}
		cout << endl;
	}
	for (i=0; i<stackLen/2; i++)
	{
		cout << "━";
	}
	cout << "┷";
	for (i=0; i<inputLen/2; i++)
	{
		cout << "━";
	}
	cout << "┷";
	for (i=0; i<outputLen/2; i++)
	{
		cout << "━";
	}
	// 若输入的字符串中只剩下'$'一个字符时宣告成功,否则失败
	if (input[pos] == '$')
	{
		cout << "\n预测分析成功完成!" << endl;
	}
	else
	{
		cout << "\n预测分析失败!请检查错误!" << endl;
		getch();
		exit(1);
	}
	// 清空栈
	stack->Clear();
}

/////////////////////////////////////////////////

// 主函数
void main()
{
	int size;
	cout << "文法包含的产生式个数: ";
	cin >> size;
	LL1Grammar LL1(size);
	LL1.GetGrammar();
	LL1.PutGrammar();
	LL1.PutFirst();
	LL1.PutFollow();
	LL1.MakePredictiveParsingTable();
	LL1.PutPredictiveParsingTable();
	LL1.DoPredictiveParsing();
}

/*
ETP
P+TP|~
TFQ
Q*FQ|~
F(E)|d

SiEtSR|a
ReS|~
Eb

*/

⌨️ 快捷键说明

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