Browse Source

Evaluate C define expressions using postfix evaluation, and rename 'asm' to 'parseutil'

Marcus Huderle 6 years ago
parent
commit
af4dc34eba
7 changed files with 287 additions and 142 deletions
  1. 0
    59
      asm.cpp
  2. 0
    15
      asm.h
  3. 199
    0
      parseutil.cpp
  4. 43
    0
      parseutil.h
  5. 4
    4
      pretmap.pro
  6. 40
    62
      project.cpp
  7. 1
    2
      project.h

+ 0
- 59
asm.cpp View File

@@ -1,59 +0,0 @@
1
-#include "asm.h"
2
-
3
-Asm::Asm()
4
-{
5
-}
6
-
7
-void Asm::strip_comment(QString *line) {
8
-    bool in_string = false;
9
-    for (int i = 0; i < line->length(); i++) {
10
-        if (line->at(i) == '"') {
11
-            in_string = !in_string;
12
-        } else if (line->at(i) == '@') {
13
-            if (!in_string) {
14
-                line->truncate(i);
15
-                break;
16
-            }
17
-        }
18
-    }
19
-}
20
-
21
-QList<QStringList>* Asm::parse(QString text) {
22
-    QList<QStringList> *parsed = new QList<QStringList>;
23
-    QStringList lines = text.split('\n');
24
-    for (QString line : lines) {
25
-        QString label;
26
-        //QString macro;
27
-        //QStringList *params;
28
-        strip_comment(&line);
29
-        if (line.trimmed().isEmpty()) {
30
-        } else if (line.contains(':')) {
31
-            label = line.left(line.indexOf(':'));
32
-            QStringList *list = new QStringList;
33
-            list->append(".label"); // This is not a real keyword. It's used only to make the output more regular.
34
-            list->append(label);
35
-            parsed->append(*list);
36
-            // There should not be anything else on the line.
37
-            // gas will raise a syntax error if there is.
38
-        } else {
39
-            line = line.trimmed();
40
-            //parsed->append(line.split(QRegExp("\\s*,\\s*")));
41
-            QString macro;
42
-            QStringList params;
43
-            int index = line.indexOf(QRegExp("\\s+"));
44
-            macro = line.left(index);
45
-            params = line.right(line.length() - index).trimmed().split(QRegExp("\\s*,\\s*"));
46
-            params.prepend(macro);
47
-            parsed->append(params);
48
-        }
49
-        //if (macro != NULL) {
50
-        //    if (macros->contains(macro)) {
51
-        //        void* function = macros->value(macro);
52
-        //        if (function != NULL) {
53
-        //            std::function function(params);
54
-        //        }
55
-        //    }
56
-        //}
57
-    }
58
-    return parsed;
59
-}

+ 0
- 15
asm.h View File

@@ -1,15 +0,0 @@
1
-#ifndef ASM_H
2
-#define ASM_H
3
-
4
-#include <QString>
5
-#include <QList>
6
-
7
-class Asm
8
-{
9
-public:
10
-    Asm();
11
-    void strip_comment(QString*);
12
-    QList<QStringList>* parse(QString);
13
-};
14
-
15
-#endif // ASM_H

+ 199
- 0
parseutil.cpp View File

