合工大 编译原理 实验三 LR(1) 分析法
本项目使用c++实现,利用Windows API制作了简易的UI界面。
具体功能如下:
- 支持查看文法,项目族,LR(1) 分析表,句子归约过程。
- 可使用包含左递归的文法且在过程中不生成新终结符
- 利用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,故后续需转化输出处理
}