Browse Source

Merge pull request #23 from huderlem/items

Populate items, flags, and vars in dropdown menus
yenatch 6 years ago
parent
commit
470fc92fba
No account linked to committer's email address
8 changed files with 356 additions and 156 deletions
  1. 0
    59
      asm.cpp
  2. 0
    15
      asm.h
  3. 23
    9
      mainwindow.cpp
  4. 199
    0
      parseutil.cpp
  5. 43
    0
      parseutil.h
  6. 4
    4
      pretmap.pro
  7. 78
    66
      project.cpp
  8. 9
    3
      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

+ 23
- 9
mainwindow.cpp View File

203
 
203
 
204
     QStringList songs = project->getSongNames();
204
     QStringList songs = project->getSongNames();
205
     ui->comboBox_Song->addItems(songs);
205
     ui->comboBox_Song->addItems(songs);
206
-    QString song = map->song;
207
-    if (!songs.contains(song)) {
208
-        song = project->getSongName(song.toInt());
209
-    }
210
-    ui->comboBox_Song->setCurrentText(song);
206
+    ui->comboBox_Song->setCurrentText(map->song);
211
 
207
 
212
     ui->comboBox_Location->addItems(project->getLocations());
208
     ui->comboBox_Location->addItems(project->getLocations());
213
     ui->comboBox_Location->setCurrentText(map->location);
209
     ui->comboBox_Location->setCurrentText(map->location);
284
     Project *project = editor->project;
280
     Project *project = editor->project;
285
     project->readMapAttributesTable();
281
     project->readMapAttributesTable();
286
     project->readAllMapAttributes();
282
     project->readAllMapAttributes();
283
+    project->readItemNames();
284
+    project->readFlagNames();
285
+    project->readVarNames();
287
 }
286
 }
288
 
287
 
289
 void MainWindow::populateMapList() {
288
 void MainWindow::populateMapList() {
569
         field_labels["sight_radius"] = "Sight Radius";
568
         field_labels["sight_radius"] = "Sight Radius";
570
         field_labels["destination_warp"] = "Destination Warp";
569
         field_labels["destination_warp"] = "Destination Warp";
571
         field_labels["destination_map_name"] = "Destination Map";
570
         field_labels["destination_map_name"] = "Destination Map";
572
-        field_labels["coord_unknown1"] = "Unknown 1";
573
-        field_labels["coord_unknown2"] = "Unknown 2";
571
+        field_labels["script_var"] = "Var";
572
+        field_labels["script_var_value"] = "Var Value";
574
         field_labels["type"] = "Type";
573
         field_labels["type"] = "Type";
575
         field_labels["item"] = "Item";
574
         field_labels["item"] = "Item";
576
         field_labels["item_unknown5"] = "Unknown 5";
575
         field_labels["item_unknown5"] = "Unknown 5";
613
         }
612
         }
614
         else if (event_type == "trap") {
613
         else if (event_type == "trap") {
615
             fields << "script_label";
614
             fields << "script_label";
616
-            fields << "coord_unknown1";
617
-            fields << "coord_unknown2";
615
+            fields << "script_var";
616
+            fields << "script_var_value";
618
         }
617
         }
619
         else if (event_type == "trap_weather") {
618
         else if (event_type == "trap_weather") {
620
             fields << "weather";
619
             fields << "weather";
644
                     combo->addItem(value);
643
                     combo->addItem(value);
645
                 }
644
                 }
646
                 combo->addItems(*editor->project->mapNames);
645
                 combo->addItems(*editor->project->mapNames);
646
+            } else if (key == "item") {
647
+                if (!editor->project->itemNames->contains(value)) {
648
+                    combo->addItem(value);
649
+                }
650
+                combo->addItems(*editor->project->itemNames);
651
+            } else if (key == "flag") {
652
+                if (!editor->project->flagNames->contains(value)) {
653
+                    combo->addItem(value);
654
+                }
655
+                combo->addItems(*editor->project->flagNames);
656
+            } else if (key == "script_var") {
657
+                if (!editor->project->varNames->contains(value)) {
658
+                    combo->addItem(value);
659
+                }
660
+                combo->addItems(*editor->project->varNames);
647
             } else {
661
             } else {
648
                 combo->addItem(value);
662
                 combo->addItem(value);
649
             }