@@ -0,0 +1,199 @@
1
+#include "parseutil.h"
2
+
3
+#include <QDebug>
4
+#include <QRegularExpression>
5
+#include <QStack>
6
+
7
+ParseUtil::ParseUtil()
8
+{
9
+}
10
+
11
+void ParseUtil::strip_comment(QString *line) {
12
+    bool in_string = false;
13
+    for (int i = 0; i < line->length(); i++) {
14
+        if (line->at(i) == '"') {
15
+            in_string = !in_string;
16
+        } else if (line->at(i) == '@') {
17
+            if (!in_string) {
18
+                line->truncate(i);
19
+                break;
20
+            }
21
+        }
22
+    }
23
+}
24
+
25
+QList<QStringList>* ParseUtil::parseAsm(QString text) {
26
+    QList<QStringList> *parsed = new QList<QStringList>;
27
+    QStringList lines = text.split('\n');
28
+    for (QString line : lines) {
29
+        QString label;
30
+        //QString macro;
31
+        //QStringList *params;
32
+        strip_comment(&line);
33
+        if (line.trimmed().isEmpty()) {
34
+        } else if (line.contains(':')) {
35
+            label = line.left(line.indexOf(':'));
36
+            QStringList *list = new QStringList;
37
+            list->append(".label"); // This is not a real keyword. It's used only to make the output more regular.
38
+            list->append(label);
39
+            parsed->append(*list);
40
+            // There should not be anything else on the line.
41
+            // gas will raise a syntax error if there is.
42
+        } else {
43
+            line = line.trimmed();
44
+            //parsed->append(line.split(QRegExp("\\s*,\\s*")));
45
+            QString macro;
46
+            QStringList params;
47
+            int index = line.indexOf(QRegExp("\\s+"));
48
+            macro = line.left(index);
49
+            params = line.right(line.length() - index).trimmed().split(QRegExp("\\s*,\\s*"));
50
+            params.prepend(macro);
51
+            parsed->append(params);
52
+        }
53
+        //if (macro != NULL) {
54
+        //    if (macros->contains(macro)) {
55
+        //        void* function = macros->value(macro);
56
+        //        if (function != NULL) {
57
+        //            std::function function(params);
58
+        //        }
59
+        //    }
60
+        //}
61
+    }
62
+    return parsed;
63
+}
64
+
65
+int ParseUtil::evaluateDefine(QString define, QMap<QString, int>* knownDefines) {
66
+    QList<Token> tokens = tokenizeExpression(define, knownDefines);
67
+    QList<Token> postfixExpression = generatePostfix(tokens);
68
+    return evaluatePostfix(postfixExpression);
69
+}
70
+
71
+QList<Token> ParseUtil::tokenizeExpression(QString expression, QMap<QString, int>* knownIdentifiers) {
72
+    QList<Token> tokens;
73
+
74
+    QStringList tokenTypes = (QStringList() << "hex" << "decimal" << "identifier" << "operator" << "leftparen" << "rightparen");
75
+    QRegularExpression re("^(?<hex>0x[0-9a-fA-F]+)|(?<decimal>[0-9]+)|(?<identifier>[a-zA-Z_0-9]+)|(?<operator>[+\\-*\\/<>|^%]+)|(?<leftparen>\\()|(?<rightparen>\\))");
76
+
77
+    expression = expression.trimmed();
78
+    while (!expression.isEmpty()) {
79
+        QRegularExpressionMatch match = re.match(expression);
80
+        if (!match.hasMatch()) {
81
+            qDebug() << "Failed to tokenize expression: " << expression;
82
+            break;
83
+        }
84
+        for (QString tokenType : tokenTypes) {
85
+            QString token = match.captured(tokenType);
86
+            if (!token.isEmpty()) {
87
+                if (tokenType == "identifier") {
88
+                    if (knownIdentifiers->contains(token)) {
89
+                        QString actualToken = QString("%1").arg(knownIdentifiers->value(token));
90
+                        expression = expression.replace(0, token.length(), actualToken);
91
+                        token = actualToken;
92
+                        tokenType = "decimal";
93
+                    } else {
94
+                        qDebug() << "Unknown identifier found in expression: " << token;
95
+                    }
96
+                }
97
+
98
+                tokens.append(Token(token, tokenType));
99
+                expression = expression.remove(0, token.length()).trimmed();
100
+                break;
101
+            }
102
+        }
103
+    }
104
+    return tokens;
105
+}
106
+
107
+QMap<QString, int> Token::precedenceMap = QMap<QString, int>(
108
+{
109
+    {"*", 3},
110
+    {"/", 3},
111
+    {"+", 4},
112
+    {"-", 4},
113
+    {"<<", 5},
114
+    {">>", 5},
115
+    {"&", 8},
116
+    {"^", 9},
117
+    {"|", 10}
118
+});
119
+
120
+// Shunting-yard algorithm for generating postfix notation.
121
+// https://en.wikipedia.org/wiki/Shunting-yard_algorithm
122
+QList<Token> ParseUtil::generatePostfix(QList<Token> tokens) {
123
+    QList<Token> output;
124
+    QStack<Token> operatorStack;
125
+    for (Token token : tokens) {
126
+        if (token.type == TokenType::Number) {
127
+            output.append(token);
128
+        } else if (token.value == "(") {
129
+            operatorStack.push(token);
130
+        } else if (token.value == ")") {
131
+            while (!operatorStack.empty() && operatorStack.top().value != "(") {
132
+                output.append(operatorStack.pop());
133
+            }
134
+            if (!operatorStack.empty()) {
135
+                // pop the left parenthesis token
136
+                operatorStack.pop();
137
+            } else {
138
+                qDebug() << "Mismatched parentheses detected in expression!";
139
+            }
140
+        } else {
141
+            // token is an operator
142
+            while (!operatorStack.isEmpty()
143
+                   && operatorStack.top().operatorPrecedence <= token.operatorPrecedence
144
+                   && operatorStack.top().value != "(") {
145
+                output.append(operatorStack.pop());
146
+            }
147
+            operatorStack.push(token);
148
+        }
149
+    }
150
+
151
+    while (!operatorStack.isEmpty()) {
152
+        if (operatorStack.top().value == "(" || operatorStack.top().value == ")") {
153
+            qDebug() << "Mismatched parentheses detected in expression!";
154
+        } else {
155
+            output.append(operatorStack.pop());
156
+        }
157
+    }
158
+
159
+    return output;
160
+}
161
+
162
+// Evaluate postfix expression.
163
+// https://en.wikipedia.org/wiki/Reverse_Polish_notation#Postfix_evaluation_algorithm
164
+int ParseUtil::evaluatePostfix(QList<Token> postfix) {
165
+    QStack<Token> stack;
166
+    for (Token token : postfix) {
167
+        if (token.type == TokenType::Operator) {
168
+            int op2 = stack.pop().value.toInt(nullptr, 0);
169
+            int op1 = stack.pop().value.toInt(nullptr, 0);
170
+            int result = 0;
171
+            if (token.value == "*") {
172
+                result = op1 * op2;
173
+            } else if (token.value == "/") {
174
+                result = op1 / op2;
175
+            } else if (token.value == "+") {
176
+                result = op1 + op2;
177
+            } else if (token.value == "-") {
178
+                result = op1 - op2;
179
+            } else if (token.value == "<<") {
180
+                result = op1 << op2;
181
+            } else if (token.value == ">>") {
182
+                result = op1 >> op2;
183
+            } else if (token.value == "&") {
184
+                result = op1 & op2;
185
+            } else if (token.value == "^") {
186
+                result = op1 ^ op2;
187
+            } else if (token.value == "|") {
188
+                result = op1 | op2;
189
+            } else {
190
+                qDebug() << "Unsupported postfix operator: " << token.value;
191
+            }
192
+            stack.push(Token(QString("%1").arg(result), "decimal"));
193
+        } else {
194
+            stack.push(token);
195
+        }
196
+    }
197
+
198
+    return stack.pop().value.toInt(nullptr, 0);
199
+}

