You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
187 lines
6.0 KiB
187 lines
6.0 KiB
2 years ago
|
//
|
||
|
// Created by lenfrex on 2023/5/7.
|
||
|
//
|
||
|
|
||
|
#include "Grammar.h"
|
||
|
|
||
|
using namespace std;
|
||
|
|
||
|
#define isEmptyStr(c) (c == '~')
|
||
|
|
||
|
void Grammar::generateFollowSet() {
|
||
|
this->followPreProcess();
|
||
|
|
||
|
// 不断补充follow集,直到总的follow集大小不会再变大为止
|
||
|
int beforeSize = getTotalFollowSize();
|
||
|
for (int afterSize = -1; afterSize != beforeSize; afterSize = getTotalFollowSize()) {
|
||
|
beforeSize = getTotalFollowSize();
|
||
|
this->followFinalProcess();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int Grammar::getTotalFollowSize() {
|
||
|
int count = 0;
|
||
|
for (const auto &followPair: followSet) {
|
||
|
count += (int) followPair.second.size();
|
||
|
}
|
||
|
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
void searchForProduction(const Grammar &grammar,
|
||
|
const string &production,
|
||
|
std::map<char, std::set<char>> &followSet);
|
||
|
|
||
|
void Grammar::followPreProcess() {
|
||
|
// 获取每一个非终止符,以获得所有的产生式
|
||
|
for (const auto &nonTerminal: nonTerminals) {
|
||
|
// 开始符号先加个'#'结束符
|
||
|
if (nonTerminal == startChar) {
|
||
|
followSet[nonTerminal].insert('#');
|
||
|
}
|
||
|
|
||
|
if (!productionsMap.contains(nonTerminal)) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
const set<string> &productions = productionsMap.at(nonTerminal);
|
||
|
|
||
|
// 对当前非终止符的所有的产生式进行解析,搜索所有的非终止符进行求follow
|
||
|
for (const auto &production: productions) {
|
||
|
searchForProduction(*this, production, this->followSet);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
enum LoopStatus {
|
||
|
Finish, Continue
|
||
|
};
|
||
|
|
||
|
LoopStatus processNonTerminalFollow(const Grammar &grammar,
|
||
|
const string &production, const auto &currPos,
|
||
|
std::map<char, std::set<char>> &followSet);
|
||
|
|
||
|
void searchForProduction(const Grammar &grammar,
|
||
|
const string &production,
|
||
|
std::map<char, std::set<char>> &followSet) {
|
||
|
|
||
|
const auto &nonTerminals = grammar.getNonTerminals();
|
||
|
|
||
|
for (auto currPos = production.begin(); currPos != production.end(); currPos++) {
|
||
|
char currChar = *currPos;
|
||
|
|
||
|
// 如果当前的符号不是非终止符,就继续解析下一个字符,
|
||
|
// 直到遇到的是非终止符
|
||
|
if (!nonTerminals.contains(currChar)) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
LoopStatus result = processNonTerminalFollow(grammar, production, currPos, followSet);
|
||
|
switch (result) {
|
||
|
case Continue:
|
||
|
continue;
|
||
|
case Finish:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LoopStatus processNonTerminalFollow(const Grammar &grammar,
|
||
|
const string &production, const auto &currPos,
|
||
|
std::map<char, std::set<char>> &followSet) {
|
||
|
|
||
|
const auto &terminals = grammar.getTerminals();
|
||
|
const auto &productionsMap = grammar.getProductionsMap();
|
||
|
const auto &firstSet = grammar.getFirstSet();
|
||
|
|
||
|
auto next = currPos + 1;
|
||
|
char currChar = *currPos;
|
||
|
|
||
|
ProcessNoneTerminal:
|
||
|
// 到了产生式尾部就直接添加结束符
|
||
|
if (next == production.end()) {
|
||
|
followSet[currChar].insert('#');
|
||
|
return Finish;
|
||
|
}
|
||
|
|
||
|
// 如果下一个字符就是终结符的话,直接加到结果里边去,然后继续处理后面可能会遇到的非终止符
|
||
|
// 如果下一个字符也是非终止符,把下一个非终止符的firs去掉空串之后加到当前的follow中
|
||
|
if (terminals.contains(*next)) {
|
||
|
followSet[currChar].insert(*next);
|
||
|
return Continue;
|
||
|
} else {
|
||
|
set<char> addFirst = firstSet.at(*next);
|
||
|
addFirst.erase('~');
|
||
|
followSet[currChar].insert(addFirst.begin(), addFirst.end());
|
||
|
|
||
|
// 如果下一个能推导出空串,那就还要继续找后面非终止符,知道非终止符不能推空为止
|
||
|
if (Grammar::canDeducedEmpty(productionsMap.at(*next))) {
|
||
|
next++;
|
||
|
goto ProcessNoneTerminal;
|
||
|
} else {
|
||
|
return Finish;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LoopStatus finalProcessNonTerminalFollow(const Grammar &grammar, char nonTerminal,
|
||
|
const string &production, const auto &currPos,
|
||
|
std::map<char, std::set<char>> &followSet);
|
||
|
|
||
|
void Grammar::followFinalProcess() {
|
||
|
// 处理每一个非终止符
|
||
|
for (char nonTerminal: nonTerminals) {
|
||
|
if (!productionsMap.contains(nonTerminal)) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
const set<string> &productions = productionsMap.at(nonTerminal);
|
||
|
|
||
|
// 对所有的产生式进行解析,搜索所有的非终止符进行求follow
|
||
|
for (const auto &production: productions) {
|
||
|
for (auto currPos = production.begin(); currPos != production.end(); currPos++) {
|
||
|
LoopStatus result = finalProcessNonTerminalFollow(*this, nonTerminal, production, currPos, this->followSet);
|
||
|
switch (result) {
|
||
|
case Continue:
|
||
|
continue;
|
||
|
case Finish:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LoopStatus finalProcessNonTerminalFollow(
|
||
|
const Grammar &grammar, char nonTerminal,
|
||
|
const string &production, const auto &currPos,
|
||
|
std::map<char, std::set<char>> &followSet) {
|
||
|
|
||
|
char currChar = *currPos;
|
||
|
|
||
|
const auto &productionsMap = grammar.getProductionsMap();
|
||
|
const auto &nonTerminals = grammar.getNonTerminals();
|
||
|
|
||
|
// 如果当前的符号不是非终止符,就继续解析下一个字符,
|
||
|
// 直到遇到的是非终止符
|
||
|
if (!nonTerminals.contains(*currPos)) {
|
||
|
return Continue;
|
||
|
}
|
||
|
|
||
|
// 当前字符是当前产生式的尾部,添加产生式左部的follow进这个字符的follow中
|
||
|
auto next = currPos + 1;
|
||
|
if (next == production.end()) {
|
||
|
followSet[currChar].insert(followSet[nonTerminal].begin(), followSet[nonTerminal].end());
|
||
|
return Continue;
|
||
|
}
|
||
|
|
||
|
// 如果当前字符不是产生式尾部但是下一个字符是非终结符并且位于尾部,而且还能推空,也把产生式左部的follow添加进这个字符的follow中
|
||
|
auto nextNext = next + 1;
|
||
|
if (nextNext == production.end() && nonTerminals.contains(*next)) {
|
||
|
if (Grammar::canDeducedEmpty(productionsMap.at(*next))) {
|
||
|
followSet[currChar].insert(followSet[nonTerminal].begin(), followSet[nonTerminal].end());
|
||
|
return Continue;
|
||
|
}
|
||
|
}
|
||
|
}
|