663
             }

+ 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

+ 78
- 66
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"
18
     groupNames = new QStringList;
18
     groupNames = new QStringList;
19
     map_groups = new QMap<QString, int>;
19
     map_groups = new QMap<QString, int>;
20
     mapNames = new QStringList;
20
     mapNames = new QStringList;
21
+    itemNames = new QStringList;
22
+    flagNames = new QStringList;
23
+    varNames = new QStringList;
21
     map_cache = new QMap<QString, Map*>;
24
     map_cache = new QMap<QString, Map*>;
22
     mapConstantsToMapNames = new QMap<QString, QString>;
25
     mapConstantsToMapNames = new QMap<QString, QString>;
23
     mapNamesToMapConstants = new QMap<QString, QString>;
26
     mapNamesToMapConstants = new QMap<QString, QString>;
68
         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);
69
         QString text = readTextFile(path);
72
         QString text = readTextFile(path);
70
         if (!text.isNull()) {
73
         if (!text.isNull()) {
71
-            QList<QStringList> *commands = parse(text);
74
+            QList<QStringList> *commands = parseAsm(text);
72
             QStringList *list = getLabelValues(commands, map->connections_label);
75
             QStringList *list = getLabelValues(commands, map->connections_label);
73
 
76
 
74
             //// Avoid using this value. It ought to be generated instead.
77
             //// Avoid using this value. It ought to be generated instead.
147
     }
150
     }
148
 
151
 
149
     QString label = map->name;
152
     QString label = map->name;
150
-    Asm *parser = new Asm;
153
+    ParseUtil *parser = new ParseUtil;
151
 
154
 
152
     QString header_text = readTextFile(root + "/data/maps/" + label + "/header.inc");
155
     QString header_text = readTextFile(root + "/data/maps/" + label + "/header.inc");
153
     if (header_text.isNull()) {
156
     if (header_text.isNull()) {
154
         return;
157
         return;
155
     }
158
     }
156
-    QStringList *header = getLabelValues(parser->parse(header_text), label);
159
+    QStringList *header = getLabelValues(parser->parseAsm(header_text), label);
157
     map->attributes_label = header->value(0);
160
     map->attributes_label = header->value(0);
158
     map->events_label = header->value(1);
161
     map->events_label = header->value(1);
159
     map->scripts_label = header->value(2);
162
     map->scripts_label = header->value(2);
