合工大 编译原理 实验三

合工大 编译原理 实验三 LR(1) 分析法

本项目使用c++实现,利用Windows API制作了简易的UI界面。
具体功能如下:

  1. 支持查看文法,项目族,LR(1) 分析表,句子归约过程。
  2. 可使用包含左递归的文法且在过程中不生成新终结符
  3. 利用Graphviz查看DFA转换图

详细功能、示例截图、项目代码请见GitHub:LR(1)分析

部分核心代码如下:
1.求FIRST集(该方法尚属测试阶段,如有问题欢迎大佬批评指出)

//利用检测FIRSTset变动情况来求FIRST集的函数,试图忽视左递归与回溯,并不产生新的非终结符
void CheckLR1class::getFIRSTsets() {
	multimap<string, string> CopyedGrammarFormula = GrammarFormula;		//备份的文法表达式列表

	while (true) {
		bool isFIRSTsetincreased = false;//本次遍历是否存在FIRST集变动

		for (auto i = FIRSTset.begin(); i != FIRSTset.end() && isFIRSTsetincreased == false; i++) {		//删去first集中存在空字符且在产生式右部首位的字符,这样可以保证遍历到B->Ab,A->€中的b
			if (i->second.find(NULLCHARACTER) != i->second.end()) {
				for (auto ii = CopyedGrammarFormula.begin(); ii != CopyedGrammarFormula.end(); ii++) {
					if (ii->first.at(0) == i->first) {

						auto oldii = ii;
						CopyedGrammarFormula.insert(make_pair(ii->first.substr(1),ii->second));
						ii++;
						CopyedGrammarFormula.erase(oldii);
						
						isFIRSTsetincreased = true;
						
					}
				}
			}
		}

		for (auto i = CopyedGrammarFormula.begin(); i != CopyedGrammarFormula.end(); i++) {
			//ReversedGrammarFormula.insert(i->second, i->first);
			if (Vnset.find(i->first.at(0)) == Vnset.end() && (FIRSTset.find(i->second.at(0))== FIRSTset.end() || FIRSTset[i->second.at(0)].find(i->first.at(0)) == FIRSTset[i->second.at(0)].end())) {	//终结符且未收录直接添加
				FIRSTset[i->second.at(0)].insert(i->first.at(0));
				isFIRSTsetincreased = true;
			}
			if (Vnset.find(i->first.at(0)) != Vnset.end() && FIRSTset[i->first.at(0)].size() != 0) {						//非终结符且该符号非终结符非空
				bool isallhasincluded = true;																					//若存在不包括则添加
				
				
					for (auto tmpj = FIRSTset[i->first.at(0)].begin(); tmpj != FIRSTset[i->first.at(0)].end(); tmpj++) {//判断右侧非终结符FIRST集是否已被包含在自身FIRST集中,如果包含则不添加,并不视为FIRST集改动;否则添加,并记录为FIRST集改动
						bool isthishasincluded = false;
						for (auto tmpi = FIRSTset[i->second.at(0)].begin(); tmpi != FIRSTset[i->second.at(0)].end(); tmpi++) {						
							if (*tmpi == *tmpj && *tmpj!=NULLCHARACTER) {
								isthishasincluded = true;
							}					
						}
						if (isthishasincluded == false) {
							isallhasincluded = false;
						}
					}
				
				if (isallhasincluded == false) {
					for (auto tmpj = FIRSTset[i->first.at(0)].begin(); tmpj != FIRSTset[i->first.at(0)].end(); tmpj++) {
						if (*tmpj != NULLCHARACTER) {
							FIRSTset[i->second.at(0)].insert(*tmpj);
							isFIRSTsetincreased = true;
						}					
					}
				}
			}
		}

		if (isFIRSTsetincreased == false) {
			break;
		}
	}

}

2.制作DFA分析
本函数使用队列来进行生成DFA,队列中储存需要展开(求取其子节点)的项目族,每次取队列中的队首进行展开,并将其子节点添加到队列中(前提为未曾在队列中出现过)。

void CheckLR1class::makeAnalysedSheet() {
	statusblock initalstatusblock;
	
	/*tmp.GrammarSentence = string{ mostcharacter };
	tmp.GrammarVn = "0";
	tmp.index = 0;*/
	SymbolSet tmpsymbolset;
	tmpsymbolset.insert('#');
	//tmp.SearchSymbol = tmpsymbolset;
	ProjectSentence tmp = make_tuple("0", string{ mostcharacter }, tmpsymbolset, 0);
	initalstatusblock.ProjectItem.insert(tmp);
	initalstatusblock += getCLOSURE(initalstatusblock);

	//set<set<ProjectSentence>> alreadyexpanedstatusblock;		//已经展开过的状态族集合的集合 由于statusblock结构中存在自增变量无法利用
	stack<statusblock> searchingstack;
	searchingstack.push(initalstatusblock);

	while (searchingstack.empty() == false) {
		statusblock currentstatusblock = searchingstack.top();

		collapsesameFormula(currentstatusblock);

		searchingstack.pop();
		SymbolSet symbol_iter = getSymbols(currentstatusblock);

		for (auto i = symbol_iter.begin(); i != symbol_iter.end(); i++) {
			statusblock tmpfetchedstatusblock = GO(currentstatusblock, *i);


			collapsesameFormula(tmpfetchedstatusblock);


			GOset[currentstatusblock][*i] = tmpfetchedstatusblock;

			bool isfinded = false;

			for (auto GOset_iter = GOset.begin(); GOset_iter != GOset.end(); GOset_iter++) {
				if (GOset_iter->first == tmpfetchedstatusblock) {
					isfinded = true;
				}
			}

			if(isfinded==false )		//尚未进行展开
				searchingstack.push(tmpfetchedstatusblock);
		}
	}
	//该函数产生父节点与子节点之间的对应关系map,故后续需转化输出处理
}
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wjh776a68

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

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值