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
-#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
-#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

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

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
 SOURCES += main.cpp\
15
 SOURCES += main.cpp\
16
         mainwindow.cpp \
16
         mainwindow.cpp \
17
     project.cpp \
17
     project.cpp \
18
-    asm.cpp \
19
     map.cpp \
18
     map.cpp \
20
     blockdata.cpp \
19
     blockdata.cpp \
21
     block.cpp \
20
     block.cpp \
25
     event.cpp \
24
     event.cpp \
26
     editor.cpp \
25
     editor.cpp \
27
     objectpropertiesframe.cpp \
26
     objectpropertiesframe.cpp \
28
-    graphicsview.cpp
27
+    graphicsview.cpp \
28
+    parseutil.cpp
29
 
29
 
30
 HEADERS  += mainwindow.h \
30
 HEADERS  += mainwindow.h \
31
     project.h \
31
     project.h \
32
-    asm.h \
33
     map.h \
32
     map.h \
34
     blockdata.h \
33
     blockdata.h \
35
     block.h \
34
     block.h \
39
     event.h \
38
     event.h \
40
     editor.h \
39
     editor.h \
41
     objectpropertiesframe.h \
40
     objectpropertiesframe.h \
42
-    graphicsview.h
41
+    graphicsview.h \
42
+    parseutil.h
43
 
43
 
44
 FORMS    += mainwindow.ui \
44
 FORMS    += mainwindow.ui \
45
     objectpropertiesframe.ui
45
     objectpropertiesframe.ui

+ 40
- 62
project.cpp View File

1
-#include "asm.h"
1
+#include "parseutil.h"
2
 #include "project.h"
2
 #include "project.h"
3
 #include "tile.h"
3
 #include "tile.h"
4
 #include "tileset.h"
4
 #include "tileset.h"
71
         QString path = root + QString("/data/maps/%1/connections.inc").arg(map->name);
71
         QString path = root + QString("/data/maps/%1/connections.inc").arg(map->name);
72
         QString text = readTextFile(path);
72
         QString text = readTextFile(path);
73
         if (!text.isNull()) {
73
         if (!text.isNull()) {
74
-            QList<QStringList> *commands = parse(text);
74
+            QList<QStringList> *commands = parseAsm(text);
75
             QStringList *list = getLabelValues(commands, map->connections_label);
75
             QStringList *list = getLabelValues(commands, map->connections_label);
76
 
76
 
77
             //// Avoid using this value. It ought to be generated instead.
77
             //// Avoid using this value. It ought to be generated instead.
150
     }
150
     }
151
 
151
 
152
     QString label = map->name;
152
     QString label = map->name;
153
-    Asm *parser = new Asm;
153
+    ParseUtil *parser = new ParseUtil;
154
 
154
 
155
     QString header_text = readTextFile(root + "/data/maps/" + label + "/header.inc");
155
     QString header_text = readTextFile(root + "/data/maps/" + label + "/header.inc");
156
     if (header_text.isNull()) {
156
     if (header_text.isNull()) {
157
         return;
157
         return;
158
     }
158
     }
159
-    QStringList *header = getLabelValues(parser->parse(header_text), label);
159
+    QStringList *header = getLabelValues(parser->parseAsm(header_text), label);
160
     map->attributes_label = header->value(0);
160
     map->attributes_label = header->value(0);
161
     map->events_label = header->value(1);
161
     map->events_label = header->value(1);
162
     map->scripts_label = header->value(2);
162
     map->scripts_label = header->value(2);
