From 38360de140a3f23dff7ecd3ff2a2d15b8ba864bc Mon Sep 17 00:00:00 2001 From: Marcus Huderle Date: Fri, 2 Mar 2018 19:55:55 -0800 Subject: [PATCH 1/5] Update map object filepath --- project.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.cpp b/project.cpp index cbe6f65d..4db155e2 100755 --- a/project.cpp +++ b/project.cpp @@ -1128,7 +1128,7 @@ void Project::loadObjectPixmaps(QList objects) { QString pointers_text = readTextFile(root + "/src/data/field_map_obj/map_object_graphics_info_pointers.h"); QString info_text = readTextFile(root + "/src/data/field_map_obj/map_object_graphics_info.h"); QString pic_text = readTextFile(root + "/src/data/field_map_obj/map_object_pic_tables.h"); - QString assets_text = readTextFile(root + "/src/field/field_map_obj.c"); + QString assets_text = readTextFile(root + "/src/field/event_object_movement.c"); QStringList pointers = readCArray(pointers_text, "gMapObjectGraphicsInfoPointers"); From 2bc949612d97c8e0064f65524103c212e04a59bd Mon Sep 17 00:00:00 2001 From: Marcus Huderle Date: Fri, 2 Mar 2018 19:56:23 -0800 Subject: [PATCH 2/5] Populate hidden item dropdown menu with item constants --- mainwindow.cpp | 6 ++++++ project.cpp | 24 ++++++++++++++++++++++++ project.h | 3 ++- 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/mainwindow.cpp b/mainwindow.cpp index 3e1e48f2..a053ec90 100755 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -284,6 +284,7 @@ void MainWindow::loadDataStructures() { Project *project = editor->project; project->readMapAttributesTable(); project->readAllMapAttributes(); + project->readItemNames(); } void MainWindow::populateMapList() { @@ -644,6 +645,11 @@ void MainWindow::updateSelectedObjects() { combo->addItem(value); } combo->addItems(*editor->project->mapNames); + } else if (key == "item") { + if (!editor->project->itemNames->contains(value)) { + combo->addItem(value); + } + combo->addItems(*editor->project->itemNames); } else { combo->addItem(value); } diff --git a/project.cpp b/project.cpp index 4db155e2..d036795c 100755 --- a/project.cpp +++ b/project.cpp @@ -18,6 +18,7 @@ Project::Project() groupNames = new QStringList; map_groups = new QMap; mapNames = new QStringList; + itemNames = new QStringList; map_cache = new QMap; mapConstantsToMapNames = new QMap; mapNamesToMapConstants = new QMap; @@ -1062,6 +1063,29 @@ QStringList Project::getBattleScenes() { return names; } +void Project::readItemNames() { + QString text = readTextFile(root + "/include/constants/items.h"); + if (!text.isNull()) { + QStringList itemDefinePrefixes; + itemDefinePrefixes << "ITEM_"; + QMap itemDefines = readCDefines(text, itemDefinePrefixes); + + // The item names should to be sorted by their underlying value, not alphabetically. + // Reverse the map and read out the resulting keys in order. + QMultiMap itemDefinesInverse; + for (QString itemName : itemDefines.keys()) { + itemDefinesInverse.insert(itemDefines[itemName], itemName); + } + + for (int itemValue : itemDefinesInverse.keys()) { + QList names = itemDefinesInverse.values(itemValue); + for (QString name : names) { + itemNames->append(name); + } + } + } +} + QStringList Project::getSongNames() { QStringList names; QString text = readTextFile(root + "/include/constants/songs.h"); diff --git a/project.h b/project.h index 37ae487f..2a67f0b6 100755 --- a/project.h +++ b/project.h @@ -23,7 +23,7 @@ public: QMap mapAttributesTableMaster; QMap> mapAttributes; QMap> mapAttributesMaster; - + QStringList *itemNames = NULL; QMap *map_cache; Map* loadMap(QString); @@ -73,6 +73,7 @@ public: QStringList getWeathers(); QStringList getMapTypes(); QStringList getBattleScenes(); + void readItemNames(); void loadObjectPixmaps(QList objects); QMap getMapObjGfxConstants(); From 669c81b50b8bee2b15968eae7f4dc15b3914a9fd Mon Sep 17 00:00:00 2001 From: Marcus Huderle Date: Fri, 2 Mar 2018 21:54:08 -0800 Subject: [PATCH 3/5] Populate flag and var dropdown menus with their respective constants --- mainwindow.cpp | 20 ++++++++++--- project.cpp | 80 ++++++++++++++++++++++++++++++++++---------------- project.h | 7 +++++ 3 files changed, 78 insertions(+), 29 deletions(-) diff --git a/mainwindow.cpp b/mainwindow.cpp index a053ec90..3ee30ad2 100755 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -285,6 +285,8 @@ void MainWindow::loadDataStructures() { project->readMapAttributesTable(); project->readAllMapAttributes(); project->readItemNames(); + project->readFlagNames(); + project->readVarNames(); } void MainWindow::populateMapList() { @@ -570,8 +572,8 @@ void MainWindow::updateSelectedObjects() { field_labels["sight_radius"] = "Sight Radius"; field_labels["destination_warp"] = "Destination Warp"; field_labels["destination_map_name"] = "Destination Map"; - field_labels["coord_unknown1"] = "Unknown 1"; - field_labels["coord_unknown2"] = "Unknown 2"; + field_labels["script_var"] = "Var"; + field_labels["script_var_value"] = "Var Value"; field_labels["type"] = "Type"; field_labels["item"] = "Item"; field_labels["item_unknown5"] = "Unknown 5"; @@ -614,8 +616,8 @@ void MainWindow::updateSelectedObjects() { } else if (event_type == "trap") { fields << "script_label"; - fields << "coord_unknown1"; - fields << "coord_unknown2"; + fields << "script_var"; + fields << "script_var_value"; } else if (event_type == "trap_weather") { fields << "weather"; @@ -650,6 +652,16 @@ void MainWindow::updateSelectedObjects() { combo->addItem(value); } combo->addItems(*editor->project->itemNames); + } else if (key == "flag") { + if (!editor->project->flagNames->contains(value)) { + combo->addItem(value); + } + combo->addItems(*editor->project->flagNames); + } else if (key == "script_var") { + if (!editor->project->varNames->contains(value)) { + combo->addItem(value); + } + combo->addItems(*editor->project->varNames); } else { combo->addItem(value); } diff --git a/project.cpp b/project.cpp index d036795c..6768e1fd 100755 --- a/project.cpp +++ b/project.cpp @@ -19,6 +19,8 @@ Project::Project() map_groups = new QMap; mapNames = new QStringList; itemNames = new QStringList; + flagNames = new QStringList; + varNames = new QStringList; map_cache = new QMap; mapConstantsToMapNames = new QMap; mapNamesToMapConstants = new QMap; @@ -1064,25 +1066,39 @@ QStringList Project::getBattleScenes() { } void Project::readItemNames() { - QString text = readTextFile(root + "/include/constants/items.h"); + QString filepath = root + "/include/constants/items.h"; + QStringList prefixes = (QStringList() << "ITEM_"); + readCDefinesSorted(filepath, prefixes, itemNames); +} + +void Project::readFlagNames() { + QString filepath = root + "/include/constants/flags.h"; + QStringList prefixes = (QStringList() << "FLAG_"); + readCDefinesSorted(filepath, prefixes, flagNames, "SYSTEM_FLAGS", 0x800); +} + +void Project::readVarNames() { + QString filepath = root + "/include/constants/vars.h"; + QStringList prefixes = (QStringList() << "VAR_"); + readCDefinesSorted(filepath, prefixes, varNames); +} + +void Project::readCDefinesSorted(QString filepath, QStringList prefixes, QStringList* definesToSet) { + return readCDefinesSorted(filepath, prefixes, definesToSet, "", 0); +} + +void Project::readCDefinesSorted(QString filepath, QStringList prefixes, QStringList* definesToSet, QString hardcodedDefine, int hardcodedDefineValue) { + QString text = readTextFile(filepath); if (!text.isNull()) { - QStringList itemDefinePrefixes; - itemDefinePrefixes << "ITEM_"; - QMap itemDefines = readCDefines(text, itemDefinePrefixes); + QMap defines = readCDefines(text, prefixes, hardcodedDefine, hardcodedDefineValue); - // The item names should to be sorted by their underlying value, not alphabetically. + // The defines should to be sorted by their underlying value, not alphabetically. // Reverse the map and read out the resulting keys in order. - QMultiMap itemDefinesInverse; - for (QString itemName : itemDefines.keys()) { - itemDefinesInverse.insert(itemDefines[itemName], itemName); - } - - for (int itemValue : itemDefinesInverse.keys()) { - QList names = itemDefinesInverse.values(itemValue); - for (QString name : names) { - itemNames->append(name); - } + QMultiMap definesInverse; + for (QString defineName : defines.keys()) { + definesInverse.insert(defines[defineName], defineName); } + *definesToSet = definesInverse.values(); } } @@ -1252,8 +1268,8 @@ void Project::saveMapEvents(Map *map) { text += QString(", %1").arg(coords->get("y")); text += QString(", %1").arg(coords->get("elevation")); text += QString(", 0"); - text += QString(", %1").arg(coords->get("coord_unknown1")); - text += QString(", %1").arg(coords->get("coord_unknown2")); + text += QString(", %1").arg(coords->get("script_var")); + text += QString(", %1").arg(coords->get("script_var_value")); text += QString(", 0"); text += QString(", %1").arg(coords->get("script_label")); text += "\n"; @@ -1413,8 +1429,8 @@ void Project::readMapEvents(Map *map) { coord->put("x", command.value(i++)); coord->put("y", command.value(i++)); coord->put("elevation", command.value(i++)); - coord->put("coord_unknown1", command.value(i++)); - coord->put("coord_unknown2", command.value(i++)); + coord->put("script_var", command.value(i++)); + coord->put("script_var_value", command.value(i++)); coord->put("script_label", command.value(i++)); //coord_unknown3 //coord_unknown4 @@ -1539,23 +1555,37 @@ QString Project::readCIncbin(QString text, QString label) { } QMap Project::readCDefines(QString text, QStringList prefixes) { + return readCDefines(text, prefixes, "", 0); +} + +QMap Project::readCDefines(QString text, QStringList prefixes, QString hardcodedDefine, int hardcodedDefineValue) { QMap defines; - QString combinedPrefixes = "[" + prefixes.join('|') + "]"; - QRegularExpression re(QString("#define\\s+(?%1\\w+)\\s(?\\w+)").arg(combinedPrefixes)); + QString combinedPrefixes = "(" + prefixes.join('|') + ")"; + QString regex; + if (hardcodedDefine.isEmpty()) { + regex = QString("#define\\s+(?(%1)\\w+)\\s+(?\\w+)").arg(combinedPrefixes); + } else { + regex = QString("#define\\s+(?(%1)\\w+)\\s+\\(*(?\\\s*%2\\s+\\+\\s+)*(?\\w+\)\\)*").arg(combinedPrefixes, hardcodedDefine); + } + + QRegularExpression re(regex); QRegularExpressionMatchIterator iter = re.globalMatch(text); while (iter.hasNext()) { QRegularExpressionMatch match = iter.next(); QString name = match.captured("defineName"); + QString hardcodedDefineName = match.captured("hardcodedDefineName"); QString value = match.captured("defineValue"); bool valid; int parsedValue = value.startsWith("0x") ? value.toInt(&valid, 16) : value.toInt(&valid, 10); if (valid) { - if (!defines.contains(name)) { - defines.insert(name, parsedValue); - } else { - qDebug() << QString("Define '%1' is defined multiple times'").arg(name); + int actualValue = parsedValue; + if (!hardcodedDefine.isEmpty() && !hardcodedDefineName.isEmpty()) { + actualValue += hardcodedDefineValue; } + defines.insert(name, actualValue); + } else if (defines.contains(value)) { + defines.insert(name, defines.value(value)); } else { qDebug() << QString("Failed to parse define '%1' value '%2' as base 10 or hexadecimal value").arg(name, value); } diff --git a/project.h b/project.h index 2a67f0b6..d595821b 100755 --- a/project.h +++ b/project.h @@ -24,6 +24,8 @@ public: QMap> mapAttributes; QMap> mapAttributesMaster; QStringList *itemNames = NULL; + QStringList *flagNames = NULL; + QStringList *varNames = NULL; QMap *map_cache; Map* loadMap(QString); @@ -74,6 +76,8 @@ public: QStringList getMapTypes(); QStringList getBattleScenes(); void readItemNames(); + void readFlagNames(); + void readVarNames(); void loadObjectPixmaps(QList objects); QMap getMapObjGfxConstants(); @@ -90,12 +94,15 @@ public: QStringList readCArray(QString text, QString label); QString readCIncbin(QString text, QString label); QMap readCDefines(QString text, QStringList prefixes); + QMap readCDefines(QString text, QStringList prefixes, QString hardcodedDefine, int hardcodedDefineValue); private: QString getMapAttributesTableFilepath(); QString getMapAssetsFilepath(); void saveMapHeader(Map*); void saveMapAttributesTable(); void updateMapAttributes(Map* map); + void readCDefinesSorted(QString, QStringList, QStringList*); + void readCDefinesSorted(QString, QStringList, QStringList*, QString, int); void setNewMapHeader(Map* map, int mapIndex); void setNewMapAttributes(Map* map); From d87d5e6f006d249fd5b496d09755ee8bd39877ba Mon Sep 17 00:00:00 2001 From: Marcus Huderle Date: Sat, 3 Mar 2018 12:20:59 -0800 Subject: [PATCH 4/5] Remove the reverse song constant lookup --- mainwindow.cpp | 6 +----- project.cpp | 20 -------------------- project.h | 1 - 3 files changed, 1 insertion(+), 26 deletions(-) diff --git a/mainwindow.cpp b/mainwindow.cpp index 3ee30ad2..fd5bebc5 100755 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -203,11 +203,7 @@ void MainWindow::displayMapProperties() { QStringList songs = project->getSongNames(); ui->comboBox_Song->addItems(songs); - QString song = map->song; - if (!songs.contains(song)) { - song = project->getSongName(song.toInt()); - } - ui->comboBox_Song->setCurrentText(song); + ui->comboBox_Song->setCurrentText(map->song); ui->comboBox_Location->addItems(project->getLocations()); ui->comboBox_Location->setCurrentText(map->location); diff --git a/project.cpp b/project.cpp index 6768e1fd..974dbefe 100755 --- a/project.cpp +++ b/project.cpp @@ -1114,26 +1114,6 @@ QStringList Project::getSongNames() { return names; } -QString Project::getSongName(int songNumber) { - QStringList names; - QString text = readTextFile(root + "/include/constants/songs.h"); - if (!text.isNull()) { - QStringList songDefinePrefixes; - songDefinePrefixes << "SE_" << "BGM_"; - QMap songDefines = readCDefines(text, songDefinePrefixes); - - // Loop through song defines, and fine the one with the matching song number. - QMap::iterator iter = songDefines.begin(); - while (iter != songDefines.end()) { - if (iter.value() == songNumber) { - return iter.key(); - } - iter++; - } - } - return ""; -} - QMap Project::getMapObjGfxConstants() { QMap constants; QString text = readTextFile(root + "/include/constants/map_objects.h"); diff --git a/project.h b/project.h index d595821b..465b4fb9 100755 --- a/project.h +++ b/project.h @@ -69,7 +69,6 @@ public: QList* parse(QString text); QStringList getSongNames(); - QString getSongName(int); QStringList getLocations(); QStringList getVisibilities(); QStringList getWeathers(); From af4dc34ebab53fc36e8faa4cd81b47b9ce55e707 Mon Sep 17 00:00:00 2001 From: Marcus Huderle Date: Sat, 3 Mar 2018 17:09:05 -0800 Subject: [PATCH 5/5] Evaluate C define expressions using postfix evaluation, and rename 'asm' to 'parseutil' --- asm.cpp | 59 --------------- asm.h | 15 ---- parseutil.cpp | 199 ++++++++++++++++++++++++++++++++++++++++++++++++++ parseutil.h | 43 +++++++++++ pretmap.pro | 8 +- project.cpp | 102 ++++++++++---------------- project.h | 3 +- 7 files changed, 287 insertions(+), 142 deletions(-) delete mode 100755 asm.cpp delete mode 100755 asm.h create mode 100755 parseutil.cpp create mode 100755 parseutil.h diff --git a/asm.cpp b/asm.cpp deleted file mode 100755 index f291e3ba..00000000 --- a/asm.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include "asm.h" - -Asm::Asm() -{ -} - -void Asm::strip_comment(QString *line) { - bool in_string = false; - for (int i = 0; i < line->length(); i++) { - if (line->at(i) == '"') { - in_string = !in_string; - } else if (line->at(i) == '@') { - if (!in_string) { - line->truncate(i); - break; - } - } - } -} - -QList* Asm::parse(QString text) { - QList *parsed = new QList; - QStringList lines = text.split('\n'); - for (QString line : lines) { - QString label; - //QString macro; - //QStringList *params; - strip_comment(&line); - if (line.trimmed().isEmpty()) { - } else if (line.contains(':')) { - label = line.left(line.indexOf(':')); - QStringList *list = new QStringList; - list->append(".label"); // This is not a real keyword. It's used only to make the output more regular. - list->append(label); - parsed->append(*list); - // There should not be anything else on the line. - // gas will raise a syntax error if there is. - } else { - line = line.trimmed(); - //parsed->append(line.split(QRegExp("\\s*,\\s*"))); - QString macro; - QStringList params; - int index = line.indexOf(QRegExp("\\s+")); - macro = line.left(index); - params = line.right(line.length() - index).trimmed().split(QRegExp("\\s*,\\s*")); - params.prepend(macro); - parsed->append(params); - } - //if (macro != NULL) { - // if (macros->contains(macro)) { - // void* function = macros->value(macro); - // if (function != NULL) { - // std::function function(params); - // } - // } - //} - } - return parsed; -} diff --git a/asm.h b/asm.h deleted file mode 100755 index 5aa55b55..00000000 --- a/asm.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef ASM_H -#define ASM_H - -#include -#include - -class Asm -{ -public: - Asm(); - void strip_comment(QString*); - QList* parse(QString); -}; - -#endif // ASM_H diff --git a/parseutil.cpp b/parseutil.cpp new file mode 100755 index 00000000..9b481159 --- /dev/null +++ b/parseutil.cpp @@ -0,0 +1,199 @@ +#include "parseutil.h" + +#include +#include +#include + +ParseUtil::ParseUtil() +{ +} + +void ParseUtil::strip_comment(QString *line) { + bool in_string = false; + for (int i = 0; i < line->length(); i++) { + if (line->at(i) == '"') { + in_string = !in_string; + } else if (line->at(i) == '@') { + if (!in_string) { + line->truncate(i); + break; + } + } + } +} + +QList* ParseUtil::parseAsm(QString text) { + QList *parsed = new QList; + QStringList lines = text.split('\n'); + for (QString line : lines) { + QString label; + //QString macro; + //QStringList *params; + strip_comment(&line); + if (line.trimmed().isEmpty()) { + } else if (line.contains(':')) { + label = line.left(line.indexOf(':')); + QStringList *list = new QStringList; + list->append(".label"); // This is not a real keyword. It's used only to make the output more regular. + list->append(label); + parsed->append(*list); + // There should not be anything else on the line. + // gas will raise a syntax error if there is. + } else { + line = line.trimmed(); + //parsed->append(line.split(QRegExp("\\s*,\\s*"))); + QString macro; + QStringList params; + int index = line.indexOf(QRegExp("\\s+")); + macro = line.left(index); + params = line.right(line.length() - index).trimmed().split(QRegExp("\\s*,\\s*")); + params.prepend(macro); + parsed->append(params); + } + //if (macro != NULL) { + // if (macros->contains(macro)) { + // void* function = macros->value(macro); + // if (function != NULL) { + // std::function function(params); + // } + // } + //} + } + return parsed; +} + +int ParseUtil::evaluateDefine(QString define, QMap* knownDefines) { + QList tokens = tokenizeExpression(define, knownDefines); + QList postfixExpression = generatePostfix(tokens); + return evaluatePostfix(postfixExpression); +} + +QList ParseUtil::tokenizeExpression(QString expression, QMap* knownIdentifiers) { + QList tokens; + + QStringList tokenTypes = (QStringList() << "hex" << "decimal" << "identifier" << "operator" << "leftparen" << "rightparen"); + QRegularExpression re("^(?0x[0-9a-fA-F]+)|(?[0-9]+)|(?[a-zA-Z_0-9]+)|(?[+\\-*\\/<>|^%]+)|(?\\()|(?\\))"); + + expression = expression.trimmed(); + while (!expression.isEmpty()) { + QRegularExpressionMatch match = re.match(expression); + if (!match.hasMatch()) { + qDebug() << "Failed to tokenize expression: " << expression; + break; + } + for (QString tokenType : tokenTypes) { + QString token = match.captured(tokenType); + if (!token.isEmpty()) { + if (tokenType == "identifier") { + if (knownIdentifiers->contains(token)) { + QString actualToken = QString("%1").arg(knownIdentifiers->value(token)); + expression = expression.replace(0, token.length(), actualToken); + token = actualToken; + tokenType = "decimal"; + } else { + qDebug() << "Unknown identifier found in expression: " << token; + } + } + + tokens.append(Token(token, tokenType)); + expression = expression.remove(0, token.length()).trimmed(); + break; + } + } + } + return tokens; +} + +QMap Token::precedenceMap = QMap( +{ + {"*", 3}, + {"/", 3}, + {"+", 4}, + {"-", 4}, + {"<<", 5}, + {">>", 5}, + {"&", 8}, + {"^", 9}, + {"|", 10} +}); + +// Shunting-yard algorithm for generating postfix notation. +// https://en.wikipedia.org/wiki/Shunting-yard_algorithm +QList ParseUtil::generatePostfix(QList tokens) { + QList output; + QStack operatorStack; + for (Token token : tokens) { + if (token.type == TokenType::Number) { + output.append(token); + } else if (token.value == "(") { + operatorStack.push(token); + } else if (token.value == ")") { + while (!operatorStack.empty() && operatorStack.top().value != "(") { + output.append(operatorStack.pop()); + } + if (!operatorStack.empty()) { + // pop the left parenthesis token + operatorStack.pop(); + } else { + qDebug() << "Mismatched parentheses detected in expression!"; + } + } else { + // token is an operator + while (!operatorStack.isEmpty() + && operatorStack.top().operatorPrecedence <= token.operatorPrecedence + && operatorStack.top().value != "(") { + output.append(operatorStack.pop()); + } + operatorStack.push(token); + } + } + + while (!operatorStack.isEmpty()) { + if (operatorStack.top().value == "(" || operatorStack.top().value == ")") { + qDebug() << "Mismatched parentheses detected in expression!"; + } else { + output.append(operatorStack.pop()); + } + } + + return output; +} + +// Evaluate postfix expression. +// https://en.wikipedia.org/wiki/Reverse_Polish_notation#Postfix_evaluation_algorithm +int ParseUtil::evaluatePostfix(QList postfix) { + QStack stack; + for (Token token : postfix) { + if (token.type == TokenType::Operator) { + int op2 = stack.pop().value.toInt(nullptr, 0); + int op1 = stack.pop().value.toInt(nullptr, 0); + int result = 0; + if (token.value == "*") { + result = op1 * op2; + } else if (token.value == "/") { + result = op1 / op2; + } else if (token.value == "+") { + result = op1 + op2; + } else if (token.value == "-") { + result = op1 - op2; + } else if (token.value == "<<") { + result = op1 << op2; + } else if (token.value == ">>") { + result = op1 >> op2; + } else if (token.value == "&") { + result = op1 & op2; + } else if (token.value == "^") { + result = op1 ^ op2; + } else if (token.value == "|") { + result = op1 | op2; + } else { + qDebug() << "Unsupported postfix operator: " << token.value; + } + stack.push(Token(QString("%1").arg(result), "decimal")); + } else { + stack.push(token); + } + } + + return stack.pop().value.toInt(nullptr, 0); +} diff --git a/parseutil.h b/parseutil.h new file mode 100755 index 00000000..aec0bec4 --- /dev/null +++ b/parseutil.h @@ -0,0 +1,43 @@ +#ifndef PARSEUTIL_H +#define PARSEUTIL_H + +#include +#include + +enum TokenType { + Number, + Operator, +}; + +class Token { +public: + Token(QString value = "", QString type = "") { + this->value = value; + this->type = TokenType::Operator; + if (type == "decimal" || type == "hex") { + this->type = TokenType::Number; + this->operatorPrecedence = -1; + } else if (type == "operator") { + this->operatorPrecedence = precedenceMap[value]; + } + } + static QMap precedenceMap; + QString value; + TokenType type; + int operatorPrecedence; // only relevant for operator tokens +}; + +class ParseUtil +{ +public: + ParseUtil(); + void strip_comment(QString*); + QList* parseAsm(QString); + int evaluateDefine(QString, QMap*); +private: + QList tokenizeExpression(QString expression, QMap* knownIdentifiers); + QList generatePostfix(QList tokens); + int evaluatePostfix(QList postfix); +}; + +#endif // PARSEUTIL_H diff --git a/pretmap.pro b/pretmap.pro index 80d4a716..d0221dce 100755 --- a/pretmap.pro +++ b/pretmap.pro @@ -15,7 +15,6 @@ TEMPLATE = app SOURCES += main.cpp\ mainwindow.cpp \ project.cpp \ - asm.cpp \ map.cpp \ blockdata.cpp \ block.cpp \ @@ -25,11 +24,11 @@ SOURCES += main.cpp\ event.cpp \ editor.cpp \ objectpropertiesframe.cpp \ - graphicsview.cpp + graphicsview.cpp \ + parseutil.cpp HEADERS += mainwindow.h \ project.h \ - asm.h \ map.h \ blockdata.h \ block.h \ @@ -39,7 +38,8 @@ HEADERS += mainwindow.h \ event.h \ editor.h \ objectpropertiesframe.h \ - graphicsview.h + graphicsview.h \ + parseutil.h FORMS += mainwindow.ui \ objectpropertiesframe.ui diff --git a/project.cpp b/project.cpp index 974dbefe..fd54f6a9 100755 --- a/project.cpp +++ b/project.cpp @@ -1,4 +1,4 @@ -#include "asm.h" +#include "parseutil.h" #include "project.h" #include "tile.h" #include "tileset.h" @@ -71,7 +71,7 @@ void Project::loadMapConnections(Map *map) { QString path = root + QString("/data/maps/%1/connections.inc").arg(map->name); QString text = readTextFile(path); if (!text.isNull()) { - QList *commands = parse(text); + QList *commands = parseAsm(text); QStringList *list = getLabelValues(commands, map->connections_label); //// Avoid using this value. It ought to be generated instead. @@ -150,13 +150,13 @@ void Project::readMapHeader(Map* map) { } QString label = map->name; - Asm *parser = new Asm; + ParseUtil *parser = new ParseUtil; QString header_text = readTextFile(root + "/data/maps/" + label + "/header.inc"); if (header_text.isNull()) { return; } - QStringList *header = getLabelValues(parser->parse(header_text), label); + QStringList *header = getLabelValues(parser->parseAsm(header_text), label); map->attributes_label = header->value(0); map->events_label = header->value(1); map->scripts_label = header->value(2); @@ -212,7 +212,7 @@ void Project::saveMapHeader(Map *map) { void Project::readMapAttributesTable() { int curMapIndex = 1; QString attributesText = readTextFile(getMapAttributesTableFilepath()); - QList* values = parse(attributesText); + QList* values = parseAsm(attributesText); bool inAttributePointers = false; for (int i = 0; i < values->length(); i++) { QStringList params = values->value(i); @@ -265,13 +265,13 @@ void Project::readMapAttributes(Map* map) { return; } - Asm *parser = new Asm; + ParseUtil *parser = new ParseUtil; QString assets_text = readTextFile(getMapAssetsFilepath()); if (assets_text.isNull()) { return; } - QStringList *attributes = getLabelValues(parser->parse(assets_text), map->attributes_label); + QStringList *attributes = getLabelValues(parser->parseAsm(assets_text), map->attributes_label); map->width = attributes->value(0); map->height = attributes->value(1); map->border_label = attributes->value(2); @@ -283,13 +283,13 @@ void Project::readMapAttributes(Map* map) { void Project::readAllMapAttributes() { mapAttributes.clear(); - Asm *parser = new Asm; + ParseUtil *parser = new ParseUtil; QString assets_text = readTextFile(getMapAssetsFilepath()); if (assets_text.isNull()) { return; } - QList *commands = parser->parse(assets_text); + QList *commands = parser->parseAsm(assets_text); // Assume the _assets.inc file is grouped consistently in the order of: // 1. _MapBorder @@ -539,10 +539,10 @@ void Project::getTilesets(Map* map) { } Tileset* Project::loadTileset(QString label) { - Asm *parser = new Asm; + ParseUtil *parser = new ParseUtil; QString headers_text = readTextFile(root + "/data/tilesets/headers.inc"); - QStringList *values = getLabelValues(parser->parse(headers_text), label); + QStringList *values = getLabelValues(parser->parseAsm(headers_text), label); Tileset *tileset = new Tileset; tileset->name = label; tileset->is_compressed = values->value(0); @@ -562,7 +562,7 @@ Tileset* Project::loadTileset(QString label) { QString Project::getBlockdataPath(Map* map) { QString text = readTextFile(getMapAssetsFilepath()); - QStringList *values = getLabelValues(parse(text), map->blockdata_label); + QStringList *values = getLabelValues(parseAsm(text), map->blockdata_label); QString path; if (!values->isEmpty()) { path = root + "/" + values->value(0).section('"', 1, 1); @@ -574,7 +574,7 @@ QString Project::getBlockdataPath(Map* map) { QString Project::getMapBorderPath(Map *map) { QString text = readTextFile(getMapAssetsFilepath()); - QStringList *values = getLabelValues(parse(text), map->border_label); + QStringList *values = getLabelValues(parseAsm(text), map->border_label); QString path; if (!values->isEmpty()) { path = root + "/" + values->value(0).section('"', 1, 1); @@ -705,7 +705,7 @@ void Project::saveAllDataStructures() { } void Project::loadTilesetAssets(Tileset* tileset) { - Asm* parser = new Asm; + ParseUtil* parser = new ParseUtil; QString category = (tileset->is_secondary == "TRUE") ? "secondary" : "primary"; if (tileset->name.isNull()) { return; @@ -713,7 +713,7 @@ void Project::loadTilesetAssets(Tileset* tileset) { QString dir_path = root + "/data/tilesets/" + category + "/" + tileset->name.replace("gTileset_", "").toLower(); QString graphics_text = readTextFile(root + "/data/tilesets/graphics.inc"); - QList *graphics = parser->parse(graphics_text); + QList *graphics = parser->parseAsm(graphics_text); QStringList *tiles_values = getLabelValues(graphics, tileset->tiles_label); QStringList *palettes_values = getLabelValues(graphics, tileset->palettes_label); @@ -743,7 +743,7 @@ void Project::loadTilesetAssets(Tileset* tileset) { QString metatiles_path; QString metatile_attrs_path; QString metatiles_text = readTextFile(root + "/data/tilesets/metatiles.inc"); - QList *metatiles_macros = parser->parse(metatiles_text); + QList *metatiles_macros = parser->parseAsm(metatiles_text); QStringList *metatiles_values = getLabelValues(metatiles_macros, tileset->metatiles_label); if (!metatiles_values->isEmpty()) { metatiles_path = root + "/" + metatiles_values->value(0).section('"', 1, 1); @@ -918,8 +918,8 @@ void Project::readMapGroups() { if (text.isNull()) { return; } - Asm *parser = new Asm; - QList *commands = parser->parse(text); + ParseUtil *parser = new ParseUtil; + QList *commands = parser->parseAsm(text); bool in_group_pointers = false; QStringList *groups = new QStringList; @@ -1015,9 +1015,9 @@ QString Project::getNewMapName() { return newMapName; } -QList* Project::parse(QString text) { - Asm *parser = new Asm; - return parser->parse(text); +QList* Project::parseAsm(QString text) { + ParseUtil *parser = new ParseUtil; + return parser->parseAsm(text); } QStringList Project::getLocations() { @@ -1074,7 +1074,7 @@ void Project::readItemNames() { void Project::readFlagNames() { QString filepath = root + "/include/constants/flags.h"; QStringList prefixes = (QStringList() << "FLAG_"); - readCDefinesSorted(filepath, prefixes, flagNames, "SYSTEM_FLAGS", 0x800); + readCDefinesSorted(filepath, prefixes, flagNames); } void Project::readVarNames() { @@ -1084,13 +1084,9 @@ void Project::readVarNames() { } void Project::readCDefinesSorted(QString filepath, QStringList prefixes, QStringList* definesToSet) { - return readCDefinesSorted(filepath, prefixes, definesToSet, "", 0); -} - -void Project::readCDefinesSorted(QString filepath, QStringList prefixes, QStringList* definesToSet, QString hardcodedDefine, int hardcodedDefineValue) { QString text = readTextFile(filepath); if (!text.isNull()) { - QMap defines = readCDefines(text, prefixes, hardcodedDefine, hardcodedDefineValue); + QMap defines = readCDefines(text, prefixes); // The defines should to be sorted by their underlying value, not alphabetically. // Reverse the map and read out the resulting keys in order. @@ -1318,13 +1314,13 @@ void Project::readMapEvents(Map *map) { return; } - QStringList *labels = getLabelValues(parse(text), map->events_label); + QStringList *labels = getLabelValues(parseAsm(text), map->events_label); map->object_events_label = labels->value(0); map->warps_label = labels->value(1); map->coord_events_label = labels->value(2); map->bg_events_label = labels->value(3); - QList *object_events = getLabelMacros(parse(text), map->object_events_label); + QList *object_events = getLabelMacros(parseAsm(text), map->object_events_label); map->events["object"].clear(); for (QStringList command : *object_events) { if (command.value(0) == "object_event") { @@ -1368,7 +1364,7 @@ void Project::readMapEvents(Map *map) { } } - QList *warps = getLabelMacros(parse(text), map->warps_label); + QList *warps = getLabelMacros(parseAsm(text), map->warps_label); map->events["warp"].clear(); for (QStringList command : *warps) { if (command.value(0) == "warp_def") { @@ -1392,7 +1388,7 @@ void Project::readMapEvents(Map *map) { } } - QList *coords = getLabelMacros(parse(text), map->coord_events_label); + QList *coords = getLabelMacros(parseAsm(text), map->coord_events_label); map->events["trap"].clear(); map->events["trap_weather"].clear(); for (QStringList command : *coords) { @@ -1430,7 +1426,7 @@ void Project::readMapEvents(Map *map) { } } - QList *bgs = getLabelMacros(parse(text), map->bg_events_label); + QList *bgs = getLabelMacros(parseAsm(text), map->bg_events_label); map->events["sign"].clear(); map->events["event_hidden_item"].clear(); map->events["event_secret_base"].clear(); @@ -1535,41 +1531,23 @@ QString Project::readCIncbin(QString text, QString label) { } QMap Project::readCDefines(QString text, QStringList prefixes) { - return readCDefines(text, prefixes, "", 0); -} - -QMap Project::readCDefines(QString text, QStringList prefixes, QString hardcodedDefine, int hardcodedDefineValue) { - QMap defines; - - QString combinedPrefixes = "(" + prefixes.join('|') + ")"; - QString regex; - if (hardcodedDefine.isEmpty()) { - regex = QString("#define\\s+(?(%1)\\w+)\\s+(?\\w+)").arg(combinedPrefixes); - } else { - regex = QString("#define\\s+(?(%1)\\w+)\\s+\\(*(?\\\s*%2\\s+\\+\\s+)*(?\\w+\)\\)*").arg(combinedPrefixes, hardcodedDefine); - } - - QRegularExpression re(regex); + ParseUtil parser; + QMap allDefines; + QMap filteredDefines; + QRegularExpression re("#define\\s+(?\\w+)[^\\S\\n]+(?.+)"); QRegularExpressionMatchIterator iter = re.globalMatch(text); while (iter.hasNext()) { QRegularExpressionMatch match = iter.next(); QString name = match.captured("defineName"); - QString hardcodedDefineName = match.captured("hardcodedDefineName"); - QString value = match.captured("defineValue"); - bool valid; - int parsedValue = value.startsWith("0x") ? value.toInt(&valid, 16) : value.toInt(&valid, 10); - if (valid) { - int actualValue = parsedValue; - if (!hardcodedDefine.isEmpty() && !hardcodedDefineName.isEmpty()) { - actualValue += hardcodedDefineValue; + QString expression = match.captured("defineValue"); + expression.replace(QRegularExpression("//.*"), ""); + int value = parser.evaluateDefine(expression, &allDefines); + allDefines.insert(name, value); + for (QString prefix : prefixes) { + if (name.startsWith(prefix)) { + filteredDefines.insert(name, value); } - defines.insert(name, actualValue); - } else if (defines.contains(value)) { - defines.insert(name, defines.value(value)); - } else { - qDebug() << QString("Failed to parse define '%1' value '%2' as base 10 or hexadecimal value").arg(name, value); } } - - return defines; + return filteredDefines; } diff --git a/project.h b/project.h index 465b4fb9..43736c2a 100755 --- a/project.h +++ b/project.h @@ -67,7 +67,7 @@ public: void saveMapGroupsTable(); void saveMapConstantsHeader(); - QList* parse(QString text); + QList* parseAsm(QString text); QStringList getSongNames(); QStringList getLocations(); QStringList getVisibilities(); @@ -93,7 +93,6 @@ public: QStringList readCArray(QString text, QString label); QString readCIncbin(QString text, QString label); QMap readCDefines(QString text, QStringList prefixes); - QMap readCDefines(QString text, QStringList prefixes, QString hardcodedDefine, int hardcodedDefineValue); private: QString getMapAttributesTableFilepath(); QString getMapAssetsFilepath();