// // Created by lenfrex on 2023/5/7. // #include #include "Grammar.h" using namespace std; const set &Grammar::getNonTerminals() const { return nonTerminals; } const set &Grammar::getTerminals() const { return terminals; } #define isBlankSpace(c) (c == ' ') Grammar::Grammar(const string &nonTerminalString, const string &terminalString, const set &productionTexts, char startChar) : startChar(startChar) { for (char c: nonTerminalString) { nonTerminals.insert(c); } for (char c: terminalString) { terminals.insert(c); } // 解析每条产生式 for (const string &prodText: productionTexts) { char nonTerminal = '\0'; for (char c: prodText) { if (isBlankSpace(c)) { continue; } else { nonTerminal = c; break; } } string::size_type start = prodText.find("->"); // 输入的产生式有误,跳过该条产生式 if (start == -1) { break; } for (string::size_type i = start + 2; i < prodText.length(); ++i) { // 跳过空格 if (isBlankSpace(prodText[i])) { continue; } productionsMap[nonTerminal].insert(prodText.substr(i)); break; } } generateFirstSet(); generateFollowSet(); generateSelectSet(); this->ll1Grammar = isLL1Grammar(); if (ll1Grammar) { buildAnalysisTable(); } } const map> &Grammar::getGrammarExpresses() const { return productionsMap; } const char emptyChar = '~'; #define isEmptyStr(c) (c == '~') // 是否可以推导出空字符 bool Grammar::canDeducedEmpty(const set &productions) { for (const auto &production: productions) { for (const auto &c: production) { if (isEmptyStr(c)) { return true; } } } return false; } ostream &alignPrint(ostream &os, const string &str) { os << setw(8) << left << setfill(' ') << str; return os; } ostream &alignPrint(ostream &os, char str) { os << setw(8) << left << setfill(' ') << str; return os; } ostream &operator<<(ostream &os, const Grammar &grammar) { const auto &terminals = grammar.getTerminals(); const auto &nonTerminals = grammar.getNonTerminals(); os << "文法符号详情:" << endl; os << "开始符号:" << grammar.getStartChar() << endl; os << "终止符:Vt = {"; for (const auto &c: terminals) { os << '\'' << c << '\'' << ", "; } os << "}" << endl; os << "非终止符:Vn = {"; for (const auto &c: nonTerminals) { os << '\'' << c << '\'' << ", "; } os << "}" << endl; os << "================================" << endl; os << " FirstSet " << endl; os << "================================" << endl; const auto &firstSet = grammar.getFirstSet(); for (const auto &nonTerminal: nonTerminals) { os << "First(" << nonTerminal << ") = {"; const auto &firstChars = firstSet.at(nonTerminal); for (const auto &firstChar: firstChars) { os << '\'' << firstChar << '\'' << ", "; } os << "}" << endl; } os << "================================" << endl; os << " FollowSet " << endl; os << "================================" << endl; const auto &followSet = grammar.getFollowSet(); for (const auto &nonTerminal: nonTerminals) { os << "Follow(" << nonTerminal << ") = {"; const auto &followChars = followSet.at(nonTerminal); for (const auto &followChar: followChars) { os << '\'' << followChar << '\'' << ", "; } os << "}" << endl; } os << "================================" << endl; os << " SelectSet " << endl; os << "================================" << endl; const auto &allSelectSet = grammar.getSelectSet(); for (const auto &nonTerminal: nonTerminals) { const auto &nonTerminalSelectSet = allSelectSet.at(nonTerminal); for (const auto &selectPair: nonTerminalSelectSet) { os << "Select(" << nonTerminal << "->" << selectPair.first << ')' << "\t=\t" << "{"; for (const auto &selectChar: selectPair.second) { os << '\'' << selectChar << '\'' << ", "; } os << "}" << endl; } } os << "================================" << endl; os << " AnalysisTable " << endl; os << "================================" << endl; alignPrint(os, "Vn/Vt"); os << "| "; for (const auto &terminal: terminals) { if (terminal != '~') { alignPrint(os, terminal); } } alignPrint(os, '#'); os << endl; for (int i = 0; i < terminals.size(); ++i) { os << "----------"; } os << endl; const auto &analysisTable = grammar.getAnalysisTable(); for (const auto &nonTerminal: nonTerminals) { alignPrint(os, nonTerminal); os << "| "; for (const auto &terminal: terminals) { if (terminal == '~') { break; } bool found = analysisTable.contains(nonTerminal) && analysisTable.at(nonTerminal).contains(terminal); string printText = found ? ("->" + analysisTable.at(nonTerminal).at(terminal)): "[/]"; alignPrint(os, printText); } bool found = analysisTable.contains(nonTerminal) && analysisTable.at(nonTerminal).contains('#'); string printText = found ? ("->" + analysisTable.at(nonTerminal).at('#')): "[/]"; alignPrint(os, printText); os << endl; } return os; } char Grammar::getStartChar() const { return startChar; } const map> &Grammar::getProductionsMap() const { return productionsMap; } const map> &Grammar::getFirstSet() const { return firstSet; } const map> &Grammar::getFollowSet() const { return followSet; } const map &Grammar::getSelectSet() const { return selectSet; } const map &Grammar::getAnalysisTable() const { return analysisTable; } bool Grammar::isLl1Grammar() const { return ll1Grammar; }