209
 void Project::readMapAttributesTable() {
212
 void Project::readMapAttributesTable() {
210
     int curMapIndex = 1;
213
     int curMapIndex = 1;
211
     QString attributesText = readTextFile(getMapAttributesTableFilepath());
214
     QString attributesText = readTextFile(getMapAttributesTableFilepath());
212
-    QList<QStringList>* values = parse(attributesText);
215
+    QList<QStringList>* values = parseAsm(attributesText);
213
     bool inAttributePointers = false;
216
     bool inAttributePointers = false;
214
     for (int i = 0; i < values->length(); i++) {
217
     for (int i = 0; i < values->length(); i++) {
215
         QStringList params = values->value(i);
218
         QStringList params = values->value(i);
262
         return;
265
         return;
263
     }
266
     }
264
 
267
 
265
-    Asm *parser = new Asm;
268
+    ParseUtil *parser = new ParseUtil;
266
 
269
 
267
     QString assets_text = readTextFile(getMapAssetsFilepath());
270
     QString assets_text = readTextFile(getMapAssetsFilepath());
268
     if (assets_text.isNull()) {
271
     if (assets_text.isNull()) {
269
         return;
272
         return;
270
     }
273
     }
271
-    QStringList *attributes = getLabelValues(parser->parse(assets_text), map->attributes_label);
274
+    QStringList *attributes = getLabelValues(parser->parseAsm(assets_text), map->attributes_label);
272
     map->width = attributes->value(0);
275
     map->width = attributes->value(0);
273
     map->height = attributes->value(1);
276
     map->height = attributes->value(1);
274
     map->border_label = attributes->value(2);
277
     map->border_label = attributes->value(2);
280
 void Project::readAllMapAttributes() {
283
 void Project::readAllMapAttributes() {
281
     mapAttributes.clear();
284
     mapAttributes.clear();
282
 
285
 
283
-    Asm *parser = new Asm;
286
+    ParseUtil *parser = new ParseUtil;
284
     QString assets_text = readTextFile(getMapAssetsFilepath());
287
     QString assets_text = readTextFile(getMapAssetsFilepath());
285
     if (assets_text.isNull()) {
288
     if (assets_text.isNull()) {
286
         return;
289
         return;
287
     }
290
     }
288
 
291
 
289
-    QList<QStringList> *commands = parser->parse(assets_text);
292
+    QList<QStringList> *commands = parser->parseAsm(assets_text);
290
 
293
 
291
     // 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:
292
     // 1. <map_name>_MapBorder
295
     // 1. <map_name>_MapBorder
536
 }
539
 }
537
 
540
 
538
 Tileset* Project::loadTileset(QString label) {
541
 Tileset* Project::loadTileset(QString label) {
539
-    Asm *parser = new Asm;
542
+    ParseUtil *parser = new ParseUtil;
540
 
543
 
541
     QString headers_text = readTextFile(root + "/data/tilesets/headers.inc");
544
     QString headers_text = readTextFile(root + "/data/tilesets/headers.inc");
542
-    QStringList *values = getLabelValues(parser->parse(headers_text), label);
545
+    QStringList *values = getLabelValues(parser->parseAsm(headers_text), label);
543
     Tileset *tileset = new Tileset;
546
     Tileset *tileset = new Tileset;
544
     tileset->name = label;
547
     tileset->name = label;
545
     tileset->is_compressed = values->value(0);
548
     tileset->is_compressed = values->value(0);
559
 
562
 
560
 QString Project::getBlockdataPath(Map* map) {
563
 QString Project::getBlockdataPath(Map* map) {
561
     QString text = readTextFile(getMapAssetsFilepath());
564
     QString text = readTextFile(getMapAssetsFilepath());
562
-    QStringList *values = getLabelValues(parse(text), map->blockdata_label);
565
+    QStringList *values = getLabelValues(parseAsm(text), map->blockdata_label);
563
     QString path;
566
     QString path;
564
     if (!values->isEmpty()) {
567
     if (!values->isEmpty()) {
565
         path = root + "/" + values->value(0).section('"', 1, 1);
568
         path = root + "/" + values->value(0).section('"', 1, 1);
571
 
574
 
572
 QString Project::getMapBorderPath(Map *map) {
575
 QString Project::getMapBorderPath(Map *map) {
573
     QString text = readTextFile(getMapAssetsFilepath());
576
     QString text = readTextFile(getMapAssetsFilepath());
574
-    QStringList *values = getLabelValues(parse(text), map->border_label);
577
+    QStringList *values = getLabelValues(parseAsm(text), map->border_label);
575
     QString path;
578
     QString path;
576
     if (!values->isEmpty()) {
579
     if (!values->isEmpty()) {
577
         path = root + "/" + values->value(0).section('"', 1, 1);
580
         path = root + "/" + values->value(0).section('"', 1, 1);
702
 }
705
 }
703
 
706
 
704
 void Project::loadTilesetAssets(Tileset* tileset) {
707
 void Project::loadTilesetAssets(Tileset* tileset) {
705
-    Asm* parser = new Asm;
708
+    ParseUtil* parser = new ParseUtil;
706
     QString category = (tileset->is_secondary == "TRUE") ? "secondary" : "primary";
709
     QString category = (tileset->is_secondary == "TRUE") ? "secondary" : "primary";
707
     if (tileset->name.isNull()) {
710
     if (tileset->name.isNull()) {
708
         return;
711
         return;
710
     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();
711
 
714
 
712
     QString graphics_text = readTextFile(root + "/data/tilesets/graphics.inc");
715
     QString graphics_text = readTextFile(root + "/data/tilesets/graphics.inc");
713
-    QList<QStringList> *graphics = parser->parse(graphics_text);
716
+    QList<QStringList> *graphics = parser->parseAsm(graphics_text);
714
     QStringList *tiles_values = getLabelValues(graphics, tileset->tiles_label);
717
     QStringList *tiles_values = getLabelValues(graphics, tileset->tiles_label);
715
     QStringList *palettes_values = getLabelValues(graphics, tileset->palettes_label);
718
     QStringList *palettes_values = getLabelValues(graphics, tileset->palettes_label);
716
 
719
 
740
     QString metatiles_path;
743
     QString metatiles_path;
741
     QString metatile_attrs_path;
744
     QString metatile_attrs_path;
742
     QString metatiles_text = readTextFile(root + "/data/tilesets/metatiles.inc");
745
     QString metatiles_text = readTextFile(root + "/data/tilesets/metatiles.inc");
743
-    QList<QStringList> *metatiles_macros = parser->parse(metatiles_text);
746
+    QList<QStringList> *metatiles_macros = parser->parseAsm(metatiles_text);
744
     QStringList *metatiles_values = getLabelValues(metatiles_macros, tileset->metatiles_label);
747
     QStringList *metatiles_values = getLabelValues(metatiles_macros, tileset->metatiles_label);
745
     if (!metatiles_values->isEmpty()) {
748
     if (!metatiles_values->isEmpty()) {
746
         metatiles_path = root + "/" + metatiles_values->value(0).section('"', 1, 1);
749
         metatiles_path = root + "/" + metatiles_values->value(0).section('"', 1, 1);
915
     if (text.isNull()) {
918
     if (text.isNull()) {
916
         return;
919
         return;
917
     }
920
     }
918
-    Asm *parser = new Asm;
919
-    QList<QStringList> *commands = parser->parse(text);
921
+    ParseUtil *parser = new ParseUtil;
922
+    QList<QStringList> *commands = parser->parseAsm(text);
920
 
923
 
921
     bool in_group_pointers = false;
924
     bool in_group_pointers = false;
922
     QStringList *groups = new QStringList;
925
     QStringList *groups = new QStringList;
1012
     return newMapName;
1015
     return newMapName;
1013
 }
1016
 }
1014
 
1017
 
1015
-QList<QStringList>* Project::parse(QString text) {
1016
-    Asm *parser = new Asm;
1017
-    return parser->parse(text);
1018
+QList<QStringList>* Project::parseAsm(QString text) {
1019
+    ParseUtil *parser = new ParseUtil;
1020
+    return parser->parseAsm(text);
1018
 }
1021
 }
1019
 
1022
 
1020
 QStringList Project::getLocations() {
1023
 QStringList Project::getLocations() {
1062
     return names;
1065
     return names;
1063
 }
1066
 }
1064
 
1067
 
1065
-QStringList Project::getSongNames() {
1066
-    QStringList names;
1067
-    QString text = readTextFile(root + "/include/constants/songs.h");
1068
+void Project::readItemNames() {
1069
+    QString filepath = root + "/include/constants/items.h";
1070
+    QStringList prefixes = (QStringList() << "ITEM_");
1071
+    readCDefinesSorted(filepath, prefixes, itemNames);
1072
+}
1073
+
1074
+void Project::readFlagNames() {
1075
+    QString filepath = root + "/include/constants/flags.h";
1076
+    QStringList prefixes = (QStringList() << "FLAG_");
1077
+    readCDefinesSorted(filepath, prefixes, flagNames);
1078
+}
1079
+
1080
+void Project::readVarNames() {
1081
+    QString filepath = root + "/include/constants/vars.h";
1082
+    QStringList prefixes = (QStringList() << "VAR_");
1083
+    readCDefinesSorted(filepath, prefixes, varNames);
1084
+}
1085
+
1086
+void Project::readCDefinesSorted(QString filepath, QStringList prefixes, QStringList* definesToSet) {
1087
+    QString text = readTextFile(filepath);
1068
     if (!text.isNull()) {
1088
     if (!text.isNull()) {
1069
-        QStringList songDefinePrefixes;
1070
-        songDefinePrefixes << "SE_" << "BGM_";
1071
-        QMap<QString, int> songDefines = readCDefines(text, songDefinePrefixes);
1072
-        names = songDefines.keys();
1089
+        QMap<QString, int> defines = readCDefines(text, prefixes);
1090
+
1091
+        // The defines should to be sorted by their underlying value, not alphabetically.
1092
+        // Reverse the map and read out the resulting keys in order.
1093
+        QMultiMap<int, QString> definesInverse;
1094
+        for (QString defineName : defines.keys()) {
1095
+            definesInverse.insert(defines[defineName], defineName);
1096
+        }
1097
+        *definesToSet = definesInverse.values();
1073
     }
1098
     }
1074
-    return names;
1075
 }
1099
 }
1076
 
1100
 
1077
-QString Project::getSongName(int songNumber) {
1101
+QStringList Project::getSongNames() {
1078
     QStringList names;
1102
     QStringList names;
1079
     QString text = readTextFile(root + "/include/constants/songs.h");
1103
     QString text = readTextFile(root + "/include/constants/songs.h");
1080
     if (!text.isNull()) {
1104
     if (!text.isNull()) {
1081
         QStringList songDefinePrefixes;
1105
         QStringList songDefinePrefixes;
1082
         songDefinePrefixes << "SE_" << "BGM_";
1106
         songDefinePrefixes << "SE_" << "BGM_";
1083
         QMap<QString, int> songDefines = readCDefines(text, songDefinePrefixes);
1107
         QMap<QString, int> songDefines = readCDefines(text, songDefinePrefixes);
1084
-
1085
-        // Loop through song defines, and fine the one with the matching song number.
1086
-        QMap<QString, int>::iterator iter = songDefines.begin();
1087
-        while (iter != songDefines.end()) {
1088
-            if (iter.value() == songNumber) {
1089
-                return iter.key();
1090
-            }
1091
-            iter++;
1092
-        }
1108
+        names = songDefines.keys();
1093
     }
1109
     }
1094
-    return "";
1110
+    return names;
1095
 }
1111
 }
1096
 
1112
 
1097
 QMap<QString, int> Project::getMapObjGfxConstants() {
1113
 QMap<QString, int> Project::getMapObjGfxConstants() {
1128
     QString pointers_text = readTextFile(root + "/src/data/field_map_obj/map_object_graphics_info_pointers.h");
1144
     QString pointers_text = readTextFile(root + "/src/data/field_map_obj/map_object_graphics_info_pointers.h");
1129
     QString info_text = readTextFile(root + "/src/data/field_map_obj/map_object_graphics_info.h");
1145
     QString info_text = readTextFile(root + "/src/data/field_map_obj/map_object_graphics_info.h");
1130
     QString pic_text = readTextFile(root + "/src/data/field_map_obj/map_object_pic_tables.h");
1146
     QString pic_text = readTextFile(root + "/src/data/field_map_obj/map_object_pic_tables.h");
1131
-    QString assets_text = readTextFile(root + "/src/field/field_map_obj.c");
1147
+    QString assets_text = readTextFile(root + "/src/field/event_object_movement.c");
1132
 
1148
 
1133
     QStringList pointers = readCArray(pointers_text, "gMapObjectGraphicsInfoPointers");
1149
     QStringList pointers = readCArray(pointers_text, "gMapObjectGraphicsInfoPointers");
1134
 
1150
 
1228
             text += QString(", %1").arg(coords->get("y"));
1244
             text += QString(", %1").arg(coords->get("y"));
1229
             text += QString(", %1").arg(coords->get("elevation"));
1245
             text += QString(", %1").arg(coords->get("elevation"));
1230
             text += QString(", 0");
1246
             text += QString(", 0");
1231
-            text += QString(", %1").arg(coords->get("coord_unknown1"));
1232
-            text += QString(", %1").arg(coords->get("coord_unknown2"));
1247
+            text += QString(", %1").arg(coords->get("script_var"));
1248
+            text += QString(", %1").arg(coords->get("script_var_value"));
1233
             text += QString(", 0");
1249
             text += QString(", 0");
1234
             text += QString(", %1").arg(coords->get("script_label"));
1250
             text += QString(", %1").arg(coords->get("script_label"));
1235
             text += "\n";
1251
             text += "\n";
1298
         return;
1314
         return;
1299
     }
1315
     }
1300
 
1316
 
1301
-    QStringList *labels = getLabelValues(parse(text), map->events_label);
1317
+    QStringList *labels = getLabelValues(parseAsm(text), map->events_label);
1302
     map->object_events_label = labels->value(0);
1318
     map->object_events_label = labels->value(0);
1303
     map->warps_label = labels->value(1);
1319
     map->warps_label = labels->value(1);
1304
     map->coord_events_label = labels->value(2);
1320
     map->coord_events_label = labels->value(2);
1305
     map->bg_events_label = labels->value(3);
1321
     map->bg_events_label = labels->value(3);
1306
 
1322
 
1307
-    QList<QStringList> *object_events = getLabelMacros(parse(text), map->object_events_label);
1323
+    QList<QStringList> *object_events = getLabelMacros(parseAsm(text), map->object_events_label);
1308
     map->events["object"].clear();
1324
     map->events["object"].clear();
1309
     for (QStringList command : *object_events) {
1325
     for (QStringList command : *object_events) {
1310
         if (command.value(0) == "object_event") {
1326
         if (command.value(0) == "object_event") {
1348
         }
1364
         }
1349
     }
1365
     }
1350
 
1366
 
1351
-    QList<QStringList> *warps = getLabelMacros(parse(text), map->warps_label);
1367
+    QList<QStringList> *warps = getLabelMacros(parseAsm(text), map->warps_label);
1352
     map->events["warp"].clear();
1368
     map->events["warp"].clear();
1353
     for (QStringList command : *warps) {
1369
     for (QStringList command : *warps) {
1354
         if (command.value(0) == "warp_def") {
1370
         if (command.value(0) == "warp_def") {
1372
         }
1388
         }
1373
     }
1389
     }
1374
 
1390
 
1375
-    QList<QStringList> *coords = getLabelMacros(parse(text), map->coord_events_label);
1391
+    QList<QStringList> *coords = getLabelMacros(parseAsm(text), map->coord_events_label);
1376
     map->events["trap"].clear();
1392
     map->events["trap"].clear();
1377
     map->events["trap_weather"].clear();
1393
     map->events["trap_weather"].clear();
1378
     for (QStringList command : *coords) {
1394
     for (QStringList command : *coords) {
1389
             coord->put("x", command.value(i++));
1405
             coord->put("x", command.value(i++));
1390
             coord->put("y", command.value(i++));
1406
             coord->put("y", command.value(i++));
1391
             coord->put("elevation", command.value(i++));
1407
             coord->put("elevation", command.value(i++));
1392
-            coord->put("coord_unknown1", command.value(i++));
1393
-            coord->put("coord_unknown2", command.value(i++));
1408
+            coord->put("script_var", command.value(i++));
1409
+            coord->put("script_var_value", command.value(i++));
1394
             coord->put("script_label", command.value(i++));
1410
             coord->put("script_label", command.value(i++));
1395
             //coord_unknown3
1411
             //coord_unknown3
1396
             //coord_unknown4
1412
             //coord_unknown4
1410
         }
1426
         }
1411
     }
1427
     }
1412
 
1428
 
1413
-    QList<QStringList> *bgs = getLabelMacros(parse(text), map->bg_events_label);
1429
+    QList<QStringList> *bgs = getLabelMacros(parseAsm(text), map->bg_events_label);
1414
     map->events["sign"].clear();
1430
     map->events["sign"].clear();
1415
     map->events["event_hidden_item"].clear();
1431
     map->events["event_hidden_item"].clear();
1416
     map->events["event_secret_base"].clear();
1432
     map->events["event_secret_base"].clear();
1515
 }
1531
 }
1516
 
1532
 
1517
 QMap<QString, int> Project::readCDefines(QString text, QStringList prefixes) {
1533
 QMap<QString, int> Project::readCDefines(QString text, QStringList prefixes) {
1518
-    QMap<QString, int> defines;
1519
-
1520
-    QString combinedPrefixes = "[" + prefixes.join('|') + "]";
1521
-    QRegularExpression re(QString("#define\\s+(?<defineName>%1\\w+)\\s(?<defineValue>\\w+)").arg(combinedPrefixes));
1534
+    ParseUtil parser;
1535
+    QMap<QString, int> allDefines;
1536
+    QMap<QString, int> filteredDefines;
1537
+    QRegularExpression re("#define\\s+(?<defineName>\\w+)[^\\S\\n]+(?<defineValue>.+)");
1522
     QRegularExpressionMatchIterator iter = re.globalMatch(text);
1538
     QRegularExpressionMatchIterator iter = re.globalMatch(text);
1523
     while (iter.hasNext()) {
1539
     while (iter.hasNext()) {
1524
         QRegularExpressionMatch match = iter.next();
1540
         QRegularExpressionMatch match = iter.next();
1525
         QString name = match.captured("defineName");
1541
         QString name = match.captured("defineName");
1526
-        QString value = match.captured("defineValue");
1527
-        bool valid;
1528
-        int parsedValue = value.startsWith("0x") ? value.toInt(&valid, 16) : value.toInt(&valid, 10);
1529
-        if (valid) {
1530
-            if (!defines.contains(name)) {
1531
-                defines.insert(name, parsedValue);
1532
-            } else {
1533
-                qDebug() << QString("Define '%1' is defined multiple times'").arg(name);
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);
1534
             }
1549
             }
1535
-        } else {
1536
-            qDebug() << QString("Failed to parse define '%1' value '%2' as base 10 or hexadecimal value").arg(name, value);
1537
         }
1550
         }
1538
     }
1551
     }
1539
-
1540
-    return defines;
1552
+    return filteredDefines;
1541
 }
1553
 }

+ 9
- 3
project.h View File

23
     QMap<int, QString> mapAttributesTableMaster;
23
     QMap<int, QString> mapAttributesTableMaster;
24
     QMap<QString, QMap<QString, QString>> mapAttributes;
24
     QMap<QString, QMap<QString, QString>> mapAttributes;
25
     QMap<QString, QMap<QString, QString>> mapAttributesMaster;
25
     QMap<QString, QMap<QString, QString>> mapAttributesMaster;
26
-
26
+    QStringList *itemNames = NULL;
27
+    QStringList *flagNames = NULL;
28
+    QStringList *varNames = NULL;
27
 
29
 
28
     QMap<QString, Map*> *map_cache;
30
     QMap<QString, Map*> *map_cache;
29
     Map* loadMap(QString);
31
     Map* loadMap(QString);
65
     void saveMapGroupsTable();
67
     void saveMapGroupsTable();
66
     void saveMapConstantsHeader();
68
     void saveMapConstantsHeader();
67
 
69
 
68
-    QList<QStringList>* parse(QString text);
70
+    QList<QStringList>* parseAsm(QString text);
69
     QStringList getSongNames();
71
     QStringList getSongNames();
70
-    QString getSongName(int);
71
     QStringList getLocations();
72
     QStringList getLocations();
72
     QStringList getVisibilities();
73
     QStringList getVisibilities();
73
     QStringList getWeathers();
74
     QStringList getWeathers();
74
     QStringList getMapTypes();
75
     QStringList getMapTypes();
75
     QStringList getBattleScenes();
76
     QStringList getBattleScenes();
77
+    void readItemNames();
78
+    void readFlagNames();
79
+    void readVarNames();
76
 
80
 
77
     void loadObjectPixmaps(QList<Event*> objects);
81
     void loadObjectPixmaps(QList<Event*> objects);
78
     QMap<QString, int> getMapObjGfxConstants();
82
     QMap<QString, int> getMapObjGfxConstants();
95
     void saveMapHeader(Map*);
99
     void saveMapHeader(Map*);
96
     void saveMapAttributesTable();
100
     void saveMapAttributesTable();
97
     void updateMapAttributes(Map* map);
101
     void updateMapAttributes(Map* map);
102
+    void readCDefinesSorted(QString, QStringList, QStringList*);
103
+    void readCDefinesSorted(QString, QStringList, QStringList*, QString, int);
98
 
104
 
99
     void setNewMapHeader(Map* map, int mapIndex);
105
     void setNewMapHeader(Map* map, int mapIndex);
100
     void setNewMapAttributes(Map* map);
106
     void setNewMapAttributes(Map* map);