+ 43
- 0
parseutil.h View File

@@ -0,0 +1,43 @@
1
+#ifndef PARSEUTIL_H
2
+#define PARSEUTIL_H
3
+
4
+#include <QString>
5
+#include <QList>
6
+
7
+enum TokenType {
8
+    Number,
9
+    Operator,
10
+};
11
+
12
+class Token {
13
+public:
14
+    Token(QString value = "", QString type = "") {
15
+        this->value = value;
16
+        this->type = TokenType::Operator;
17
+        if (type == "decimal" || type == "hex") {
18
+            this->type = TokenType::Number;
19
+            this->operatorPrecedence = -1;
20
+        } else if (type == "operator") {
21
+            this->operatorPrecedence = precedenceMap[value];
22
+        }
23
+    }
24
+    static QMap<QString, int> precedenceMap;
25
+    QString value;
26
+    TokenType type;
27
+    int operatorPrecedence; // only relevant for operator tokens
28
+};
29
+
30
+class ParseUtil
31
+{
32
+public:
33
+    ParseUtil();
34
+    void strip_comment(QString*);
35
+    QList<QStringList>* parseAsm(QString);
36
+    int evaluateDefine(QString, QMap<QString, int>*);
37
+private:
38
+    QList<Token> tokenizeExpression(QString expression, QMap<QString, int>* knownIdentifiers);
39
+    QList<Token> generatePostfix(QList<Token> tokens);
40
+    int evaluatePostfix(QList<Token> postfix);
41
+};
42
+
43
+#endif // PARSEUTIL_H

+ 4
- 4
pretmap.pro View File

@@ -15,7 +15,6 @@ TEMPLATE = app
15 15
 SOURCES += main.cpp\
16 16
         mainwindow.cpp \
17 17
     project.cpp \
18
-    asm.cpp \
19 18
     map.cpp \
20 19
     blockdata.cpp \
