C++实现first集follow集

1.“@”代替字符“ε”
2.同一非终结符如有多条产生式必须写成一行,中间用“|”分隔,不允许有空格
代码存在很多问题,大量“非正常”情况都未考虑,谨慎参考

#include<iostream>
#include<vector>
#include<string>
#include<fstream>

using namespace std;

struct exp{
	char ter;	//终结符 
	bool e = false;	//是否能产生空转(用@表示) 
	vector<string> nonter;	//非终结符 
};
vector<exp> v;	//产生式集合 

string T = "";	//终结符集合 
string first[20];	//所有非终结符的first集 
string f ="";	//follow集 

//将文件中的文法转换成产生式 
void fun1(string str){
	exp e;
	e.ter = str[0];
	int i = 3;
	for(int k = i;k <str.length();k++){
		if(str[k] == '|'){
			e.nonter.push_back(str.substr(i,k-i));
			i = k + 1;
		} else if(str[k] == '@'){
			e.e = true;		//存在@(即空转) 
			i = k + 2;
			k++;
		}
	}
	if(i < str.length()){
		e.nonter.push_back(str.substr(i));
	}
	
	v.push_back(e);
	T = T + str[0];
}

//求first集 
void fun3(int p,exp e,int index){
	for(int k = 0;k < e.nonter.size();k++){
		for(int i = index;i < e.nonter[k].length();i++){
			if(e.nonter[k][i] >= 'a'&&e.nonter[k][i] <= 'z'){
				first[p] += e.nonter[k][i];
				break;
			} else if(e.nonter[k][i] >= 'A'&&e.nonter[k][i] <= 'Z'){
				int j = T.find(e.nonter[k][i]);
				if(v[j].e){
					fun3(p,v[j],0);
					first[p] += '@';
				}else{
					fun3(p,v[j],0);
					break;
				}
			}
		}
	}
	
}
void fun2(){
	for(int i = 0;i < v.size();i++){
		exp e = v[i];
		fun3(i,e,0);
	}
}

//求follow集 
void follow(char a){
	for(int i = 0;i < T.length();i++){
		for(int k = 0;k < v[i].nonter.size();k++){
			if(v[i].nonter[k].find(a) != string::npos){
				int j = v[i].nonter[k].find(a);
				if(j == v[i].nonter[k].length()-1){
					follow(T[i]);
				} else if(j < v[i].nonter[k].length()-1){
					char p = v[i].nonter[k][j+1];
					if(p >= 'a' && p <= 'z'){
						f += p;
					} else{
						int m = 0;
						for(;m < T.length();m++){
							if(T[m] == p){
								f = first[m];
							}
						}	
						if(first[m].find('@') != string::npos){
							follow(T[i]);
						}
					}	
				}
			}
		}
	}
}

int main(){
	ifstream open("D:\\1.txt");
	string str;
	if(!open.is_open())
		cout<<"open file failed"<<endl;
	while(getline(open,str)){
		fun1(str);
	}
	open.close();
	fun2();
	cout<<"first集如下:"<<endl;
	for(int len = 0;len < T.length();len++){
		if(v[len].e){
			first[len] += '@';
		}
		cout<<T[len]<<": "<<first[len]<<endl;
	}
	cout<<"输入非终结符:"<<endl;
	char a;
	cin>>a;
	follow(a);
	if(T.find(a) != string::npos){
		f += '$';
	}
	string::iterator it;
	//除去@,因为follow集中不能有@(空转) 
    for (it = f.begin(); it < f.end(); it++)
    {
        if (*it == '@')
        {
            str.erase(it);
            it--;
        }
    }
	cout<<a<<"的follow集:"<<f<<endl;
	return 0;
}

在这里插入图片描述
在这里插入图片描述

  • 3
    点赞
  • 2
    评论
  • 16
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

©️2022 CSDN 皮肤主题:书香水墨 设计师:CSDN官方博客 返回首页

打赏作者

南小呗

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

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

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

打赏作者

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

抵扣说明:

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

余额充值