编译原理LL(1)文法分析程序的一种思路

编译原理LL(1)文法分析程序

First(X)集

其中X可以是终结符或非终结符组成的任意字符串或字符

  • 如果X是单个字符。
    1. 如果X是终结符。那么First(X) = {X};
    2. 如果X是非终结符。寻找满足X->ABC…N…,的推导式,则First(X)=First(ABC…N…)。
  • 如果X是字符串,即X=ABC…N…(这里的A、B、C、N等代表单个字符),那么求出First(A),如果First(A)中存在’ε’,继续求出First(B),若First(B)中仍存在’ε‘,继续求出First(C),直到存在一个First(N),满足First(N)中没有’ε‘。这时候,First(X)等于First(A)、First(B)…First(N)的去除’ε‘的并集。如果一直求到X的最后一个字符,都不存在这样的First(N),那么First(X)等于First(A)、First(B)…First(N)的并集(注意,这时First(X)中存在’ε‘)。

Follow(X)集

其中X代表一个非终结符。约定S代表文法的开始符号。
求Follow(X)时,在所有推导式中,寻找到形如A->…X…的式子。

  • 如果X是该式右部的最后一个元素,即A->…X。则Follow(X)=Follow(A)。
  • 否则,即存在形如A->…XB…的式子(B代表一个非终结符或终结符,或二者组成的字符串)。此时求出First(B),如果’ε‘不在First(B)中,则Follow(X)=First(B);如果’ε‘在First(B)中,则求出Follow(A),此时Follow(X)等于Follow(A)加上First(B)中去除’ε‘的所有元素。
  • 注意,求取Follow(S)时,将‘#’(输入串终结符)放入Follow(S)中,然后继续求取Follow(S)。(这里S代表文法开始符号)
    可以看出,在Follow集中是不可能存在’ε‘的,但是可能存在‘#’。

Select(X)集

获得Select集是定义First集和Follow集的目的,而获得Select集,是为了构建LL(1)分析表。
在求Select(X)中,X代表一个推导式,形如S->ABC…(其中A、B、C等代表一个字符,S是一个非终结符)。

  • 首先求First(ABC…),如果’ε‘不在First(ABC…)中,则Select(S->ABC…)=First(ABC…)。
  • 如果’ε‘在First(ABC…)中,则求Follow(S),这时Select(S->ABC…)等于Follow(S)加上First(ABC…)中不是‘ε’的元素。
  • 可以看出,在Select集中也不可能存在‘ε’。

代码实现如下

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <list>

using namespace std;

struct Production {//推导式结构体,同时实现了图的作用。
	char left;
	string right;
	vector<char> selectSet;//select集
};
vector<Production> production;//

vector<char> followStack;//加个栈,防止Follow()出现无限递归,实在没别的办法了。

bool isNonterminal(char para) {//判断字符是否为非终结符
	if (para >= 'A' && para <= 'Z')
		return true;
	return false;
}

bool isElementInVector(vector<char> v, char element) {//字符是否已经存在于容器中。
	vector<char>::iterator it;
	it = find(v.begin(), v.end(), element);
	if (it != v.end()) {
		return true;
	}
	else {
		return false;
	}
}

vector<char> getFirst(char right1) {
	vector<char> firstSet;
	for (int i = 0; i < production.size(); i++) {
		
			if (!isNonterminal(right1)) {// 对于终结符,直接加入first
				firstSet.push_back(right1);
				return firstSet;
			}
			
			else {
				int countEmpty = 0;//记录空的个数。
				if (production[i].left == right1) {
					for (int j = 0; j < production[i].right.length(); j++) {
						vector<char> buffer = getFirst(production[i].right[j]);
						vector<char>::iterator it = buffer.begin();
						for (it; it != buffer.end(); it++) {
							if (*it == '$')  // 遍历查看是否含有'$'(能产生空)
								++countEmpty;
							else if (!isElementInVector(firstSet, *it))
								firstSet.push_back(*it);//将非$加入FIRST(X)
						}
						if (countEmpty == 0)
							break;
					}
					if (countEmpty == production[i].right.length())//所有右部first(Y)都有$(空),将$加入FIRST(X)中
						firstSet.push_back('$');
				}
			}
	}
	return firstSet;
};

vector<char> getFollow(char left) {//求Follow(B)
	vector<char> followSet;

	if (is_element_in_vector(followStack, left))//如果在递归栈中已经存在了要求的元素,说明进入了无限递归,这时再求也没有意义,直接返回空集。
		return followSet;
	else
		followStack.push_back(left);


	if (left == production[0].left)//对文法开始符号S,置#于FOLLOW(S)中
		followSet.push_back('#');

	for (int i = 0; i < production.size(); i++) {
		for (int j = 0; j < production[i].right.length(); j++) {
			if (production[i].right[j] == left) {
				if (j + 1 == production[i].right.length() && production[i].left != left) {//A->aB,将Follow(A)加入Follow(B)
					vector<char> buffer1 = getFollow(production[i].left);
					vector<char>::iterator it = buffer1.begin();
					for (it; it != buffer1.end(); it++) {
						if (!is_element_in_vector(followSet, *it))
							followSet.push_back(*it);
					}
				}
				else {//A->aBC
					int countEmpty = 0;
					for (int k = j+1; k < production[i].right.length(); k++) {//将除去空集e的First(C)加入Follow(B)
						vector<char> buffer = getFirst(production[i].right[k]);
						vector<char>::iterator iter = buffer.begin();
						for (iter; iter != buffer.end(); iter++) {
							if (!is_element_in_vector(followSet, *iter) && *iter != '$')
								followSet.push_back(*iter);
						}
						if (is_element_in_vector(buffer, '$'))
							++countEmpty;
						else
							break;
					}

					if (countEmpty == production[i].right.length() - j - 1) {//若C=>*e,将Follow(A)加入Follow(B)中
						vector<char> buffer1 = getFollow(production[i].left);
						vector<char>::iterator it = buffer1.begin();
						for (it; it != buffer1.end(); it++) {
							if (!is_element_in_vector(followSet, *it))
								followSet.push_back(*it);
						}
					}
				}
				break;//防止 S->aAbAc这种出现。找右部第一个。
			}
		}
	}
	followStack.pop_back();
	return followSet;
};

