实验一:first集与follow集

Thisarticlecoversthedefinition,computationmethods,andprogrammingimplementationoffirstandfollowsetsincontext-freegrammars,withafocusontheconceptsandaC++codesnippetdemonstratingtheprocess,referringtoPrinciplesofCompilerDesign.
摘要由CSDN通过智能技术生成

  • 实验目的
  1. 了解上下文无关文法中的first集合与follow集合的定义。
  2. 掌握计算first集合与follow集合的方法,编程实现算法并验证。
  3. 理解求解first集合与follow集合的意义。
  • 实验预备知识
  1. 理解first集合与follow集合的定义。
  2. 参考配套教材《编译原理》集合求解原理与方法。
#include <fstream>
#include<iostream>
#include<string>
#include<vector>
#include<set>
#include<unordered_map>
using namespace std;

typedef string  variable;//变量
typedef string  terminal;//终结符
typedef string  start;//开始符号

typedef struct production//产生式
{
	string left;
	vector<string> right;//将右部的产生式按照每一个变量和每一个终结符分割放入右部数组
}proudction;

typedef struct grammar
{
	set<variable> V;//变量集合
	set<terminal> T;//终结符集合
	vector<production> P;//产生式
	start S;//开始符号
	unordered_map<variable, set<terminal>>FIRST;//FIRST集合
	unordered_map<variable, set<terminal>>FLLOW;//FLLOW集合
}grammar;

int split(vector<production>& pro, string s)//分割字符串取出产生式左部和右部
{
	production p;
	int i = 0;
	int spLR = -1;
	for (i; i < s.size() - 1; i++)
	{
		if (s[i] == '-' && s[i + 1] == '>')
		{
			spLR = i;
			break;
		}
	}
	if (i == 0 || i >= s.size())
	{
		cout <<endl<< "这个产生式"<<s<<"错误!!!请重新输入";
		return -1;
	}
	p.left = s.substr(0, i);
	s.erase(0, i + 2);

	p.right.push_back("");
	for (i = 0; i < s.size(); i++)
	{
		if (s[i] == '|')
		{
			if (p.right[0].size() == 0)
			{
				p.right[0] = "$";
			}
			pro.push_back(p);
			p.right[0] = "";
		}
		else
		{
			p.right[0] = p.right[0] + s[i];
		}
	}
	if (p.right[0].size() == 0)
	{
		p.right[0] = "$";
	}
	pro.push_back(p);
	return 0;
}

int getV_PR_S(grammar &G)//获得文法的变量,获得开始符号,以一个变量和一个终结符为单位分割产生式的右部
{
	G.S = G.P[0].left;//获得开始符号
	for (int i = 0; i < G.P.size(); i++)//获得变量
	{
		G.V.insert(G.P[i].left);
	}
	//以单一变量或者终结符为单位分割产生式右部
	for (int i = 0; i < G.P.size(); i++)
	{
		string s = G.P[i].right[0];//获得此时的产生式
		G.P[i].right.clear();//清空产生式右部分
		if (s == "$")//如果此时的产生式本身就是空的话把$加入右部之后直接进入下一次循环
		{
			G.P[i].right.push_back("$");
			continue;
		}
		int flag = 0;
		while (flag != 1)
		{
			flag = 1;
			int x = s.size();
			for (auto j = G.V.begin(); j != G.V.end(); j++)//先用变量集合去匹配
			{
				string v = *j;
				if (v.size() > s.size())//如果此时变量长度大于字符长度了就匹配下一个变量
				{
					continue;
				}
				string prfv = s.substr(s.size()-v.size(), v.size());
				//cout <<v<<":" << prfv;
				if (v == prfv)
				{
					G.P[i].right.insert(G.P[i].right.begin(), v);
					//cout << G.P[i].right[0] << " ";
					s.erase(s.size() - v.size());
				}
				//cout << endl;
				
			}
			
			for (auto j = G.T.begin(); j != G.T.end(); j++)//再用终结符集合去匹配
			{
				string t = *j;
				if (t.size() > s.size())//如果此时终结符长度大于字符长度了就匹配下一个终结符
				{
					continue;
				}
				string prft = s.substr(s.size()-t.size(), t.size());
				//cout << t << ":" << prft;
				if (t == prft)
				{
					G.P[i].right.insert(G.P[i].right.begin(), t);
					//cout << G.P[i].right[0] << " ";
					s.erase(s.size() - t.size());
				}
				//cout << endl;
				
			}
			if (s.size() < x)
			{
				flag++;
			}
		}
		if (s.size() > 0)
		{
			cout << "产生式中出现了不是变量也不是终结符的变量";
			exit(0);
		}
	}
}

