123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 |
- #include "parseutil.h"
-
- #include <QDebug>
- #include <QRegularExpression>
- #include <QStack>
-
- ParseUtil::ParseUtil()
- {
- }
-
- void ParseUtil::strip_comment(QString *line) {
- bool in_string = false;
- for (int i = 0; i < line->length(); i++) {
- if (line->at(i) == '"') {
- in_string = !in_string;
- } else if (line->at(i) == '@') {
- if (!in_string) {
- line->truncate(i);
- break;
- }
- }
- }
- }
-
- QList<QStringList>* ParseUtil::parseAsm(QString text) {
- QList<QStringList> *parsed = new QList<QStringList>;
- QStringList lines = text.split('\n');
- for (QString line : lines) {
- QString label;
- //QString macro;
- //QStringList *params;
- strip_comment(&line);
- if (line.trimmed().isEmpty()) {
- } else if (line.contains(':')) {
- label = line.left(line.indexOf(':'));
- QStringList *list = new QStringList;
- list->append(".label"); // This is not a real keyword. It's used only to make the output more regular.
- list->append(label);
- parsed->append(*list);
- // There should not be anything else on the line.
- // gas will raise a syntax error if there is.
- } else {
- line = line.trimmed();
- //parsed->append(line.split(QRegExp("\\s*,\\s*")));
- QString macro;
- QStringList params;
- int index = line.indexOf(QRegExp("\\s+"));
- macro = line.left(index);
- params = line.right(line.length() - index).trimmed().split(QRegExp("\\s*,\\s*"));
- params.prepend(macro);
- parsed->append(params);
- }
- //if (macro != NULL) {
- // if (macros->contains(macro)) {
- // void* function = macros->value(macro);
- // if (function != NULL) {
- // std::function function(params);
- // }
- // }
- //}
- }
- return parsed;
- }
-
- int ParseUtil::evaluateDefine(QString define, QMap<QString, int>* knownDefines) {
- QList<Token> tokens = tokenizeExpression(define, knownDefines);
- QList<Token> postfixExpression = generatePostfix(tokens);
- return evaluatePostfix(postfixExpression);
- }
-
- QList<Token> ParseUtil::tokenizeExpression(QString expression, QMap<QString, int>* knownIdentifiers) {
- QList<Token> tokens;
-
- QStringList tokenTypes = (QStringList() << "hex" << "decimal" << "identifier" << "operator" << "leftparen" << "rightparen");
- QRegularExpression re("^(?<hex>0x[0-9a-fA-F]+)|(?<decimal>[0-9]+)|(?<identifier>[a-zA-Z_0-9]+)|(?<operator>[+\\-*\\/<>|^%]+)|(?<leftparen>\\()|(?<rightparen>\\))");
-
- expression = expression.trimmed();
- while (!expression.isEmpty()) {
- QRegularExpressionMatch match = re.match(expression);
- if (!match.hasMatch()) {
- qDebug() << "Failed to tokenize expression: " << expression;
- break;
- }
- for (QString tokenType : tokenTypes) {
- QString token = match.captured(tokenType);
- if (!token.isEmpty()) {
- if (tokenType == "identifier") {
- if (knownIdentifiers->contains(token)) {
- QString actualToken = QString("%1").arg(knownIdentifiers->value(token));
- expression = expression.replace(0, token.length(), actualToken);
- token = actualToken;
- tokenType = "decimal";
- } else {
- qDebug() << "Unknown identifier found in expression: " << token;
- }
- }
-
- tokens.append(Token(token, tokenType));
- expression = expression.remove(0, token.length()).trimmed();
- break;
- }
- }
- }
- return tokens;
- }
-
- QMap<QString, int> Token::precedenceMap = QMap<QString, int>(
- {
- {"*", 3},
- {"/", 3},
- {"+", 4},
- {"-", 4},
- {"<<", 5},
- {">>", 5},
- {"&", 8},
- {"^", 9},
- {"|", 10}
- });
-
- // Shunting-yard algorithm for generating postfix notation.
- // https://en.wikipedia.org/wiki/Shunting-yard_algorithm
- QList<Token> ParseUtil::generatePostfix(QList<Token> tokens) {
- QList<Token> output;
- QStack<Token> operatorStack;
- for (Token token : tokens) {
- if (token.type == TokenType::Number) {
- output.append(token);
- } else if (token.value == "(") {
- operatorStack.push(token);
- } else if (token.value == ")") {
- while (!operatorStack.empty() && operatorStack.top().value != "(") {
- output.append(operatorStack.pop());
- }
- if (!operatorStack.empty()) {
- // pop the left parenthesis token
- operatorStack.pop();
- } else {
- qDebug() << "Mismatched parentheses detected in expression!";
- }
- } else {
- // token is an operator
- while (!operatorStack.isEmpty()
- && operatorStack.top().operatorPrecedence <= token.operatorPrecedence
- && operatorStack.top().value != "(") {
- output.append(operatorStack.pop());
- }
- operatorStack.push(token);
- }
- }
-
- while (!operatorStack.isEmpty()) {
- if (operatorStack.top().value == "(" || operatorStack.top().value == ")") {
- qDebug() << "Mismatched parentheses detected in expression!";
- } else {
- output.append(operatorStack.pop());
- }
- }
-
- return output;
- }
-
- // Evaluate postfix expression.
- // https://en.wikipedia.org/wiki/Reverse_Polish_notation#Postfix_evaluation_algorithm
- int ParseUtil::evaluatePostfix(QList<Token> postfix) {
- QStack<Token> stack;
- for (Token token : postfix) {
- if (token.type == TokenType::Operator) {
- int op2 = stack.pop().value.toInt(nullptr, 0);
- int op1 = stack.pop().value.toInt(nullptr, 0);
- int result = 0;
- if (token.value == "*") {
- result = op1 * op2;
- } else if (token.value == "/") {
- result = op1 / op2;
- } else if (token.value == "+") {
- result = op1 + op2;
- } else if (token.value == "-") {
- result = op1 - op2;
- } else if (token.value == "<<") {
- result = op1 << op2;
- } else if (token.value == ">>") {
- result = op1 >> op2;
- } else if (token.value == "&") {
- result = op1 & op2;
- } else if (token.value == "^") {
- result = op1 ^ op2;
- } else if (token.value == "|") {
- result = op1 | op2;
- } else {
- qDebug() << "Unsupported postfix operator: " << token.value;
- }
- stack.push(Token(QString("%1").arg(result), "decimal"));
- } else {
- stack.push(token);
- }
- }
-
- return stack.pop().value.toInt(nullptr, 0);
- }
|