Suppress errors for unneeded defines
This commit is contained in:
parent
ddf0fe4e11
commit
d353164244
3 changed files with 56 additions and 32 deletions
|
@ -74,10 +74,15 @@ private:
|
||||||
QString root;
|
QString root;
|
||||||
QString text;
|
QString text;
|
||||||
QString file;
|
QString file;
|
||||||
|
QString curDefine;
|
||||||
|
QMap<QString, QStringList> errorMap;
|
||||||
QList<Token> tokenizeExpression(QString expression, const QMap<QString, int> &knownIdentifiers);
|
QList<Token> tokenizeExpression(QString expression, const QMap<QString, int> &knownIdentifiers);
|
||||||
QList<Token> generatePostfix(const QList<Token> &tokens);
|
QList<Token> generatePostfix(const QList<Token> &tokens);
|
||||||
int evaluatePostfix(const QList<Token> &postfix);
|
int evaluatePostfix(const QList<Token> &postfix);
|
||||||
void error(const QString &message, const QString &expression);
|
void recordError(const QString &message);
|
||||||
|
void recordErrors(const QStringList &errors);
|
||||||
|
void logRecordedErrors();
|
||||||
|
QString createErrorMessage(const QString &message, const QString &expression);
|
||||||
|
|
||||||
static const QRegularExpression re_incScriptLabel;
|
static const QRegularExpression re_incScriptLabel;
|
||||||
static const QRegularExpression re_globalIncScriptLabel;
|
static const QRegularExpression re_globalIncScriptLabel;
|
||||||
|
|
|
@ -16,15 +16,33 @@ void ParseUtil::set_root(const QString &dir) {
|
||||||
this->root = dir;
|
this->root = dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ParseUtil::error(const QString &message, const QString &expression) {
|
void ParseUtil::recordError(const QString &message) {
|
||||||
QStringList lines = text.split(QRegularExpression("[\r\n]"));
|
this->errorMap[this->curDefine].append(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ParseUtil::recordErrors(const QStringList &errors) {
|
||||||
|
if (errors.isEmpty()) return;
|
||||||
|
this->errorMap[this->curDefine].append(errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ParseUtil::logRecordedErrors() {
|
||||||
|
QStringList errors = this->errorMap.value(this->curDefine);
|
||||||
|
if (errors.isEmpty()) return;
|
||||||
|
QString message = QString("Failed to parse '%1':").arg(this->curDefine);
|
||||||
|
for (const auto error : errors)
|
||||||
|
message.append(QString("\n%1").arg(error));
|
||||||
|
logError(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ParseUtil::createErrorMessage(const QString &message, const QString &expression) {
|
||||||
|
QStringList lines = this->text.split(QRegularExpression("[\r\n]"));
|
||||||
int lineNum = 0, colNum = 0;
|
int lineNum = 0, colNum = 0;
|
||||||
for (QString line : lines) {
|
for (QString line : lines) {
|
||||||
lineNum++;
|
lineNum++;
|
||||||
colNum = line.indexOf(expression) + 1;
|
colNum = line.indexOf(expression) + 1;
|
||||||
if (colNum) break;
|
if (colNum) break;
|
||||||
}
|
}
|
||||||
logError(QString("%1:%2:%3: %4").arg(file).arg(lineNum).arg(colNum).arg(message));
|
return QString("%1:%2:%3: %4").arg(this->file).arg(lineNum).arg(colNum).arg(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ParseUtil::readTextFile(const QString &path) {
|
QString ParseUtil::readTextFile(const QString &path) {
|
||||||
|
@ -52,8 +70,8 @@ int ParseUtil::textFileLineCount(const QString &path) {
|
||||||
QList<QStringList> ParseUtil::parseAsm(const QString &filename) {
|
QList<QStringList> ParseUtil::parseAsm(const QString &filename) {
|
||||||
QList<QStringList> parsed;
|
QList<QStringList> parsed;
|
||||||
|
|
||||||
text = readTextFile(root + '/' + filename);
|
this->text = readTextFile(this->root + '/' + filename);
|
||||||
const QStringList lines = removeLineComments(text, "@").split('\n');
|
const QStringList lines = removeLineComments(this->text, "@").split('\n');
|
||||||
for (const auto &line : lines) {
|
for (const auto &line : lines) {
|
||||||
const QString trimmedLine = line.trimmed();
|
const QString trimmedLine = line.trimmed();
|
||||||
if (trimmedLine.isEmpty()) {
|
if (trimmedLine.isEmpty()) {
|
||||||
|
@ -101,6 +119,8 @@ QList<Token> ParseUtil::tokenizeExpression(QString expression, const QMap<QStrin
|
||||||
if (!token.isEmpty()) {
|
if (!token.isEmpty()) {
|
||||||
if (tokenType == "identifier") {
|
if (tokenType == "identifier") {
|
||||||
if (knownIdentifiers.contains(token)) {
|
if (knownIdentifiers.contains(token)) {
|
||||||
|
// Any errors encountered when this identifier was evaluated should be recorded for this expression as well.
|
||||||
|
recordErrors(this->errorMap.value(token));
|
||||||
QString actualToken = QString("%1").arg(knownIdentifiers.value(token));
|
QString actualToken = QString("%1").arg(knownIdentifiers.value(token));
|
||||||
expression = expression.replace(0, token.length(), actualToken);
|
expression = expression.replace(0, token.length(), actualToken);
|
||||||
token = actualToken;
|
token = actualToken;
|
||||||
|
@ -109,14 +129,14 @@ QList<Token> ParseUtil::tokenizeExpression(QString expression, const QMap<QStrin
|
||||||
tokenType = "error";
|
tokenType = "error";
|
||||||
QString message = QString("unknown token '%1' found in expression '%2'")
|
QString message = QString("unknown token '%1' found in expression '%2'")
|
||||||
.arg(token).arg(expression);
|
.arg(token).arg(expression);
|
||||||
error(message, expression);
|
recordError(createErrorMessage(message, expression));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (tokenType == "operator") {
|
else if (tokenType == "operator") {
|
||||||
if (!Token::precedenceMap.contains(token)) {
|
if (!Token::precedenceMap.contains(token)) {
|
||||||
QString message = QString("unsupported postfix operator: '%1'")
|
QString message = QString("unsupported postfix operator: '%1'")
|
||||||
.arg(token);
|
.arg(token);
|
||||||
error(message, expression);
|
recordError(createErrorMessage(message, expression));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,7 +181,7 @@ QList<Token> ParseUtil::generatePostfix(const QList<Token> &tokens) {
|
||||||
// pop the left parenthesis token
|
// pop the left parenthesis token
|
||||||
operatorStack.pop();
|
operatorStack.pop();
|
||||||
} else {
|
} else {
|
||||||
logError("Mismatched parentheses detected in expression!");
|
recordError("Mismatched parentheses detected in expression!");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// token is an operator
|
// token is an operator
|
||||||
|
@ -176,7 +196,7 @@ QList<Token> ParseUtil::generatePostfix(const QList<Token> &tokens) {
|
||||||
|
|
||||||
while (!operatorStack.isEmpty()) {
|
while (!operatorStack.isEmpty()) {
|
||||||
if (operatorStack.top().value == "(" || operatorStack.top().value == ")") {
|
if (operatorStack.top().value == "(" || operatorStack.top().value == ")") {
|
||||||
logError("Mismatched parentheses detected in expression!");
|
recordError("Mismatched parentheses detected in expression!");
|
||||||
} else {
|
} else {
|
||||||
output.append(operatorStack.pop());
|
output.append(operatorStack.pop());
|
||||||
}
|
}
|
||||||
|
@ -230,7 +250,7 @@ QString ParseUtil::readCIncbin(const QString &filename, const QString &label) {
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
text = readTextFile(root + "/" + filename);
|
this->text = readTextFile(this->root + "/" + filename);
|
||||||
|
|
||||||
QRegularExpression re(QString(
|
QRegularExpression re(QString(
|
||||||
"\\b%1\\b"
|
"\\b%1\\b"
|
||||||
|
@ -239,7 +259,7 @@ QString ParseUtil::readCIncbin(const QString &filename, const QString &label) {
|
||||||
"\\(\\s*\"([^\"]*)\"\\s*\\)").arg(label));
|
"\\(\\s*\"([^\"]*)\"\\s*\\)").arg(label));
|
||||||
|
|
||||||
QRegularExpressionMatch match;
|
QRegularExpressionMatch match;
|
||||||
qsizetype pos = text.indexOf(re, 0, &match);
|
qsizetype pos = this->text.indexOf(re, 0, &match);
|
||||||
if (pos != -1) {
|
if (pos != -1) {
|
||||||
path = match.captured(1);
|
path = match.captured(1);
|
||||||
}
|
}
|
||||||
|
@ -253,36 +273,40 @@ QMap<QString, int> ParseUtil::readCDefines(const QString &filename,
|
||||||
{
|
{
|
||||||
QMap<QString, int> filteredDefines;
|
QMap<QString, int> filteredDefines;
|
||||||
|
|
||||||
file = filename;
|
this->file = filename;
|
||||||
|
|
||||||
if (file.isEmpty()) {
|
if (this->file.isEmpty()) {
|
||||||
return filteredDefines;
|
return filteredDefines;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString filepath = root + "/" + file;
|
QString filepath = this->root + "/" + this->file;
|
||||||
text = readTextFile(filepath);
|
this->text = readTextFile(filepath);
|
||||||
|
|
||||||
if (text.isNull()) {
|
if (this->text.isNull()) {
|
||||||
logError(QString("Failed to read C defines file: '%1'").arg(filepath));
|
logError(QString("Failed to read C defines file: '%1'").arg(filepath));
|
||||||
return filteredDefines;
|
return filteredDefines;
|
||||||
}
|
}
|
||||||
|
|
||||||
text.replace(QRegularExpression("(//.*)|(\\/+\\*+[^*]*\\*+\\/+)"), "");
|
this->text.replace(QRegularExpression("(//.*)|(\\/+\\*+[^*]*\\*+\\/+)"), "");
|
||||||
text.replace(QRegularExpression("(\\\\\\s+)"), "");
|
this->text.replace(QRegularExpression("(\\\\\\s+)"), "");
|
||||||
allDefines.insert("FALSE", 0);
|
allDefines.insert("FALSE", 0);
|
||||||
allDefines.insert("TRUE", 1);
|
allDefines.insert("TRUE", 1);
|
||||||
|
|
||||||
QRegularExpression re("#define\\s+(?<defineName>\\w+)[^\\S\\n]+(?<defineValue>.+)");
|
QRegularExpression re("#define\\s+(?<defineName>\\w+)[^\\S\\n]+(?<defineValue>.+)");
|
||||||
QRegularExpressionMatchIterator iter = re.globalMatch(text);
|
QRegularExpressionMatchIterator iter = re.globalMatch(this->text);
|
||||||
|
this->errorMap.clear();
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
QRegularExpressionMatch match = iter.next();
|
QRegularExpressionMatch match = iter.next();
|
||||||
QString name = match.captured("defineName");
|
QString name = match.captured("defineName");
|
||||||
QString expression = match.captured("defineValue");
|
QString expression = match.captured("defineValue");
|
||||||
if (expression == " ") continue;
|
if (expression == " ") continue;
|
||||||
|
this->curDefine = name;
|
||||||
int value = evaluateDefine(expression, allDefines);
|
int value = evaluateDefine(expression, allDefines);
|
||||||
allDefines.insert(name, value);
|
allDefines.insert(name, value);
|
||||||
for (QString prefix : prefixes) {
|
for (QString prefix : prefixes) {
|
||||||
if (name.startsWith(prefix) || QRegularExpression(prefix).match(name).hasMatch()) {
|
if (name.startsWith(prefix) || QRegularExpression(prefix).match(name).hasMatch()) {
|
||||||
|
// Only log errors for defines that Porymap is looking for
|
||||||
|
logRecordedErrors();
|
||||||
filteredDefines.insert(name, value);
|
filteredDefines.insert(name, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -296,7 +320,7 @@ QStringList ParseUtil::readCDefinesSorted(const QString &filename,
|
||||||
{
|
{
|
||||||
QMap<QString, int> defines = readCDefines(filename, prefixes, knownDefines);
|
QMap<QString, int> defines = readCDefines(filename, prefixes, knownDefines);
|
||||||
|
|
||||||
// The defines should to be sorted by their underlying value, not alphabetically.
|
// The defines should be sorted by their underlying value, not alphabetically.
|
||||||
// Reverse the map and read out the resulting keys in order.
|
// Reverse the map and read out the resulting keys in order.
|
||||||
QMultiMap<int, QString> definesInverse;
|
QMultiMap<int, QString> definesInverse;
|
||||||
for (QString defineName : defines.keys()) {
|
for (QString defineName : defines.keys()) {
|
||||||
|
@ -312,11 +336,11 @@ QStringList ParseUtil::readCArray(const QString &filename, const QString &label)
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
file = filename;
|
this->file = filename;
|
||||||
text = readTextFile(root + "/" + filename);
|
this->text = readTextFile(this->root + "/" + filename);
|
||||||
|
|
||||||
QRegularExpression re(QString(R"(\b%1\b\s*(\[?[^\]]*\])?\s*=\s*\{([^\}]*)\})").arg(label));
|
QRegularExpression re(QString(R"(\b%1\b\s*(\[?[^\]]*\])?\s*=\s*\{([^\}]*)\})").arg(label));
|
||||||
QRegularExpressionMatch match = re.match(text);
|
QRegularExpressionMatch match = re.match(this->text);
|
||||||
|
|
||||||
if (match.hasMatch()) {
|
if (match.hasMatch()) {
|
||||||
QString body = match.captured(2);
|
QString body = match.captured(2);
|
||||||
|
@ -332,11 +356,11 @@ QStringList ParseUtil::readCArray(const QString &filename, const QString &label)
|
||||||
}
|
}
|
||||||
|
|
||||||
QMap<QString, QString> ParseUtil::readNamedIndexCArray(const QString &filename, const QString &label) {
|
QMap<QString, QString> ParseUtil::readNamedIndexCArray(const QString &filename, const QString &label) {
|
||||||
text = readTextFile(root + "/" + filename);
|
this->text = readTextFile(this->root + "/" + filename);
|
||||||
QMap<QString, QString> map;
|
QMap<QString, QString> map;
|
||||||
|
|
||||||
QRegularExpression re_text(QString(R"(\b%1\b\s*(\[?[^\]]*\])?\s*=\s*\{([^\}]*)\})").arg(label));
|
QRegularExpression re_text(QString(R"(\b%1\b\s*(\[?[^\]]*\])?\s*=\s*\{([^\}]*)\})").arg(label));
|
||||||
QString body = re_text.match(text).captured(2).replace(QRegularExpression("\\s*"), "");
|
QString body = re_text.match(this->text).captured(2).replace(QRegularExpression("\\s*"), "");
|
||||||
|
|
||||||
QRegularExpression re("\\[(?<index>[A-Za-z0-9_]*)\\]=(?<value>&?[A-Za-z0-9_]*)");
|
QRegularExpression re("\\[(?<index>[A-Za-z0-9_]*)\\]=(?<value>&?[A-Za-z0-9_]*)");
|
||||||
QRegularExpressionMatchIterator iter = re.globalMatch(body);
|
QRegularExpressionMatchIterator iter = re.globalMatch(body);
|
||||||
|
|
|
@ -2221,15 +2221,10 @@ bool Project::readSecretBaseIds() {
|
||||||
if (!projectConfig.getEventSecretBaseEnabled())
|
if (!projectConfig.getEventSecretBaseEnabled())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// SECRET_BASE_GROUP is a function-like macro, which Porymap can't handle.
|
|
||||||
// Redefine it so Porymap won't produce spurious errors about failing to parse it.
|
|
||||||
QMap<QString, int> knownDefines = QMap<QString, int>();
|
|
||||||
knownDefines.insert("SECRET_BASE_GROUP", 0);
|
|
||||||
|
|
||||||
QStringList prefixes("\\bSECRET_BASE_[A-Za-z0-9_]*_[0-9]+");
|
QStringList prefixes("\\bSECRET_BASE_[A-Za-z0-9_]*_[0-9]+");
|
||||||
QString filename = projectConfig.getFilePath(ProjectFilePath::constants_secret_bases);
|
QString filename = projectConfig.getFilePath(ProjectFilePath::constants_secret_bases);
|
||||||
fileWatcher.addPath(root + "/" + filename);
|
fileWatcher.addPath(root + "/" + filename);
|
||||||
secretBaseIds = parser.readCDefinesSorted(filename, prefixes, knownDefines);
|
secretBaseIds = parser.readCDefinesSorted(filename, prefixes);
|
||||||
if (secretBaseIds.isEmpty()) {
|
if (secretBaseIds.isEmpty()) {
|
||||||
logError(QString("Failed to read secret base id constants from %1").arg(filename));
|
logError(QString("Failed to read secret base id constants from %1").arg(filename));
|
||||||
return false;
|
return false;
|
||||||
|
|
Loading…
Reference in a new issue