21 20
     block.cpp \
@@ -25,11 +24,11 @@ SOURCES += main.cpp\
25 24
     event.cpp \
26 25
     editor.cpp \
27 26
     objectpropertiesframe.cpp \
28
-    graphicsview.cpp
27
+    graphicsview.cpp \
28
+    parseutil.cpp
29 29
 
30 30
 HEADERS  += mainwindow.h \
31 31
     project.h \
32
-    asm.h \
33 32
     map.h \
34 33
     blockdata.h \
35 34
     block.h \
@@ -39,7 +38,8 @@ HEADERS  += mainwindow.h \
39 38
     event.h \
40 39
     editor.h \
41 40
     objectpropertiesframe.h \
42
-    graphicsview.h
41
+    graphicsview.h \
42
+    parseutil.h
43 43
 
44 44
 FORMS    += mainwindow.ui \
45 45
     objectpropertiesframe.ui

+ 40
- 62
project.cpp View File

@@ -1,4 +1,4 @@
1
-#include "asm.h"
1
+#include "parseutil.h"
2 2
 #include "project.h"
3 3
 #include "tile.h"
4 4
 #include "tileset.h"
@@ -71,7 +71,7 @@ void Project::loadMapConnections(Map *map) {
71 71
         QString path = root + QString("/data/maps/%1/connections.inc").arg(map->name);
72 72
         QString text = readTextFile(path);
73 73
         if (!text.isNull()) {
74
-            QList<QStringList> *commands = parse(text);
74
+            QList<QStringList> *commands = parseAsm(text);
75 75
             QStringList *list = getLabelValues(commands, map->connections_label);
76 76
 
77 77
             //// Avoid using this value. It ought to be generated instead.
@@ -150,13 +150,13 @@ void Project::readMapHeader(Map* map) {
150 150
     }
151 151
 
152 152
     QString label = map->name;
153
-    Asm *parser = new Asm;
153
+    ParseUtil *parser = new ParseUtil;
154 154
 
155 155
     QString header_text = readTextFile(root + "/data/maps/" + label + "/header.inc");
156 156
     if (header_text.isNull()) {
157 157
         return;
158 158
     }
159
-    QStringList *header = getLabelValues(parser->parse(header_text), label);
159
+    QStringList *header = getLabelValues(parser->parseAsm(header_text), label);
160 160
     map->attributes_label = header->value(0);
161 161
     map->events_label = header->value(1);
162 162
     map->scripts_label = header->value(2);
@@ -212,7 +212,7 @@ void Project::saveMapHeader(Map *map) {
212 212
 void Project::readMapAttributesTable() {
213 213
     int curMapIndex = 1;
214 214
     QString attributesText = readTextFile(getMapAttributesTableFilepath());
215
-    QList<QStringList>* values = parse(attributesText);
215
+    QList<QStringList>* values = parseAsm(attributesText);
216 216
     bool inAttributePointers = false;
217 217
     for (int i = 0; i < values->length(); i++) {
218 218
         QStringList params = values->value(i);
@@ -265,13 +265,13 @@ void Project::readMapAttributes(Map* map) {
265 265
         return;
266 266
     }
267 267
 
268
-    Asm *parser = new Asm;
268
+    ParseUtil *parser = new ParseUtil;
269 269
 
270 270
     QString assets_text = readTextFile(getMapAssetsFilepath());
271 271
     if (assets_text.isNull()) {
272 272
         return;
273 273
     }
274
-    QStringList *attributes = getLabelValues(parser->parse(assets_text), map->attributes_label);
274
+    QStringList *attributes = getLabelValues(parser->parseAsm(assets_text), map->attributes_label);
275 275
     map->width = attributes->value(0);
276 276
     map->height = attributes->value(1);
277 277
     map->border_label = attributes->value(2);
@@ -283,13 +283,13 @@ void Project::readMapAttributes(Map* map) {
283 283
 void Project::readAllMapAttributes() {
284 284
     mapAttributes.clear();
285 285
 
286
-    Asm *parser = new Asm;
286
+    ParseUtil *parser = new ParseUtil;
287 287
     QString assets_text = readTextFile(getMapAssetsFilepath());
288 288
     if (assets_text.isNull()) {
289 289
         return;
290 290
     }
291 291
 
292
-    QList<QStringList> *commands = parser->parse(assets_text);
292
+    QList<QStringList> *commands = parser->parseAsm(assets_text);
293 293
 
294 294
     // Assume the _assets.inc file is grouped consistently in the order of:
295 295
     // 1. <map_name>_MapBorder
@@ -539,10 +539,10 @@ void Project::getTilesets(Map* map) {
539 539
 }
540 540
 
541 541
 Tileset* Project::loadTileset(QString label) {
542
-    Asm *parser = new Asm;
542
+    ParseUtil *parser = new ParseUtil;
543 543
 
544 544
     QString headers_text = readTextFile(root + "/data/tilesets/headers.inc");
545
-    QStringList *values = getLabelValues(parser->parse(headers_text), label);
545
+    QStringList *values = getLabelValues(parser->parseAsm(headers_text), label);
546 546
     Tileset *tileset = new Tileset;
547 547
     tileset->name = label;
548 548
     tileset->is_compressed = values->value(0);
@@ -562,7 +562,7 @@ Tileset* Project::loadTileset(QString label) {
562 562
 
563 563
 QString Project::getBlockdataPath(Map* map) {
564 564
     QString text = readTextFile(getMapAssetsFilepath());
565
-    QStringList *values = getLabelValues(parse(text), map->blockdata_label);
565
+    QStringList *values = getLabelValues(parseAsm(text), map->blockdata_label);
566 566
     QString path;
567 567
     if (!values->isEmpty()) {
568 568
         path = root + "/" + values->value(0).section('"', 1, 1);
@@ -574,7 +574,7 @@ QString Project::getBlockdataPath(Map* map) {
574 574
 
575 575
 QString Project::getMapBorderPath(Map *map) {
576 576
     QString text = readTextFile(getMapAssetsFilepath());
577
-    QStringList *values = getLabelValues(parse(text), map->border_label);
577
+    QStringList *values = getLabelValues(parseAsm(text), map->border_label);
578 578
     QString path;
579 579
     if (!values->isEmpty()) {
580 580
         path = root + "/" + values->value(0).section('"', 1, 1);
@@ -705,7 +705,7 @@ void Project::saveAllDataStructures() {
705 705
 }
706 706
 
707 707
 void Project::loadTilesetAssets(Tileset* tileset) {
708
-    Asm* parser = new Asm;
708
+    ParseUtil* parser = new ParseUtil;
709 709
     QString category = (tileset->is_secondary == "TRUE") ? "secondary" : "primary";
710 710
     if (tileset->name.isNull()) {
711 711
         return;
@@ -713,7 +713,7 @@ void Project::loadTilesetAssets(Tileset* tileset) {
713 713
     QString dir_path = root + "/data/tilesets/" + category + "/" + tileset->name.replace("gTileset_", "").toLower();
714 714
 
715 715
     QString graphics_text = readTextFile(root + "/data/tilesets/graphics.inc");
716
-    QList<QStringList> *graphics = parser->parse(graphics_text);
716
+    QList<QStringList> *graphics = parser->parseAsm(graphics_text);
717 717
     QStringList *tiles_values = getLabelValues(graphics, tileset->tiles_label);
718 718
     QStringList *palettes_values = getLabelValues(graphics, tileset->palettes_label);
719 719
 
@@ -743,7 +743,7 @@ void Project::loadTilesetAssets(Tileset* tileset) {
743 743
     QString metatiles_path;
744 744
     QString metatile_attrs_path;
745 745
     QString metatiles_text = readTextFile(root + "/data/tilesets/metatiles.inc");
746
-    QList<QStringList> *metatiles_macros = parser->parse(metatiles_text);
746
+    QList<QStringList> *metatiles_macros = parser->parseAsm(metatiles_text);
747 747
     QStringList *metatiles_values = getLabelValues(metatiles_macros, tileset->metatiles_label);
748 748
     if (!metatiles_values->isEmpty()) {
749 749
         metatiles_path = root + "/" + metatiles_values->value(0).section('"', 1, 1);
@@ -918,8 +918,8 @@ void Project::readMapGroups() {
918 918
     if (text.isNull()) {
919 919
         return;
920 920
     }
921
-    Asm *parser = new Asm;
922
-    QList<QStringList> *commands = parser->parse(text);
921
+    ParseUtil *parser = new ParseUtil;
922
+    QList<QStringList> *commands = parser->parseAsm(text);
923 923
 
924 924
     bool in_group_pointers = false;
925 925
     QStringList *groups = new QStringList;
@@ -1015,9 +1015,9 @@ QString Project::getNewMapName() {
1015 1015
     return newMapName;
1016 1016
 }
1017 1017
 
1018
-QList<QStringList>* Project::parse(QString text) {
1019
-    Asm *parser = new Asm;
1020
-    return parser->parse(text);
1018
+QList<QStringList>* Project::parseAsm(QString text) {
1019
+    ParseUtil *parser = new ParseUtil;
1020
+    return parser->parseAsm(text);
1021 1021
 }
1022 1022
 
1023 1023
 QStringList Project::getLocations() {
@@ -1074,7 +1074,7 @@ void Project::readItemNames() {
1074 1074
 void Project::readFlagNames() {
1075 1075
     QString filepath = root + "/include/constants/flags.h";
1076 1076
     QStringList prefixes = (QStringList() << "FLAG_");
1077
-    readCDefinesSorted(filepath, prefixes, flagNames, "SYSTEM_FLAGS", 0x800);
1077
+    readCDefinesSorted(filepath, prefixes, flagNames);
1078 1078
 }
1079 1079
 
1080 1080
 void Project::readVarNames() {
@@ -1084,13 +1084,9 @@ void Project::readVarNames() {
1084 1084
 }
1085 1085
 
1086 1086
 void Project::readCDefinesSorted(QString filepath, QStringList prefixes, QStringList* definesToSet) {
1087
-    return readCDefinesSorted(filepath, prefixes, definesToSet, "", 0);
1088
-}
1089
-
1090
-void Project::readCDefinesSorted(QString filepath, QStringList prefixes, QStringList* definesToSet, QString hardcodedDefine, int hardcodedDefineValue) {
1091 1087
     QString text = readTextFile(filepath);
1092 1088
     if (!text.isNull()) {
1093
-        QMap<QString, int> defines = readCDefines(text, prefixes, hardcodedDefine, hardcodedDefineValue);
1089
+        QMap<QString, int> defines = readCDefines(text, prefixes);
1094 1090
 
1095 1091
         // The defines should to be sorted by their underlying value, not alphabetically.
1096 1092
         // Reverse the map and read out the resulting keys in order.
@@ -1318,13 +1314,13 @@ void Project::readMapEvents(Map *map) {
1318 1314
         return;
1319 1315
     }
1320 1316
 
1321
-    QStringList *labels = getLabelValues(parse(text), map->events_label);
1317
+    QStringList *labels = getLabelValues(parseAsm(text), map->events_label);
1322 1318
     map->object_events_label = labels->value(0);
1323 1319
     map->warps_label = labels->value(1);
1324 1320
     map->coord_events_label = labels->value(2);
1325 1321
     map->bg_events_label = labels->value(3);
1326 1322
 
1327
-    QList<QStringList> *object_events = getLabelMacros(parse(text), map->object_events_label);
1323
+    QList<QStringList> *object_events = getLabelMacros(parseAsm(text), map->object_events_label);
1328 1324
     map->events["object"].clear();
1329 1325
     for (QStringList command : *object_events) {
1330 1326
         if (command.value(0) == "object_event") {
@@ -1368,7 +1364,7 @@ void Project::readMapEvents(Map *map) {
1368 1364
         }
1369 1365
     }
1370 1366
 
1371
-    QList<QStringList> *warps = getLabelMacros(parse(text), map->warps_label);
1367
+    QList<QStringList> *warps = getLabelMacros(parseAsm(text), map->warps_label);
1372 1368
     map->events["warp"].clear();
1373 1369
     for (QStringList command : *warps) {
1374 1370
         if (command.value(0) == "warp_def") {
@@ -1392,7 +1388,7 @@ void Project::readMapEvents(Map *map) {
1392 1388
         }
1393 1389
     }
1394 1390
 
1395
-    QList<QStringList> *coords = getLabelMacros(parse(text), map->coord_events_label);
1391
+    QList<QStringList> *coords = getLabelMacros(parseAsm(text), map->coord_events_label);
1396 1392
     map->events["trap"].clear();
1397 1393
     map->events["trap_weather"].clear();
1398 1394
     for (QStringList command : *coords) {
@@ -1430,7 +1426,7 @@ void Project::readMapEvents(Map *map) {
1430 1426
         }
1431 1427
     }
1432 1428
 
1433
-    QList<QStringList> *bgs = getLabelMacros(parse(text), map->bg_events_label);
1429
+    QList<QStringList> *bgs = getLabelMacros(parseAsm(text), map->bg_events_label);
1434 1430
     map->events["sign"].clear();
1435 1431
     map->events["event_hidden_item"].clear();
1436 1432
     map->events["event_secret_base"].clear();
@@ -1535,41 +1531,23 @@ QString Project::readCIncbin(QString text, QString label) {
1535 1531
 }
1536 1532
 
1537 1533
 QMap<QString, int> Project::readCDefines(QString text, QStringList prefixes) {
1538
-    return readCDefines(text, prefixes, "", 0);
1539
-}
1540
-
1541
-QMap<QString, int> Project::readCDefines(QString text, QStringList prefixes, QString hardcodedDefine, int hardcodedDefineValue) {
1542
-    QMap<QString, int> defines;
1543
-
1544
-    QString combinedPrefixes = "(" + prefixes.join('|') + ")";
1545
-    QString regex;
1546
-    if (hardcodedDefine.isEmpty()) {
1547
-        regex = QString("#define\\s+(?<defineName>(%1)\\w+)\\s+(?<defineValue>\\w+)").arg(combinedPrefixes);
1548
-    } else {
1549
-        regex = QString("#define\\s+(?<defineName>(%1)\\w+)\\s+\\(*(?<hardcodedDefineName>\\\s*%2\\s+\\+\\s+)*(?<defineValue>\\w+\)\\)*").arg(combinedPrefixes, hardcodedDefine);
1550
-    }
1551
-
1552
-    QRegularExpression re(regex);
1534
+    ParseUtil parser;
1535
+    QMap<QString, int> allDefines;
1536
+    QMap<QString, int> filteredDefines;
1537
+    QRegularExpression re("#define\\s+(?<defineName>\\w+)[^\\S\\n]+(?<defineValue>.+)");
1553 1538
     QRegularExpressionMatchIterator iter = re.globalMatch(text);
1554 1539
     while (iter.hasNext()) {
1555 1540
         QRegularExpressionMatch match = iter.next();
1556 1541
         QString name = match.captured("defineName");
1557
-        QString hardcodedDefineName = match.captured("hardcodedDefineName");
1558
-        QString value = match.captured("defineValue");
1559
-        bool valid;
1560
-        int parsedValue = value.startsWith("0x") ? value.toInt(&valid, 16) : value.toInt(&valid, 10);
1561
-        if (valid) {
1562
-            int actualValue = parsedValue;
1563
-            if (!hardcodedDefine.isEmpty() && !hardcodedDefineName.isEmpty()) {
1564
-                actualValue += hardcodedDefineValue;
1542
+        QString expression = match.captured("defineValue");
1543
+        expression.replace(QRegularExpression("//.*"), "");
1544
+        int value = parser.evaluateDefine(expression, &allDefines);
1545
+        allDefines.insert(name, value);
1546
+        for (QString prefix : prefixes) {
1547
+            if (name.startsWith(prefix)) {
1548
+                filteredDefines.insert(name, value);
1565 1549
             }
1566
-            defines.insert(name, actualValue);
1567
-        } else if (defines.contains(value)) {
1568
-            defines.insert(name, defines.value(value));
1569
-        } else {
1570
-            qDebug() << QString("Failed to parse define '%1' value '%2' as base 10 or hexadecimal value").arg(name, value);
1571 1550
         }
1572 1551
     }
1573
-
1574
-    return defines;
1552
+    return filteredDefines;
1575 1553
 }

+ 1
- 2
project.h View File

@@ -67,7 +67,7 @@ public:
67 67
     void saveMapGroupsTable();
68 68
     void saveMapConstantsHeader();
69 69
 
70
-    QList<QStringList>* parse(QString text);
70
+    QList<QStringList>* parseAsm(QString text);
71 71
     QStringList getSongNames();
72 72
     QStringList getLocations();
73 73
     QStringList getVisibilities();
@@ -93,7 +93,6 @@ public:
93 93
     QStringList readCArray(QString text, QString label);
94 94
     QString readCIncbin(QString text, QString label);
95 95
     QMap<QString, int> readCDefines(QString text, QStringList prefixes);
96
-    QMap<QString, int> readCDefines(QString text, QStringList prefixes, QString hardcodedDefine, int hardcodedDefineValue);
97 96
 private:
98 97
     QString getMapAttributesTableFilepath();
99 98
     QString getMapAssetsFilepath();