某个编译原理的实验代码存档
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.
 
 
compile-work/parser/grammar/Grammar.cpp

234 lines
6.3 KiB

//
// Created by lenfrex on 2023/5/7.
//
#include <iomanip>
#include "Grammar.h"
using namespace std;
const set<char> &Grammar::getNonTerminals() const {
return nonTerminals;
}
const set<char> &Grammar::getTerminals() const {
return terminals;
}
#define isBlankSpace(c) (c == ' ')
Grammar::Grammar(const string &nonTerminalString, const string &terminalString,
const set<string> &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<char, set<Express>> &Grammar::getGrammarExpresses() const {
return productionsMap;
}
const char emptyChar = '~';
#define isEmptyStr(c) (c == '~')
// 是否可以推导出空字符
bool Grammar::canDeducedEmpty(const set<string> &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<char, std::set<Express>> &Grammar::getProductionsMap() const {
return productionsMap;
}
const map<char, std::set<char>> &Grammar::getFirstSet() const {
return firstSet;
}
const map<char, std::set<char>> &Grammar::getFollowSet() const {
return followSet;
}
const map<char, SelectSet> &Grammar::getSelectSet() const {
return selectSet;
}
const map<char, TableRow> &Grammar::getAnalysisTable() const {
return analysisTable;
}
bool Grammar::isLl1Grammar() const {
return ll1Grammar;
}