Allow expressions in directive arguments
MODIFY
src/assembler/assembler.h
src/assembler/assembler.h
@@ -86,6 +86,8 @@ public:
return {};
}
+ virtual ExprEvalRes evalExpr(const QString& expr) const = 0;
+
protected:
void setDirectives(DirectiveVec& directives) {
if (m_directives.size() != 0) {
@@ -601,6 +603,15 @@ protected:
return {program};
}
+ ExprEvalRes evalExpr(const QString& expr) const override {
+ auto symbolValue = m_symbolMap.find(expr);
+ if (symbolValue != m_symbolMap.end()) {
+ return symbolValue->second;
+ } else {
+ return evaluate(expr, &m_symbolMap);
+ }
+ }
+
std::variant<Errors, NoPassResult> pass3(Program& program, const LinkRequests& needsLinkage) const {
Errors errors;
for (const auto& linkRequest : needsLinkage) {
@@ -612,24 +623,14 @@ protected:
const uint32_t linkRequestAddress = linkReqAddress(linkRequest);
m_symbolMap["__address__"] = linkRequestAddress;
- if (m_symbolMap.count(symbol) == 0) {
- if (couldBeExpression(symbol)) {
- // No recorded symbol for the token; our last option is to try and evaluate a possible
- // expression.
- auto evaluate_res = evaluate(symbol, &m_symbolMap);
- if (auto* err = std::get_if<Error>(&evaluate_res)) {
+ // Expression evaluation also performs symbol evaluation
+ auto exprRes = evalExpr(symbol);
+ if (auto* err = std::get_if<Error>(&exprRes)) {
err->first = linkRequest.sourceLine;
errors.push_back(*err);
continue;
- }
- // Expression evaluated successfully
- symbolValue = std::get<long>(evaluate_res);
- } else {
- errors.push_back(Error(linkRequest.sourceLine, "Unknown symbol '" + symbol + "'"));
- continue;
- }
} else {
- symbolValue = m_symbolMap.at(symbol);
+ symbolValue = std::get<long>(exprRes);
}
if (!linkRequest.fieldRequest.relocation.isEmpty()) {

MODIFY
src/assembler/expreval.cpp
src/assembler/expreval.cpp
@@ -262,7 +262,7 @@ long evaluate(const std::shared_ptr<Expr>& expr, const SymbolMap* variables) {
Q_UNREACHABLE();
}
-std::variant<Error, long> evaluate(const QString& s, const SymbolMap* variables) {
+ExprEvalRes evaluate(const QString& s, const SymbolMap* variables) {
QString sNoWhitespace = s;
sNoWhitespace.replace(" ", "");
int pos = 0;

MODIFY
src/assembler/expreval.h
src/assembler/expreval.h
@@ -11,15 +11,16 @@ namespace Assembler {
extern const QRegularExpression s_exprOperatorsRegex;
extern const QString s_exprOperators;
extern const QString s_exprTokens;
+using ExprEvalRes = std::variant<Error, long>;
/**
* @brief evaluate
* Very simple expression parser for evaluating a right-associative binary (2-operand) mathematical expressions.
* For now, no operator precedence is implemented - to ensure precedence, parentheses must be implemented. The
- * functionality is mainly intended to be used by the assembler to expand complex pseudoinstructions and as such not by
- * the user.
+ * 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 SymbolMap* variables = nullptr);
+ExprEvalRes evaluate(const QString&, const SymbolMap* variables = nullptr);
/**
* @brief couldBeExpression

MODIFY
src/assembler/gnudirectives.cpp
src/assembler/gnudirectives.cpp
@@ -29,15 +29,20 @@ DirectiveVec gnuDirectives() {
return directives;
}
-std::optional<Error> assembleData(const TokenizedSrcLine& line, QByteArray& byteArray, size_t size) {
+#define getImmediateErroring(token, res, srcline) \
+ auto exprRes##res = assembler->evalExpr(token); \
+ if (auto* err = std::get_if<Error>(&exprRes##res)) { \
+ err->first = srcline; \
+ return {*err}; \
+ } \
+ res = std::get<long>(exprRes##res);
+
+std::optional<Error> assembleData(const AssemblerBase* assembler, const TokenizedSrcLine& line, QByteArray& byteArray,
+ size_t size) {
Q_ASSERT(size >= 1 && size <= 4);
- bool ok;
for (const auto& token : line.tokens) {
- qlonglong val = getImmediate(token, ok);
- if (!ok) {
- return {Error(line.sourceLine, "Invalid immediate value")};
- }
-
+ long val;
+ getImmediateErroring(token, val, line.sourceLine);
for (size_t i = 0; i < size; i++) {
byteArray.append(val & 0xff);
val >>= 8;
@@ -47,12 +52,12 @@ std::optional<Error> assembleData(const TokenizedSrcLine& line, QByteArray& byte
}
template <size_t width>
-HandleDirectiveRes dataFunctor(const AssemblerBase*, const DirectiveArg& arg) {
+HandleDirectiveRes dataFunctor(const AssemblerBase* assembler, const DirectiveArg& arg) {
if (arg.line.tokens.length() < 1) {
return {Error(arg.line.sourceLine, "Invalid number of arguments (expected >1)")};
}
QByteArray bytes;
- auto err = assembleData(arg.line, bytes, width);
+ auto err = assembleData(assembler, arg.line, bytes, width);
if (err) {
return {err.value()};
} else {
@@ -134,15 +139,12 @@ Directive dataDirective() {
}
Directive zeroDirective() {
- auto zeroFunctor = [](const AssemblerBase*, const DirectiveArg& arg) -> HandleDirectiveRes {
+ auto zeroFunctor = [](const AssemblerBase* assembler, const DirectiveArg& arg) -> HandleDirectiveRes {
if (arg.line.tokens.length() != 1) {
return {Error(arg.line.sourceLine, "Invalid number of arguments (expected 1)")};
}
- bool ok;
- int value = getImmediate(arg.line.tokens.at(0), ok);
- if (!ok) {
- return {Error(arg.line.sourceLine, "Invalid argument")};
- }
+ long value;
+ getImmediateErroring(arg.line.tokens.at(0), value, arg.line.sourceLine);
QByteArray bytes;
for (int i = 0; i < value; i++) {
bytes.append(static_cast<char>(0x0));
@@ -157,11 +159,8 @@ Directive equDirective() {
if (arg.line.tokens.length() != 2) {
return {Error(arg.line.sourceLine, "Invalid number of arguments (expected 2)")};
}
- bool ok;
- int value = getImmediate(arg.line.tokens.at(1), ok);
- if (!ok) {
- return {Error(arg.line.sourceLine, "Invalid argument")};
- }
+ long value;
+ getImmediateErroring(arg.line.tokens.at(1), value, arg.line.sourceLine);
auto err = assembler->addSymbol(arg.line, arg.line.tokens.at(0), value);
if (err) {
@@ -174,28 +173,21 @@ Directive equDirective() {
true /* Constants should be made available during ie. pseudo instruction expansion */);
}
-#define getImmediateErroring(token, res, _ok) \
- res = getImmediate(token, _ok); \
- if (!_ok) { \
- return {Error(arg.line.sourceLine, "Invalid argument '" + token + "'")}; \
- }
-
Directive alignDirective() {
- auto alignFunctor = [](const AssemblerBase*, const DirectiveArg& arg) -> HandleDirectiveRes {
+ auto alignFunctor = [](const AssemblerBase* assembler, const DirectiveArg& arg) -> HandleDirectiveRes {
if (arg.line.tokens.length() == 0 || arg.line.tokens.length() > 3) {
return {Error(arg.line.sourceLine, "Invalid number of arguments (expected at least 1, at most 3)")};
}
- bool ok;
int boundary, fill, max;
fill = 0;
bool hasMax = false;
- getImmediateErroring(arg.line.tokens.at(0), boundary, ok);
+ getImmediateErroring(arg.line.tokens.at(0), boundary, arg.line.sourceLine);
if (arg.line.tokens.size() > 1) {
- getImmediateErroring(arg.line.tokens.at(1), fill, ok);
+ getImmediateErroring(arg.line.tokens.at(1), fill, arg.line.sourceLine);
}
if (arg.line.tokens.size() > 2) {
- getImmediateErroring(arg.line.tokens.at(2), max, ok);
+ getImmediateErroring(arg.line.tokens.at(2), max, arg.line.sourceLine);
hasMax = true;
}

Allow expressions in directive arguments