int showG(grammar &G)
{
	cout << "\n\n终结符:";
	cout << endl<<"\t";
	for (auto i = G.T.begin(); i != G.T.end(); i++)
	{
		cout << *i << " ";
	}
	cout << "\n\n变量:";
	cout << endl<<"\t";
	for (auto i = G.V.begin(); i != G.V.end(); i++)
	{
		cout << *i << " ";
	}
	cout << "\n\n产生式:";
	cout << endl;
	for (int i = 0; i < G.P.size(); i++)
	{
		cout <<"\t" << G.P[i].left << "->";
		for (int j = 0; j < G.P[i].right.size(); j++)
		{
			cout<< G.P[i].right[j];
		}
		cout << endl;
	}
	cout << "\nFIRST集:";
	cout << endl;
	for (auto i = G.FIRST.begin(); i != G.FIRST.end(); i++)
	{
		cout << "\tFIRST(" << i->first << "):\t{ ";
		auto s = i->second.begin();
		s++;
		for (auto j = i->second.begin(); j != i->second.end(); j++)
		{
			cout << *j;
			if (s != i->second.end())
			{
				cout << ",";
				s++;
			}
		}
		cout << " }\n";
	}
	cout << "\nFOLLOW集:";
	cout << endl;
	for (auto i = G.FLLOW.begin(); i != G.FLLOW.end(); i++)
	{
		cout << "\tFOLLOW(" << i->first << "):\t{ ";
		auto s = i->second.begin();
		s++;
		for (auto j = i->second.begin(); j != i->second.end(); j++)
		{
			cout << *j;
			if (s != i->second.end())
			{
				cout << ",";
				s++;
			}
		}
		cout << " }\n";
	}
	return 0;
}

int getFIRST(grammar &G)
{
	//1.显式规则1
	int n = G.P.size();
	for (int i = 0; i < n; i++)
	{
		if (G.P[i].right.size() == 1&&G.P[i].right[0]=="$")
		{
			G.FIRST[G.P[i].left].insert("$");
		}
	}
	//2.显式规则2
	for (int i = 0; i < n; i++)
	{
		string s=G.P[i].right[0];
		if (G.T.find(s) != G.T.end())
		{
			G.FIRST[G.P[i].left].insert(s);
		}
	}
	//3.隐式规则1如果右边的第一个是变量的话把变量的first集合去空给first(左部)
	int flag = 0;
	while (flag != 1)
	{
		flag = 1;
		for (int i = 0; i < n; i++)
		{
			int num = G.FIRST[G.P[i].left].size();
			string s = G.P[i].right[0];
			if (G.V.find(s) != G.V.end())
			{
				set<terminal>se(G.FIRST[s]);
				se.erase("$");
				for (auto j = se.begin(); j != se.end(); j++)
				{
					G.FIRST[G.P[i].left].insert(*j);
				}
			}
			if (G.FIRST[G.P[i].left].size() > num)
			{
				flag++;
			}
		}
	}
	//4.隐式规则2和3
	flag = 0;
	while (flag != 1)
	{
		flag = 1;
		for (int i = 0; i < n; i++)
		{
			int num = G.FIRST[G.P[i].left].size();

			int m = G.P[i].right.size();
			int j = 0;
			for (; j < m; j++)
			{
				string s = G.P[i].right[j];
				if (G.V.find(s) != G.V.end() && G.FIRST[s].find("$") != G.FIRST[s].end())//这里是变量能推出来空
				{
					set<terminal>se(G.FIRST[s]);
					se.erase("$");
					for (auto j = se.begin(); j != se.end(); j++)
					{
						G.FIRST[G.P[i].left].insert(*j);
					}
				}
				else if (G.V.find(s) != G.V.end())//这里是变量不能推出来空
				{
					set<terminal>se(G.FIRST[s]);
					for (auto j = se.begin(); j != se.end(); j++)
					{
						G.FIRST[G.P[i].left].insert(*j);
					}
					break;
				}
				else//这里是终结符的FIRST集
				{
					G.FIRST[G.P[i].left].insert(s);
					break;
				}
			}
			if (j == m)
			{
				G.FIRST[G.P[i].left].insert("$");
			}
			if (G.FIRST[G.P[i].left].size() > num)
			{
				flag++;
			}
		}
	}
	//所有的终结符的first集是自己
	for (auto i = G.T.begin(); i != G.T.end(); i++)
	{
		G.FIRST[*i].insert(*i);
	}
	return 0;
}

