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