编译原理------C++实现求First集和Follow集

First集算法描述

1.若X->a…,则将终结符a放入First(X)中
2.若X->ε,则将ε放入First(X)中
3.若有X->Y1Y2Y3…Yk,则
(1)把First(Y1)去掉 ε后加入First(X)
(2)如果First(Y1)包含ε,则把First(Y2)也加入到First(X)中,以此类推,直到某一个非终结符Yn的First集中不包含ε
(3)如果First(Yk)中包含ε,即Y1~Yn都有ε产生式,就把ε加入到First(X)中

Follow集算法描述

1.对于文法开始符号S,把$加入到Follow(S)中
2.若有A->aBC,则将First(C)中除了ε之外的元素加入到Follow(B)(此处a可以为空)
3.若有A->aB或者A->aBC且ε属于first(C),则将Follow(A)加入到follow(B)中(此处a可以为空)
4.若有A->Bc,则直接将c加入follow(B)中
follow集中不含有空串ε

代码

代码说明

1.原产生式存于文件中
2.终结符只能用一个小写字母表示
3.产生式内不可以有空格
4.ε用#代替
5.代码没有实现消除左递归和二义性,所以产生式必须为消除左递归和二义性的
6.暂时看来代码没什么问题(可以准确求出first集和follow集),有问题请指正。

#include<iostream>
#include<string>
#include<set>
#include<map>
#include <Windows.h>
#include <fstream>

using namespace std;

/*
所有非终结符均为单个字符,#代表空串
E->TE'
E'->+TE'|#
T->FT'
T'->*FT'|#
F->(E)|i
*/

class FF {
public:
	string fileName = "productions.txt";
	set<string> productions;//产生式集合
	map<string, set<string>> split_productions;//分解后的产生式集合
	set<string> Vt;//终结符集合
	set<string> Vn;//非终结符集合
	map<string, set<string>> first;//First集
	map<string, set<string>> follow;//Follow集

	void init();//从文件读取产生式
	void splitProductions();//分解产生式
	void findVtAndVn();//获得终结符和非终结符
	bool isVn(string s);
	bool isVt(string s);
	set<string> getOneFirst(string s);//获得单个非终结符first集
	void getFirst();//获得所有非终结符first集
	void getFollow();//获得所有非终结符follow集
	void SSS();//求folloe集的步骤3
};

