[Assembler] Let segments be strings, not typed enums
By not constraining segments to be specified as typed enums,
an implementing assembler can add whatever segment name
that it needs (through a string comparison).
MODIFY
src/assembler/assembler.h
src/assembler/assembler.h
@@ -45,7 +45,7 @@ class AssemblerBase {
public:
std::optional<Error> setCurrentSegment(Segment seg) const {
if (m_segmentPointers.count(seg) == 0) {
- return Error(0, "No base address set for segment '" + s_segmentName.at(seg) + +"'");
+ return Error(0, "No base address set for segment '" + seg + +"'");
}
m_currentSegment = seg;
return {};
@@ -53,8 +53,7 @@ public:
void setSegmentBase(Segment seg, uint32_t base) {
if (m_segmentPointers.count(seg) != 0) {
- throw std::runtime_error("Base address already set for segment '" + s_segmentName.at(seg).toStdString() +
- +"'");
+ throw std::runtime_error("Base address already set for segment '" + seg.toStdString() + +"'");
}
m_segmentPointers[seg] = {base, base};
}
@@ -213,7 +212,7 @@ public:
AssembleResult result;
// Per default, emit to .text until otherwise specified
- setCurrentSegment(Segment::text);
+ setCurrentSegment(".text");
// Tokenize each source line and separate symbol from remainder of tokens
runPass(tokenizedLines, SourceProgram, pass0, programLines);

MODIFY
src/assembler/assembler_defines.h
src/assembler/assembler_defines.h
@@ -31,10 +31,7 @@ using SymbolLinePair = std::pair<Symbols, LineTokens>;
using SourceProgram = std::vector<TokenizedSrcLine>;
using NoPassResult = std::monostate;
-enum class Segment { bss, data, text };
-const static std::map<Segment, QString> s_segmentName = {{Segment::bss, ".bss"},
- {Segment::data, ".data"},
- {Segment::text, ".text"}};
+using Segment = QString;
struct Program {
std::map<Segment, QByteArray> segments;
};

MODIFY
src/assembler/gnudirectives.cpp
src/assembler/gnudirectives.cpp
@@ -109,9 +109,9 @@ Directive stringDirective() {
return Directive(".string", &stringFunctor);
}
-template <Segment seg>
+template <char const* str>
HandleDirectiveRes segmentChangeFunctor(const AssemblerBase* assembler, const TokenizedSrcLine& line) {
- auto err = assembler->setCurrentSegment(seg);
+ auto err = assembler->setCurrentSegment(str);
if (err) {
// Embed source line into error message
err.value().first = line.sourceLine;
@@ -120,16 +120,19 @@ HandleDirectiveRes segmentChangeFunctor(const AssemblerBase* assembler, const To
return std::nullopt;
};
+constexpr char s_text[] = ".text";
Directive textDirective() {
- return Directive(".text", &segmentChangeFunctor<Segment::text>);
+ return Directive(".text", &segmentChangeFunctor<s_text>);
}
+constexpr char s_bss[] = ".bss";
Directive bssDirective() {
- return Directive(".bss", &segmentChangeFunctor<Segment::bss>);
+ return Directive(".bss", &segmentChangeFunctor<s_bss>);
}
+constexpr char s_data[] = ".data";
Directive dataDirective() {
- return Directive(".data", &segmentChangeFunctor<Segment::data>);
+ return Directive(".data", &segmentChangeFunctor<s_data>);
}
Directive zeroDirective() {

MODIFY
src/assembler/rv32i_assembler.cpp
src/assembler/rv32i_assembler.cpp
@@ -12,9 +12,9 @@ RV32I_Assembler::RV32I_Assembler(const std::set<Extensions>& extensions) : Assem
initialize(instrs, pseudos, directives);
// Initialize segment pointers
- setSegmentBase(Segment::text, 0x0);
- setSegmentBase(Segment::data, 0x10000000);
- setSegmentBase(Segment::bss, 0x11000000);
+ setSegmentBase(".text", 0x0);
+ setSegmentBase(".data", 0x10000000);
+ setSegmentBase(".bss", 0x11000000);
}
std::tuple<RV32I_Assembler::RVInstrVec, RV32I_Assembler::RVPseudoInstrVec, DirectiveVec>

MODIFY
test/tst_assembler.cpp
test/tst_assembler.cpp
@@ -97,7 +97,7 @@ void tst_Assembler::tst_simpleprogram() {
res.errors.print();
QFAIL("Errors during assembly");
}
- auto disres = assembler.disassemble(res.program.segments[Segment::text]);
+ auto disres = assembler.disassemble(res.program.segments[".text"]);
return;
}
@@ -113,7 +113,7 @@ void tst_Assembler::tst_simpleWithBranch() {
if (res.errors.size() != 0) {
res.errors.print();
}
- auto disres = assembler.disassemble(res.program.segments[Segment::text]);
+ auto disres = assembler.disassemble(res.program.segments[".text"]);
return;
}

[Assembler] Let segments be strings, not typed enums

By not constraining segments to be specified as typed enums,
an implementing assembler can add whatever segment name
that it needs (through a string comparison).