212
 void Project::readMapAttributesTable() {
212
 void Project::readMapAttributesTable() {
213
     int curMapIndex = 1;
213
     int curMapIndex = 1;
214
     QString attributesText = readTextFile(getMapAttributesTableFilepath());
214
     QString attributesText = readTextFile(getMapAttributesTableFilepath());
215
-    QList<QStringList>* values = parse(attributesText);
215
+    QList<QStringList>* values = parseAsm(attributesText);
216
     bool inAttributePointers = false;
216
     bool inAttributePointers = false;
217
     for (int i = 0; i < values->length(); i++) {
217
     for (int i = 0; i < values->length(); i++) {
218
         QStringList params = values->value(i);
218
         QStringList params = values->value(i);
265
         return;
265
         return;
266
     }
266
     }
267
 
267
 
268
-    Asm *parser = new Asm;
268
+    ParseUtil *parser = new ParseUtil;
269
 
269
 
270
     QString assets_text = readTextFile(getMapAssetsFilepath());
270
     QString assets_text = readTextFile(getMapAssetsFilepath());
271
     if (assets_text.isNull()) {
271
     if (assets_text.isNull()) {
272
         return;
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
     map->width = attributes->value(0);
275
     map->width = attributes->value(0);
276
     map->height = attributes->value(1);
276
     map->height = attributes->value(1);
277
     map->border_label = attributes->value(2);
277
     map->border_label = attributes->value(2);
283
 void Project::readAllMapAttributes() {
283
 void Project::readAllMapAttributes() {
284
     mapAttributes.clear();
284
     mapAttributes.clear();
285
 
285
 
286
-    Asm *parser = new Asm;
286
+    ParseUtil *parser = new ParseUtil;
287
     QString assets_text = readTextFile(getMapAssetsFilepath());
287
     QString assets_text = readTextFile(getMapAssetsFilepath());
288
     if (assets_text.isNull()) {
288
     if (assets_text.isNull()) {
289
         return;
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
     // Assume the _assets.inc file is grouped consistently in the order of:
294
     // Assume the _assets.inc file is grouped consistently in the order of:
295
     // 1. <map_name>_MapBorder
295
     // 1. <map_name>_MapBorder
539
 }
539
 }
540
 
540
 
541
 Tileset* Project::loadTileset(QString label) {
541
 Tileset* Project::loadTileset(QString label) {
542
-    Asm *parser = new Asm;
542
+    ParseUtil *parser = new ParseUtil;
543
 
543
 
544
     QString headers_text = readTextFile(root + "/data/tilesets/headers.inc");
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
     Tileset *tileset = new Tileset;
546
     Tileset *tileset = new Tileset;
547
     tileset->name = label;
547
     tileset->name = label;
548
     tileset->is_compressed = values->value(0);
548
     tileset->is_compressed = values->value(0);
562
 
562
 
563
 QString Project::getBlockdataPath(Map* map) {
563
 QString Project::getBlockdataPath(Map* map) {
564
     QString text = readTextFile(getMapAssetsFilepath());
564
     QString text = readTextFile(getMapAssetsFilepath());
565
-    QStringList *values = getLabelValues(parse(text), map->blockdata_label);
565
+    QStringList *values = getLabelValues(parseAsm(text), map->blockdata_label);
566
     QString path;
566
     QString path;
567
     if (!values->isEmpty()) {
567
     if (!values->isEmpty()) {
568
         path = root + "/" + values->value(0).section('"', 1, 1);
568
         path = root + "/" + values->value(0).section('"', 1, 1);
574
 
574
 
575
 QString Project::getMapBorderPath(Map *map) {
575
 QString Project::getMapBorderPath(Map *map) {
576
     QString text = readTextFile(getMapAssetsFilepath());
576
     QString text = readTextFile(getMapAssetsFilepath());
577
-    QStringList *values = getLabelValues(parse(text), map->border_label);
577
+    QStringList *values = getLabelValues(parseAsm(text), map->border_label);
578
     QString path;
578
     QString path;
579
     if (!values->isEmpty()) {
579
     if (!values->isEmpty()) {
580
         path = root + "/" + values->value(0).section('"', 1, 1);
580
         path = root + "/" + values->value(0).section('"', 1, 1);
705
 }
705
 }
706
 
706
 
707
 void Project::loadTilesetAssets(Tileset* tileset) {
707
 void Project::loadTilesetAssets(Tileset* tileset) {
708
-    Asm* parser = new Asm;
708
+    ParseUtil* parser = new ParseUtil;
709
     QString category = (tileset->is_secondary == "TRUE") ? "secondary" : "primary";
709
     QString category = (tileset->is_secondary == "TRUE") ? "secondary" : "primary";
710
     if (tileset->name.isNull()) {
710
     if (tileset->name.isNull()) {
711
         return;
711
         return;
713
     QString dir_path = root + "/data/tilesets/" + category + "/" + tileset->name.replace("gTileset_", "").toLower();
713
     QString dir_path = root + "/data/tilesets/" + category + "/" + tileset->name.replace("gTileset_", "").toLower();
714
 
714
 
715
     QString graphics_text = readTextFile(root + "/data/tilesets/graphics.inc");
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
     QStringList *tiles_values = getLabelValues(graphics, tileset->tiles_label);
717
     QStringList *tiles_values = getLabelValues(graphics, tileset->tiles_label);
718
     QStringList *palettes_values = getLabelValues(graphics, tileset->palettes_label);
718
     QStringList *palettes_values = getLabelValues(graphics, tileset->palettes_label);
719
 
719
 
743
     QString metatiles_path;
743
     QString metatiles_path;
744
     QString metatile_attrs_path;
744
     QString metatile_attrs_path;
745
     QString metatiles_text = readTextFile(root + "/data/tilesets/metatiles.inc");
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
     QStringList *metatiles_values = getLabelValues(metatiles_macros, tileset->metatiles_label);
747
     QStringList *metatiles_values = getLabelValues(metatiles_macros, tileset->metatiles_label);
748
     if (!metatiles_values->isEmpty()) {
748
     if (!metatiles_values->isEmpty()) {
749
         metatiles_path = root + "/" + metatiles_values->value(0).section('"', 1, 1);
749
         metatiles_path = root + "/" + metatiles_values->value(0).section('"', 1, 1);
918
     if (text.isNull()) {
918
     if (text.isNull()) {
919
         return;
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
     bool in_group_pointers = false;
924
     bool in_group_pointers = false;
925
     QStringList *groups = new QStringList;
925
     QStringList *groups = new QStringList;
1015
     return newMapName;
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
 QStringList Project::getLocations() {
1023
 QStringList Project::getLocations() {
1074
 void Project::readFlagNames() {
1074
 void Project::readFlagNames() {
1075
     QString filepath = root + "/include/constants/flags.h";
1075
     QString filepath = root + "/include/constants/flags.h";
1076
     QStringList prefixes = (QStringList() << "FLAG_");
1076
     QStringList prefixes = (QStringList() << "FLAG_");
1077
-    readCDefinesSorted(filepath, prefixes, flagNames, "SYSTEM_FLAGS", 0x800);
1077
+    readCDefinesSorted(filepath, prefixes, flagNames);
1078
 }
1078
 }
1079
 
1079
 
1080
 void Project::readVarNames() {
1080
 void Project::readVarNames() {
1084
 }
1084
 }
1085
 
1085
 
1086
 void Project::readCDefinesSorted(QString filepath, QStringList prefixes, QStringList* definesToSet) {
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
     QString text = readTextFile(filepath);
1087
     QString text = readTextFile(filepath);
1092
     if (!text.isNull()) {
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
         // The defines should to be sorted by their underlying value, not alphabetically.
1091
         // The defines should to be sorted by their underlying value, not alphabetically.
1096
         // Reverse the map and read out the resulting keys in order.
1092
         // Reverse the map and read out the resulting keys in order.
1318
         return;
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
     map->object_events_label = labels->value(0);
1318
     map->object_events_label = labels->value(0);
1323
     map->warps_label = labels->value(1);
1319
     map->warps_label = labels->value(1);
1324
     map->coord_events_label = labels->value(2);
1320
     map->coord_events_label = labels->value(2);
1325
     map->bg_events_label = labels->value(3);
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
     map->events["object"].clear();
1324
     map->events["object"].clear();
1329
     for (QStringList command : *object_events) {
1325
     for (QStringList command : *object_events) {
1330
         if (command.value(0) == "object_event") {
1326
         if (command.value(0) == "object_event") {
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
     map->events["warp"].clear();
1368
     map->events["warp"].clear();
1373
     for (QStringList command : *warps) {
1369
     for (QStringList command : *warps) {
1374
         if (command.value(0) == "warp_def") {
1370
         if (command.value(0) == "warp_def") {
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
     map->events["trap"].clear();
1392
     map->events["trap"].clear();
1397
     map->events["trap_weather"].clear();
1393
     map->events["trap_weather"].clear();
1398
     for (QStringList command : *coords) {
1394
     for (QStringList command : *coords) {
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
     map->events["sign"].clear();
1430
     map->events["sign"].clear();
1435
     map->events["event_hidden_item"].clear();
1431
     map->events["event_hidden_item"].clear();
1436
     map->events["event_secret_base"].clear();
1432
     map->events["event_secret_base"].clear();
1535
 }
1531
 }
1536
 
1532
 
1537
 QMap<QString, int> Project::readCDefines(QString text, QStringList prefixes) {
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
     QRegularExpressionMatchIterator iter = re.globalMatch(text);
1538
     QRegularExpressionMatchIterator iter = re.globalMatch(text);
1554
     while (iter.hasNext()) {
1539
     while (iter.hasNext()) {
1555
         QRegularExpressionMatch match = iter.next();
1540
         QRegularExpressionMatch match = iter.next();
1556
         QString name = match.captured("defineName");
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
     void saveMapGroupsTable();
67
     void saveMapGroupsTable();
68
     void saveMapConstantsHeader();
68
     void saveMapConstantsHeader();
69
 
69
 
70
-    QList<QStringList>* parse(QString text);
70
+    QList<QStringList>* parseAsm(QString text);
71
     QStringList getSongNames();
71
     QStringList getSongNames();
72
     QStringList getLocations();
72
     QStringList getLocations();
73
     QStringList getVisibilities();
73
     QStringList getVisibilities();
93
     QStringList readCArray(QString text, QString label);
93
     QStringList readCArray(QString text, QString label);
94
     QString readCIncbin(QString text, QString label);
94
     QString readCIncbin(QString text, QString label);
95
     QMap<QString, int> readCDefines(QString text, QStringList prefixes);
95
     QMap<QString, int> readCDefines(QString text, QStringList prefixes);
96
-    QMap<QString, int> readCDefines(QString text, QStringList prefixes, QString hardcodedDefine, int hardcodedDefineValue);
97
 private:
96
 private:
98
     QString getMapAttributesTableFilepath();
97
     QString getMapAttributesTableFilepath();
99
     QString getMapAssetsFilepath();
98
     QString getMapAssetsFilepath();