大连理工大学第3次上机—求first集合(cpp实现)

目的:熟练掌握自上而下的语法分析方法,并能用程序实现。

 

要求

例如. 使用的文法如下:

  1. E->TE'
  2. E'->+ TE'| #
  3. T->FT '
  4. T'->*FT'|#
  5. F->(E)|id

编写First函数,实现其求解过程。

提示:

  1. 非终结符为 大写字母;或 后面带’的大写字母
  2. 终结符为 小写字母和符号(+、*)
  3. 推导符号为->
  4. 用end结束文法。
  5. 不针对特定文法,编写求first函数。

首先first集的求法:

我的思路是这样的:

1.生成式结构体:左侧只有一个,用string类型;右侧可能有由"|"隔开的多个,所以用vector;first集,也用vector。

2.首先输入生成式个数,然后依次读入生成式(用“#”表示空),用classify函数分别放入左部、右部。

3.接下来就是求first集了,对于每个生成式,分别处理右部,也就是右部vector的每个元素(都是string类型),下面是几种情况。

(1)如果某个元素的开头是小写字母(终结符),那就接着看后面,截取全部的与第一个连续的小写字母,就是first集的一个元素,将其加入first集(判断是否已存在,如果不存在才能加入),当前元素处理完毕。

(2)如果开头是规定的符号终结符,直接加入当前结构体的first集,当前元素处理完毕。

(3)如果开头是大写字母,将其first集中除“#”外的元素无重复的加入当前结构体的first集中。

         如果该非终结符的first集里面没有“#”,处理完毕。

         如果有“#”,还要继续看后面的,我的理解是把后面那个当成是一个新的右部元素处理,所以直接把它加到右部元素的vector里,最后再把后加的都弹出就好啦。

最后放代码:

#include<iostream>
#include<string>
#include<vector>
 
using namespace std;
int N = 0;
struct Generation{
	string left;
	vector<string> right;
	vector<string> first;
};
vector<Generation> G;
int find(string left){    //找到left对应的生成式的下标 
	for(int i=0;i<G.size();i++)
		if(G[i].left==left)
		return i;
	return 1111;
}
bool in(vector<string> v,string s){ //判断一个字符串是否在vector里 
	for(int i=0;i<v.size();i++)
		if(v[i]==s)
		return true;
	return false;
} 

void classify(string generation)                      //将产生式的左右部分别放入left,right
{
	Generation g;
	int j,pos = 0;
	for (j = 0;j<=generation.length();j++){ 
		if (generation[j] == '-'&&generation[j + 1] == '>'){
			g.left = generation.substr(0, j);
			pos = j+2;
		}
		if(generation[j]=='|'||j==generation.length()){
			g.right.push_back(generation.substr(pos, j-pos));
			pos = j+1;
		}
	}
	G.push_back(g);
}

void First(){
	int i,j,k,s;
	int add_num = 0;
	string v;
	for(i=G.size()-1;i>=0;i--){
		Generation temp = G[i];
		for(j=0;j<temp.right.size();j++){     //分别处理右部 
			v.clear();
			add_num = 0;
			string right = temp.right[j];
			if(right[0]>='a'&&right[0]<='z'){
				v+=right[0];
				int k=1;
				while(right[k]>='a'&&right[k]<='z'&&k<right.size()){					
					v+=right[k];					
					k+=1;
				}
				temp.first.push_back(v);
			}
			else if(right[0]=='*'||right[0]=='+'||right[0]=='('||right[0]==')'||right[0]=='#'){
				v += right[0];
				temp.first.push_back(v);
			}
			else if(right[0]>='A'||right[0]<='Z'){
				v += right[0];
				int num = find(v);
				v.clear();
				if(num!=1111){
					vector<string> target = G[num].first;
					for(k=0;k<target.size();k++){
						if(!in(temp.first,target[k])&&target[k]!="#")      //判断是否存在于temp的first集中 
							temp.first.push_back(target[k]);
						if(target[k]=="#"&&right.length()>1) {            //如果右侧的非终结符的first里包含空,那就继续处理这个非终结符后面的 
							v=right.substr(1);
							temp.right.push_back(v);
							add_num += 1;
						} 
						if(target[k]=="#"&&right.length()==1&&!in(temp.first,"#")){
							temp.first.push_back(target[k]);
						}
					} 
				}
			}			
		}
		for(k=0;k<add_num;k++)  //最后把加进去的right的元素都删除 
			temp.right.pop_back();
		G[i] = temp;	
	}
	
}
void handle(){
	int i;
	string gen;
	cout << "请输入产生式个数:";
	cin >> N;
	cout << endl<<"请输入产生式(要用#表示空):"<< endl;
	for(i=0;i<N;i++){
		cin >> gen;
		classify(gen);
	} 
	First();
}
int main(){
	handle();
	/*for(int i=0;i<G.size();i++){
		cout << G[i].left << "   ";
		cout << G[i].right.size();
		for(int j=0;j<G[i].right.size();j++)
		cout << G[i].right[j] << "  "; 
	}*/
	cout << endl << "非终结符对应的first集为:" << endl; 
	for(int i=0;i<G.size();i++){
		cout << G[i].left<<"   {";
		for(int j=0;j<G[i].first.size();j++){
			cout << G[i].first[j];
			if(j==G[i].first.size()-1)
				cout << "}" << endl;
			else
				cout << ","; 
		}
	}
		
	return 0;
}

 

 

测试

 

 

 

 

 

 

 

 

  • 8
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
题目:First集和Follow集生成算法模拟 【问题描述】 设计一个由正规文法生成First集和Follow集并进行简化的算法动态模拟。(算法参见教材) 【基本要】 动态模拟算法的基本功能是: (1) 输入一个文法G; (2) 输出由文法G构造FIRST集的算法; (3) 输出First集; (4) 输出由文法G构造FOLLOW集的算法; (5) 输出FOLLOW集。 【测试数据】 输入文法: E->TE’ E’->+TE’|ε T->FT’ T’->*FT’|εF->(E)|i 【实现提示】 用数据库存储多行文法,用LIST控件显示算法,用GRID类依据算法进行作图。并实现算法与生成过程的关联。 三、设计思路 该分析器主要包括三大部分:FIRST集,FOLLOW集,SELECT集。下面主要介绍计算FIRST集和FOLLOW集算法思想。 FIRST集的算法思想:主要有三个函数 First(), First_getvn(), First_getvt。函数 First()调用First_getvn(),First_getvn()调用First_getvt 这里主要把产生式分成的两种: 一:产生式只能推出空,形如:S->$;此时S的FIRST集为{$} 二:产生式右部包含非终结符和终结符,形如:S->aA, S->AB. 这里定义了两个比较重要字符串,分别是first 即FIRST集;另一个是first_vn,把它定义非终结符的FIRST集。当产生式右边的第一个字符为非终结符时,把该VN加入 srt first_vn中,后再调用函数first_getvt出FIRST集。若产生式右边的第一个字符为终结符时,则直接把该VT加入str first,得到FISRT集。 流程图: 略

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值