Discern between "address" and "constant" symbols
MODIFY
src/assembler/assembler.h
src/assembler/assembler.h
@@ -79,7 +79,7 @@ public:
std::optional<Error> addSymbol(const unsigned& line, Symbol s, uint32_t v) const {
if (m_symbolMap.count(s)) {
- return {Error(line, "Multiple definitions of symbol '" + s + "'")};
+ return {Error(line, "Multiple definitions of symbol '" + s.v + "'")};
}
m_symbolMap[s] = v;
return {};
@@ -183,12 +183,12 @@ protected:
for (const auto& token : splitTokens) {
if (token.endsWith(':')) {
if (symbolStillAllowed) {
- const QString cleanedSymbol = token.left(token.length() - 1);
- if (symbols.count(cleanedSymbol) != 0) {
- return {Error(sourceLine, "Multiple definitions of symbol '" + cleanedSymbol + "'")};
+ const Symbol cleanedSymbol = Symbol(token.left(token.length() - 1), Symbol::Type::Address);
+ if (symbols.count(cleanedSymbol.v) != 0) {
+ return {Error(sourceLine, "Multiple definitions of symbol '" + cleanedSymbol.v + "'")};
} else {
- if (cleanedSymbol.isEmpty() || cleanedSymbol.contains(s_exprOperatorsRegex)) {
- return {Error(sourceLine, "Invalid symbol '" + cleanedSymbol + "'")};
+ if (cleanedSymbol.v.isEmpty() || cleanedSymbol.v.contains(s_exprOperatorsRegex)) {
+ return {Error(sourceLine, "Invalid symbol '" + cleanedSymbol.v + "'")};
}
symbols.insert(cleanedSymbol);
@@ -448,7 +448,7 @@ protected:
bool uniqueSymbols = true;
for (const auto& s : symbolsAndRest.first) {
if (symbols.count(s) != 0) {
- errors.push_back(Error(i, "Multiple definitions of symbol '" + s + "'"));
+ errors.push_back(Error(i, "Multiple definitions of symbol '" + s.v + "'"));
uniqueSymbols = false;
break;
}
@@ -586,10 +586,12 @@ protected:
return {errors};
}
- // Register symbols in program struct
+ // Register address symbols in program struct
for (const auto& iter : m_symbolMap) {
+ if (iter.first.is(Symbol::Type::Address)) {
program.symbols[iter.second] = iter.first;
}
+ }
return {program};
}

MODIFY
src/assembler/assembler_defines.h
src/assembler/assembler_defines.h
@@ -28,11 +28,9 @@ private:
};
using LineTokens = QList<Token>;
using LineTokensVec = std::vector<LineTokens>;
-using Symbol = QString;
using Symbols = std::set<Symbol>;
using DirectiveLinePair = std::pair<QString, LineTokens>;
using SymbolMap = std::map<Symbol, uint32_t>;
-using ReverseSymbolMap = std::map<uint32_t, Symbol>;
using HandleDirectiveRes = std::variant<Error, std::optional<QByteArray>>;
struct TokenizedSrcLine {
Symbols symbols;

MODIFY
src/assembler/expreval.cpp
src/assembler/expreval.cpp
@@ -235,15 +235,22 @@ long evaluate(const std::shared_ptr<Expr>& expr, const SymbolMap* variables) {
IfExpr(Nothing, v) { return 0; }
FiExpr;
IfExpr(Literal, v) {
- bool canConvert;
- auto value = getImmediate(v->v, canConvert);
- if (!canConvert) {
- if (variables != nullptr && variables->count(v->v) != 0) {
- value = variables->at(v->v);
- } else {
- throw std::runtime_error(QString("Unknown symbol '%1'").arg(v->v).toStdString());
+ bool ok = false;
+ auto value = getImmediate(v->v, ok);
+ if (!ok) {
+ if (variables != nullptr) {
+ auto it = variables->find(v->v);
+ if (it != variables->end()) {
+ value = it->second;
+ ok = true;
}
}
+ }
+
+ if (!ok) {
+ throw std::runtime_error(QString("Unknown symbol '%1'").arg(v->v).toStdString());
+ }
+
return value;
}
FiExpr;

MODIFY
src/assembler/expreval.h
src/assembler/expreval.h
#include <QRegularExpression>
#include <variant>
+#include "assembler_defines.h"
#include "assemblererror.h"
namespace Ripes {
@@ -18,7 +19,7 @@ extern const QString s_exprTokens;
* functionality is mainly intended to be used by the assembler to expand complex pseudoinstructions and as such not by
* the user.
*/
-std::variant<Error, long> evaluate(const QString&, const std::map<QString, uint32_t>* variables = nullptr);
+std::variant<Error, long> evaluate(const QString&, const SymbolMap* variables = nullptr);
/**
* @brief couldBeExpression

MODIFY
src/assembler/instruction.h
src/assembler/instruction.h
@@ -264,7 +264,7 @@ struct Imm : public Field {
const int value = signextend<int32_t>(reconstructed, width);
const uint32_t symbolAddress = value + (symbolType == SymbolType::Absolute ? 0 : address);
if (symbolMap.count(symbolAddress)) {
- line.push_back("<" + symbolMap.at(symbolAddress) + ">");
+ line.push_back("<" + symbolMap.at(symbolAddress).v + ">");
}
}

MODIFY
src/assembler/objdump.cpp
src/assembler/objdump.cpp
@@ -39,8 +39,8 @@ QString stringifyProgram(std::weak_ptr<const Program> program, unsigned stride,
// of invalid lines up to the given point.
incrementAddressOffsetMap(out, addrOffsetMap, infoOffsets);
out += "\n";
- incrementAddressOffsetMap(out, addrOffsetMap, infoOffsets, symbol);
- out += QString::number(addr, 16).rightJustified(8, '0') + " <" + symbol + ">:\n";
+ incrementAddressOffsetMap(out, addrOffsetMap, infoOffsets, symbol.v);
+ out += QString::number(addr, 16).rightJustified(8, '0') + " <" + symbol.v + ">:\n";
}
// Instruction address

MODIFY
src/assembler/program.h
src/assembler/program.h
@@ -22,6 +22,28 @@ enum class SourceType {
#define TEXT_SECTION_NAME ".text"
+struct Symbol {
+public:
+ enum Type { Address = 1 << 0, Constant = 1 << 1 };
+ Symbol(){};
+ Symbol(const char* str) : v(str) {}
+ Symbol(const QString& str) : v(str) {}
+ Symbol(const QString& str, const Type _type) : v(str), type(_type) {}
+
+ bool operator==(const Symbol& rhs) const { return this->v == rhs.v; }
+ bool operator<(const Symbol& rhs) const { return this->v < rhs.v; }
+
+ bool is(const Type t) const { return type & t; }
+ bool is(const unsigned t) const { return type & t; }
+
+ operator const QString&() const { return v; }
+
+ QString v;
+ unsigned type = 0;
+};
+
+using ReverseSymbolMap = std::map<uint32_t, Symbol>;
+
struct LoadFileParams {
QString filepath;
SourceType type;
@@ -43,7 +65,7 @@ struct ProgramSection {
struct Program {
unsigned long entryPoint = 0;
std::map<QString, ProgramSection> sections;
- std::map<uint32_t, QString> symbols;
+ ReverseSymbolMap symbols;
const ProgramSection* getSection(const QString& name) const {
const auto secIter =

MODIFY
src/io/iobase.h
src/io/iobase.h
#include <QWidget>
#include <set>
+#include "../assembler/program.h"
#include "binutils.h"
#include "serializers.h"
@@ -39,7 +40,7 @@ struct IOParam {
};
struct IOSymbol {
- QString name;
+ Symbol name;
uint32_t value;
};

MODIFY
src/io/iomanager.cpp
src/io/iomanager.cpp
@@ -139,11 +139,11 @@ void IOManager::refreshMemoryMap() {
updateSymbols();
}
-std::vector<std::pair<QString, uint32_t>> IOManager::assemblerSymbolsForPeriph(IOBase* peripheral) const {
+std::vector<std::pair<Symbol, uint32_t>> IOManager::assemblerSymbolsForPeriph(IOBase* peripheral) const {
const QString& periphName = cName(peripheral->name());
- std::vector<std::pair<QString, uint32_t>> symbols;
+ std::vector<std::pair<Symbol, uint32_t>> symbols;
const auto& periphInfo = m_periphMMappings.at(peripheral);
- symbols.push_back({periphName + "_BASE", periphInfo.startAddr});
+ symbols.push_back({{periphName + "_BASE", Symbol::Type::Address}, periphInfo.startAddr});
symbols.push_back({periphName + "_SIZE", periphInfo.size});
for (const auto& reg : peripheral->registers()) {
@@ -180,7 +180,7 @@ void IOManager::updateSymbols() {
m_assemblerSymbols.insert(symbols.begin(), symbols.end());
for (const auto& symbol : assemblerSymbolsForPeriph(p.first)) {
- headerfile << "#define " + symbol.first + "\t" + "(0x" + QString::number(symbol.second, 16) + ")";
+ headerfile << "#define " + symbol.first.v + "\t" + "(0x" + QString::number(symbol.second, 16) + ")";
}
headerfile << "\n";

MODIFY
src/io/iomanager.h
src/io/iomanager.h
#pragma once
+#include "assembler/assembler_defines.h"
#include "iobase.h"
#include "ioregistry.h"
@@ -51,8 +52,8 @@ public:
* @brief assemblerSymbols
* @returns as cSymbols, but as a map which can be directly loaded into the assembler.
*/
- const std::map<QString, uint32_t>& assemblerSymbols() const { return m_assemblerSymbols; }
- std::vector<std::pair<QString, uint32_t>> assemblerSymbolsForPeriph(IOBase* peripheral) const;
+ const Assembler::SymbolMap& assemblerSymbols() const { return m_assemblerSymbols; }
+ std::vector<std::pair<Symbol, uint32_t>> assemblerSymbolsForPeriph(IOBase* peripheral) const;
signals:
void memoryMapChanged();
@@ -98,7 +99,7 @@ private:
MemoryMap m_memoryMap;
std::map<IOBase*, MemoryMapEntry> m_periphMMappings;
std::set<IOBase*> m_peripherals;
- std::map<QString, uint32_t> m_assemblerSymbols;
+ Assembler::SymbolMap m_assemblerSymbols;
std::unique_ptr<QFile> m_symbolsHeaderFile;
};

MODIFY
test/tst_expreval.cpp
test/tst_expreval.cpp
@@ -21,7 +21,7 @@ void expect(std::variant<Error, long> res, long expected) {
void tst_ExprEval::tst_binops() {
expect(evaluate("(0x2*(3+4))+4"), 18);
expect(evaluate("2+3*7*5"), 107);
- std::map<QString, uint32_t> symbols;
+ SymbolMap symbols;
symbols["B"] = 2;
expect(evaluate("(B *(3+ 4))+4", &symbols), 18);
}

Discern between "address" and "constant" symbols