void getSelect(Production& prod) {
	int countEmpty = 0;
	for (int i = 0; i < prod.right.length(); i++) {
		vector<char> buffer = getFirst(prod.right[i]);
		vector<char>::iterator iter = buffer.begin();
		for (iter; iter != buffer.end(); iter++) {
			if (!isElementInVector(prod.selectSet, *iter) && *iter != '$')
				prod.selectSet.push_back(*iter);
		}
		if (isElementInVector(buffer, '$'))
			++countEmpty;
		else
			break;
	}
	if (countEmpty == prod.right.length())
		prod.selectSet.push_back('$');
	if (isElementInVector(prod.selectSet, '$') ) {
		vector<char> buffer = getFollow(prod.left);
		prod.selectSet.insert(prod.selectSet.end(), buffer.begin(), buffer.end());
		vector<char>::iterator it = find(prod.selectSet.begin(), prod.selectSet.end(), '$');
		prod.selectSet.erase(it);
	}
};


void main() {
	string st;//输入串
	int is = 0;//串首指针
	list<char> stack;//比较的栈

	
	cout << "****************************************************************************" << endl;
	cout << "约定非终结符为大写字母 $代表空 #代表输入串结束。存在|符号的要分成两个式子写。" << endl;
	cout << "****************************************************************************" << endl;
	cout << "请分别输入文法的左部和右部。输入#结束。" << endl;
	cout << "****************************************************************************" << endl;
	char ch;
	while(cin>> ch){
		if (ch == '#')
			break;
		string st;
		cout << "->" ;
		cin >> st;
		cout << "输入下一条文法:" << endl;
		production.push_back({ ch,st });
	}
	
	cout << "****************************************************************************" << endl;
	cout << "LL1分析表:" << endl;
	cout << "****************************************************************************" << endl;

	for (int i = 0; i < production.size(); i++) {
		getSelect(production[i]);
	}
	cout << "左部----------" << "右部-----------" << "selcet集----------" << endl;
	for (int i = 0; i < production.size(); i++) {
		cout << production[i].left << "               " <<production[i].right << "               ";
		vector<char>::iterator iter = production[i].selectSet.begin();
		for (iter; iter != production[i].selectSet.end(); iter++)
			cout << *iter<<" ";
		cout << endl;
	}

	cout << "****************************************************************************" << endl;
	cout << "输入需要检测的串,以#结尾。" << endl;
	
	cin >> st;

	cout << "****************************************************************************" << endl;
	cout << "分析过程:" << endl;

	cout << "****************************************************************************" << endl;
	cout << "分析栈----------" << "当前串-----------" << "操作----------" << endl;
	stack.push_back('#');
	stack.push_back(production[0].left);

	do {
		if ((stack.back() == st[is]) && stack.back()!='#') {
			list<char>::iterator it; //输出栈
			for (it = stack.begin(); it != stack.end(); it++) {
				cout << *it;
			}
			cout << "               ";
			for (int i = is; i < st.length(); i++)
				cout << st[i];
			cout << "               " << st[is] << "匹配" << endl;
			++is;
			stack.pop_back();
		}
		else if (stack.back() == '#' && st[is] == '#') {
			cout << '#' << "               " << '#' << "               " << "接受";
			break;
		}
		else {
			int flag = 0;
			for (int i = 0; i < production.size(); i++) {
				if (stack.back() == production[i].left) {
					for (int j = 0; j < production[i].selectSet.size(); j++) {
						if (production[i].selectSet[j] == st[is]) {

							list<char>::iterator it; //输出栈
							for (it = stack.begin(); it != stack.end(); it++) {
								cout << *it;
							}
							cout << "               ";
							for (int i = is; i < st.length(); i++)//输出当前串
								cout << st[i];
							cout << "               ";

							cout << stack.back() << "->" << production[i].right << endl;

							stack.pop_back();

							if (production[i].right != "$") {
							for (int k = production[i].right.length() - 1; k >= 0; k--)//右部倒序入栈。
								stack.push_back(production[i].right[k]);
							}
							flag = 1;
							break;
						}
					}
				}
			}
			if (flag == 0) {
				cout << "文法错误," << stack.back()<<"与"<<st[is]<<"不匹配";
				break;
			}
		}	
	} while (1);
}

测试集如下

//其中’#'代表'ε'

//测试集一
    E->TA
	A->TA
	A->$
	T->FB
	B->FB
	B->$
	F->(E)
	F->i
//输入串:i+i*i#

//测试集二
	S->aA
	S->d
	A->bAS
	A->$
//输入串:abbad#
	
//测试集三
	S->AaS
	S->BbS
	S->d
	A->a
	B->$
	B->c
//输入串:aacbd#
	

测试结果
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
任良武别学了,学不会的。

©️2020 CSDN 皮肤主题: 游动-白 设计师:上身试试 返回首页