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.
143 lines
4.5 KiB
143 lines
4.5 KiB
1 year ago
|
#include <iomanip>
|
||
|
#include <utility>
|
||
|
#include "iostream"
|
||
|
|
||
|
#include "Checker.h"
|
||
|
|
||
|
using namespace std;
|
||
|
|
||
|
#define isEmptyStr(c) (c == '~')
|
||
|
|
||
|
// 能否推导出空串
|
||
|
bool Checker::canDeducedEmpty(const set<string> &productions) {
|
||
|
for (const auto &production: productions) {
|
||
|
for (const auto &c: production) {
|
||
|
if (isEmptyStr(c)) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
string Checker::getStackContent(stack<char> source) {
|
||
|
string str;
|
||
|
while (!source.empty()) {
|
||
|
str.push_back(source.top());
|
||
|
source.pop();
|
||
|
}
|
||
|
|
||
|
std::reverse(str.begin(), str.end());
|
||
|
|
||
|
return str;
|
||
|
}
|
||
|
|
||
|
void printTableHeader() {
|
||
|
cout << setw(16) << left << setfill(' ') << "步";
|
||
|
cout << setw(20) << left << setfill(' ') << "分析栈情况";
|
||
|
cout << setw(23) << left << setfill(' ') << "待分析字符串";
|
||
|
cout << setw(25) << left << setfill(' ') << "使用产生式与匹配情况" << endl;
|
||
|
}
|
||
|
|
||
|
bool Checker::identifyString(std::string input) {
|
||
|
printTableHeader();
|
||
|
|
||
|
// 添加#到输入字符串尾部
|
||
|
input.push_back('#');
|
||
|
|
||
|
stack<char> analysisStack = stack<char>();
|
||
|
|
||
|
// #先入栈
|
||
|
analysisStack.push('#');
|
||
|
|
||
|
// 开始符号入栈, S
|
||
|
analysisStack.push(grammar.getStartChar());
|
||
|
|
||
|
int step = 0;
|
||
|
|
||
|
string remain = input;
|
||
|
string status = "分析中";
|
||
|
|
||
|
cout << setw(16) << left << setfill(' ') << step;
|
||
|
cout << setw(16) << left << setfill(' ') << getStackContent(analysisStack);
|
||
|
cout << setw(16) << left << setfill(' ') << remain;
|
||
|
|
||
|
const set<char> &terminals = grammar.getTerminals();
|
||
|
const auto &productionsMap = grammar.getGrammarExpresses();
|
||
|
const auto &analysisTable = grammar.getAnalysisTable();
|
||
|
|
||
|
for (auto pos = input.begin(); pos != input.end();) {
|
||
|
char currentChar = *pos;
|
||
|
char stackTopChar = analysisStack.top();
|
||
|
|
||
|
// 如果当前栈顶是终结符,对比当前输入字符和栈顶终结符是否匹配
|
||
|
// 匹配则进行规约,否则判定不匹配
|
||
|
if (terminals.contains(stackTopChar)) {
|
||
|
if (currentChar == stackTopChar) {
|
||
|
analysisStack.pop();
|
||
|
for (const auto &c: remain) {
|
||
|
if (c == currentChar) {
|
||
|
remain = remain.substr(1);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
status.clear();
|
||
|
status.push_back('\'');
|
||
|
status.push_back(currentChar);
|
||
|
status += "': 匹配";
|
||
|
pos++;
|
||
|
} else {
|
||
|
cout << "匹配失败。期望输入:" << stackTopChar;
|
||
|
cout << ",得到输入:" << currentChar << endl;
|
||
|
return false;
|
||
|
}
|
||
|
} else if (stackTopChar == '#') {
|
||
|
return currentChar == '#';
|
||
|
} else {
|
||
|
/* 对非终结符的处理 */
|
||
|
// 预测分析表中找不到对应的规则,但是当前的非终止符能推出空串,就退栈,该非终止符作为空串推测处理
|
||
|
// 否则就判定不接受
|
||
|
bool foundInTable = analysisTable.at(stackTopChar).contains(currentChar);
|
||
|
if (!foundInTable) {
|
||
|
if (canDeducedEmpty(productionsMap.at(stackTopChar))) {
|
||
|
cout << "找不到" << stackTopChar << "与" << currentChar << "相匹配的规则" << endl;
|
||
|
return false;
|
||
|
} else {
|
||
|
analysisStack.pop();
|
||
|
status.clear();
|
||
|
status.push_back(stackTopChar);
|
||
|
status += "->~";
|
||
|
}
|
||
|
} else {
|
||
|
analysisStack.pop();
|
||
|
|
||
|
status.clear();
|
||
|
status.push_back(stackTopChar);
|
||
|
string production = analysisTable.at(stackTopChar).at(currentChar);
|
||
|
status += "-> " + production;
|
||
|
|
||
|
for (int i = (int) production.size() - 1; i >= 0; --i) {
|
||
|
char c = production[i];
|
||
|
if (c != '~') {
|
||
|
analysisStack.push(c);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
step++;
|
||
|
|
||
|
cout << setw(16) << left << setfill(' ') << status << endl;
|
||
|
cout << setw(16) << left << setfill(' ') << step;
|
||
|
cout << setw(16) << left << setfill(' ') << getStackContent(analysisStack);
|
||
|
cout << setw(16) << left << setfill(' ') << remain;
|
||
|
}
|
||
|
|
||
|
cout << endl;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
Checker::Checker(Grammar grammar) : grammar(std::move(grammar)){}
|