int getFLLOW(grammar &G)
{
	//1.显式规则
	G.FLLOW[G.S].insert("#");
	//2.显式规则
	for (int i = 0; i < G.P.size(); i++)
	{
		for (int j = 0; j < G.P[i].right.size()-1; j++)
		{
			if (G.V.find(G.P[i].right[j]) != G.V.end()&&G.T.find(G.P[i].right[j+1])!=G.T.end())
			{
				G.FLLOW[G.P[i].right[j]].insert(G.P[i].right[j + 1]);
				j++;
			}
		}
	}
	//3.隐式规则
	int flag = 0;
	while (flag != 1)
	{
		flag = 1;
		vector<int>flag1(G.V.size());
		int x = 0;
		for (auto vv = G.V.begin(); vv != G.V.end(); vv++,x++)
		{
			flag1[x] = G.FLLOW[*vv].size();
		}
		//cout << "***";
		//隐式规则1
		for (int i = 0; i < G.P.size(); i++)
		{
			int j = 0;
			for (; j < G.P[i].right.size()-1; j++)
			{
				string s = G.P[i].right[j];
				if (G.V.find(s) != G.V.end())//此时的必须是变量
				{
					//把下一个字符的first集去空给这个变量的follow集
					set<terminal>se(G.FIRST[G.P[i].right[j+1]]);
					if (se.find("$") != se.end())//如果此时后面的量的first集有空$
					{
						se.erase("$");
						for (auto seb = se.begin(); seb != se.end(); seb++)
						{
							G.FLLOW[s].insert(*seb);
						}
						set<terminal>se1(G.FLLOW[G.P[i].right[j + 1]]);
						for (auto se1b = se1.begin(); se1b != se1.end(); se1b++)
						{
							G.FLLOW[s].insert(*se1b);
						}
					}
					else
					{
						se.erase("$");
						for (auto seb = se.begin(); seb != se.end(); seb++)
						{
							G.FLLOW[s].insert(*seb);
						}
						//break;
					}
				}
			}

			if (j == G.P[i].right.size() - 1 && G.V.find(G.P[i].right[j]) != G.V.end())//如果此时已经走到右部末尾了且最后一个还是变量那就要把左部的follow集给这个变量了
			{
				for (auto f = G.FLLOW[G.P[i].left].begin(); f != G.FLLOW[G.P[i].left].end(); f++)
				{
					G.FLLOW[G.P[i].right[j]].insert(*f);
				}	
			}
		}

		x = 0;
		for (auto vv = G.V.begin(); vv != G.V.end(); vv++, x++)
		{
			if (flag1[x] != G.FLLOW[*vv].size())
			{
				flag++;
				break;
			}
		}
	}
	return 0;
}

int main()
{
	ifstream infile;
	infile.open("production.txt");
	grammar G;
	string s;
	infile >> s;
	//cin >> s;
	cout << "请先输入终结符(输入stop表示终结符输入完成):\n";
	while (s != "stop")
	{
		G.T.insert(s);
		infile >> s;
		//cin >> s;
	}
	cout << "\n请输入产生式(输入stop表示产生式输入完毕):\n";
	infile >> s;
	//cin >> s;
	while (s != "stop")
	{
		split(G.P, s);
		infile >> s;
		//cin >> s;
	}
	getV_PR_S(G);
	getFIRST(G);
	getFLLOW(G);
	showG(G);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值