void FF::init() {
	string line;
	ifstream in(fileName);
	if (in) {
		//文法开始符号的follow集中放入$
		getline(in, line);
		productions.insert(line);
		follow[line.substr(0, 1)].insert("$");
		cout << line << endl;
		while (getline(in, line)) {
			productions.insert(line);
			cout << line << endl;
		}
	}
}
void FF::splitProductions() {
	int position = 0;
	for (set<string>::iterator it = productions.begin(); it != productions.end(); it++) {
		string temp = *it;
		for (int i = 0; i < temp.length(); i++) {
			position = temp.find("->");
			string s = temp.substr(0, position);
			string ss = temp.substr(position + 2);
			set<string>sss;
			string t;
			for (int j = 0; j < ss.length(); j++) {
				if (ss[j] == '|') {
					sss.insert(t);
					t = "";
				}
				else
				{
					t.append(ss.substr(j,1));
				}
				
			}
			sss.insert(t);
			split_productions.insert(pair<string, set<string>>(s, sss));
		}
	}
	for (map<string, set<string>>::iterator it = split_productions.begin(); it != split_productions.end(); it++) {
		cout << it->first << "    ";
		for (set<string>::iterator ii = it->second.begin(); ii != it->second.end(); ii++) {
			cout << *ii << "    ";
		}
		cout << endl;
	}


}
void FF::findVtAndVn() {
	for (set<string>::iterator it = productions.begin(); it != productions.end(); it++) {
		string temp = *it;
		for (int i = 0; i < temp.length(); i++) {
			if (temp[i] == '-' || temp[i] == '>' || temp[i] == '|')
				continue;
			//是大写字母
			if (temp[i] >= 'A' && temp[i] <= 'Z') {
				//后面带'
				if (temp[i + 1] == '\'') {
					Vn.insert(temp.substr(i, 2));
					i++;
				}
				else {
					Vn.insert(temp.substr(i, 1));
				}
			}
			//是终结符
			else
			{
				Vt.insert(temp.substr(i, 1));
			}
		}
	}

	cout << "非终结符" << endl;
	for (set<string>::iterator it = Vn.begin(); it != Vn.end(); it++) {
		cout << *it << endl;
	}

	cout << "终结符" << endl;
	for (set<string>::iterator it = Vt.begin(); it != Vt.end(); it++) {
		cout << *it << endl;
	}
}
bool FF::isVn(string s) {
	if (Vn.find(s) != Vn.end()) {
		return true;
	}
	return false;
}
bool FF::isVt(string s) {
	if (Vt.find(s) != Vt.end()) {
		return true;
	}
	return false;
}
set<string> FF::getOneFirst(string s) {
	if (split_productions.count(s)>0) {
		set<string>temp = split_productions[s];
		for (set<string>::iterator it = temp.begin(); it != temp.end(); it++) {
			string stemp = *it;
			if (stemp == "#") {
				first[s].insert("#");
			}
			else {
				int flagAll = 0;//所有的非终结符的first集都有#;
				for (int i = 0; i < stemp.length(); i++) {
					int flag = 0;//当前的非终结符的first集有#;
					if (stemp[i+1] == '\'') {//带'的非终结符
						set<string>t1 = getOneFirst(stemp.substr(i, 2));
						for (set<string>::iterator ii = t1.begin(); ii !=  t1.end(); ii++) {
							if (*ii == "#") {//此时空串不可插入
								flag = 1;
							}
							else {
								first[s].insert(*ii);
							}
						}
						i++;
					}
					else if(isVn(stemp.substr(i,1)))//单个非终结符
					{
						set<string>t2 = getOneFirst(stemp.substr(i, 1));
						for (set<string>::iterator ii = t2.begin(); ii != t2.end(); ii++) {
							if (*ii == "#") {//此时空串不可插入
								flag = 1;
							}
							else {
								first[s].insert(*ii);
							}
						}
					}
					else {//终结符
						first[s].insert(stemp.substr(i, 1));
					}
					if (i == stemp.length() - 1 && flag==1) {
						flagAll = 1;
					}
					if (flag == 0)
						break;

				}
				if (flagAll == 1) {
					first[s].insert("#");
				}
			}
		}
	}
	return first[s];
}
void FF::getFirst() {
	for (map<string, set<string>>::iterator it = split_productions.begin(); it != split_productions.end(); it++) {
		getOneFirst(it->first);
	}
	cout << "First集" << endl;
	for (map<string, set<string>>::iterator it = first.begin(); it != first.end(); it++) {
		cout << it->first << "  :  "  ;
		for (set<string>::iterator ii = it->second.begin(); ii != it->second.end(); ii++)
		{
			cout << *ii << "    ";
		}
		cout << endl;
	}

}
void FF::getFollow() {
	for (map<string, set<string>>::iterator it = split_productions.begin(); it != split_productions.end(); it++) {
		string left = it->first;
		set<string>right = it->second;
		for (set<string>::iterator ii = right.begin(); ii != right.end(); ii++) {
			string temp = *ii;
			
			for (int i = 0; i < temp.length(); i++) {
				if (isVt(temp.substr(i, 1))) {//终结符
					continue;
				}
				else if (i+1<temp.length()&&temp[i + 1] == '\'') {//带有’的非终结符
					if (isVt(temp.substr(i + 2, 1))) {//非终结符后面是终结符
						follow[temp.substr(i, 2)].insert(temp.substr(i + 2, 1));
						i++;
					}
					else {//非终结符后面是非终结符s
						//把后面非终结符的first集ff加入follow集中
						string s;
						if (i+3<temp.length()&& temp[i + 3] == '\'') {
							s = temp.substr(i + 2, 2);
						}
						else {
							s = temp.substr(i + 2, 1);
						}
						set<string> ff = first[s];
						for (set<string>::iterator nn = ff.begin(); nn != ff.end(); nn++) {
							if (*nn != "#")
								follow[temp.substr(i, 2)].insert(*nn);
						}
					}
				}
				else {//不带’的非终结符
					
					if (i+1<temp.length() && isVt(temp.substr(i + 1, 1))) {//非终结符后面是终结符
						follow[temp.substr(i, 1)].insert(temp.substr(i + 1, 1));
						i++;
					}
					else {//非终结符后面是非终结符s
						//把后面非终结符的first集ff加入follow集中
						string s;
						if (i+2<temp.length() && temp[i + 2] == '\'') {
							s = temp.substr(i + 1, 2);
						}
						else {
							s = temp.substr(i + 1, 1);
						}
						set<string> ff = first[s];
						for (set<string>::iterator nn = ff.begin(); nn != ff.end(); nn++) {
							if (*nn != "#")
								follow[temp.substr(i, 1)].insert(*nn);
						}
					}
				}
			}
		}
	}
	//这一个需要多进行几次,因为follow是不断增长的
	SSS();
	SSS();

	cout << "Follow集" << endl;
	for (map<string, set<string>>::iterator it = follow.begin(); it != follow.end(); it++) {
		cout << it->first << "  :  ";
		for (set<string>::iterator ii = it->second.begin(); ii != it->second.end(); ii++)
		{
			cout << *ii << "    ";
		}
		cout << endl;
	}
}
void FF::SSS() {
	for (map<string, set<string>>::iterator it = split_productions.begin(); it != split_productions.end(); it++) {
		string left = it->first;
		set<string>right = it->second;
		for (set<string>::iterator ii = right.begin(); ii != right.end(); ii++) {
			string temp = *ii;
			for (int j = temp.length() - 1; j > 0; j--) {
				string now;
				if (temp[j] == '\'') {
					now = temp.substr(j - 1, 2);
					j--;
				}
				else now = temp.substr(j, 1);
				if (isVt(now)) {//产生式最后是终结符
					break;
				}
				else {//产生式最后是非终结符
					set<string>aa = follow[left];
					for (set<string>::iterator pp = aa.begin(); pp != aa.end(); pp++) {
						follow[now].insert(*pp);
					}
				}
				if (first[now].find("#") == first[now].end())
					break;
			}
		}
	}
}
int main() {
	FF ff;
	ff.init();
	ff.splitProductions();
	ff.findVtAndVn();
	ff.getFirst();
	ff.getFollow();
}
©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页

打赏作者

ooopig

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值