summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib94/warrior.cpp159
-rw-r--r--warriors/dwarf.red6
2 files changed, 148 insertions, 17 deletions
diff --git a/lib94/warrior.cpp b/lib94/warrior.cpp
index 274a31f..bb65828 100644
--- a/lib94/warrior.cpp
+++ b/lib94/warrior.cpp
@@ -31,26 +31,27 @@ namespace lib94 {
}
struct number_expr {
- virtual std::optional<number_t> to_number(const std::map<std::string, number_t> &label_offsets, number_t this_offset) = 0;
+ virtual std::optional<number_t> to_number(const std::map<std::string, number_t> &label_offsets, const std::map<std::string, number_t> &macro_values, number_t this_offset) = 0;
};
struct label_number_expr : public number_expr {
std::string label;
- virtual std::optional<number_t> to_number(const std::map<std::string, number_t> &label_offsets, number_t this_offset) {
+ virtual std::optional<number_t> to_number(const std::map<std::string, number_t> &label_offsets, const std::map<std::string, number_t> &macro_values, number_t this_offset) {
auto result = label_offsets.find(label);
- if (result == label_offsets.end())
- return {};
- return real_mod(result->second - this_offset);
+ if (result != label_offsets.end())
+ return real_mod(result->second - this_offset);
+ result = macro_values.find(label);
+ if (result != macro_values.end())
+ return result->second;
+ return {};
}
};
struct number_number_expr : public number_expr {
number_t value;
- virtual std::optional<number_t> to_number(const std::map<std::string, number_t> &label_offsets, number_t this_offset) {
- (void)label_offsets;
- (void)this_offset;
+ virtual std::optional<number_t> to_number(const std::map<std::string, number_t> &, const std::map<std::string, number_t> &, number_t) {
return real_mod(value);
}
};
@@ -60,9 +61,9 @@ namespace lib94 {
std::unique_ptr<number_expr> right;
std::function<std::optional<number_t> (number_t, number_t)> op;
- virtual std::optional<number_t> to_number(const std::map<std::string, number_t> &label_offsets, number_t this_offset) {
- std::optional<number_t> left_result = left->to_number(label_offsets, this_offset);
- std::optional<number_t> right_result = right->to_number(label_offsets, this_offset);
+ virtual std::optional<number_t> to_number(const std::map<std::string, number_t> &label_offsets, const std::map<std::string, number_t> &macro_values, number_t this_offset) {
+ std::optional<number_t> left_result = left->to_number(label_offsets, macro_values, this_offset);
+ std::optional<number_t> right_result = right->to_number(label_offsets, macro_values, this_offset);
if (left_result.has_value() && right_result.has_value()) {
std::optional<number_t> op_result = op(left_result.value(), right_result.value());
if (op_result.has_value())
@@ -176,6 +177,63 @@ namespace lib94 {
return {};
}
+ //using unqiue_ptr to refer to this in case i add more types in the future
+ struct assert_expr {
+ std::unique_ptr<number_expr> left;
+ std::unique_ptr<number_expr> right;
+ std::function<bool (number_t, number_t)> comparison;
+
+ std::optional<bool> is_true(const std::map<std::string, number_t> &label_offsets, const std::map<std::string, number_t> &macro_values, number_t this_offset) {
+ auto left_result = left->to_number(label_offsets, macro_values, this_offset);
+ auto right_result = right->to_number(label_offsets, macro_values, this_offset);
+ if (left_result.has_value() && right_result.has_value())
+ return comparison(left_result.value(), right_result.value());
+ return {};
+ }
+ };
+
+ std::optional<std::unique_ptr<assert_expr>> make_assert_expr(std::string part, std::string sep, std::function<bool (number_t, number_t)> comparison) {
+ size_t pos = part.find(sep);
+ if (pos == std::string::npos)
+ return {};
+
+ auto left = to_number_expr(part.substr(0, pos));
+ auto right = to_number_expr(part.substr(pos + sep.size()));
+
+ if (!left.has_value() || !right.has_value())
+ return {};
+
+ return std::make_unique<assert_expr>((assert_expr){
+ .left = std::move(left.value()), .right = std::move(right.value()), .comparison = comparison
+ });
+ }
+
+ std::optional<std::unique_ptr<assert_expr>> to_assert_expr(std::string part) {
+ std::optional<std::unique_ptr<assert_expr>> result;
+
+ result = make_assert_expr(part, "==", [](number_t a, number_t b) {return a == b;});
+ if (result)
+ return result;
+
+ result = make_assert_expr(part, "<=", [](number_t a, number_t b) {return a <= b;});
+ if (result)
+ return result;
+
+ result = make_assert_expr(part, ">=", [](number_t a, number_t b) {return a >= b;});
+ if (result)
+ return result;
+
+ result = make_assert_expr(part, "!=", [](number_t a, number_t b) {return a != b;});
+ if (result)
+ return result;
+
+ result = make_assert_expr(part, "<", [](number_t a, number_t b) {return a < b;});
+ if (result)
+ return result;
+
+ return make_assert_expr(part, ">", [](number_t a, number_t b) {return a > b;});
+ }
+
static const std::map<char, mode> mode_symbols = {
{'#', IMMEDIATE}, {'$', DIRECT},
{'*', A_INDIRECT}, {'@', B_INDIRECT},
@@ -220,6 +278,18 @@ namespace lib94 {
std::unique_ptr<number_expr> bnumber;
};
+ struct macro_definition {
+ size_t source_line;
+ std::unique_ptr<number_expr> definition;
+ number_t offset;
+ };
+
+ struct assertion {
+ size_t source_line;
+ std::unique_ptr<assert_expr> expr;
+ number_t offset;
+ };
+
std::variant<warrior *, std::string> compile_warrior(std::string source) {
for (char &ch : source)
if (ch == '\t' || ch == '\r')
@@ -229,6 +299,8 @@ namespace lib94 {
std::vector<future_instruction> instructions;
std::map<std::string, number_t> label_offsets;
+ std::map<std::string, macro_definition> macro_definitions;
+ std::vector<assertion> assertions;
std::optional<std::unique_ptr<number_expr>> org = {};
number_t org_offset = -1;
size_t org_source_line = -1;
@@ -258,6 +330,18 @@ namespace lib94 {
w->name = trim_spaces(comment.substr(5));
else if (comment.starts_with("author "))
w->author = trim_spaces(comment.substr(7));
+
+ else if (comment.starts_with("assert ")) {
+ auto expr = to_assert_expr(comment.substr(7));
+ if (expr.has_value())
+ assertions.emplace_back((assertion){
+ .source_line = on_line,
+ .expr = std::move(expr.value()),
+ .offset = (number_t)instructions.size()
+ });
+ else
+ return std::string("bad expression on line ") + std::to_string(on_line);
+ }
}
for (char &ch : line)
@@ -273,7 +357,7 @@ namespace lib94 {
if (!valid_label(label))
return std::string("bad label on line ") + std::to_string(on_line);
- if (label_offsets.contains(label))
+ if (label_offsets.contains(label) || macro_definitions.contains(label))
return std::string("duplicate label on line ") + std::to_string(on_line);
label_offsets[label] = instructions.size();
@@ -283,13 +367,39 @@ namespace lib94 {
if (line == "")
continue;
+ size_t equ = line.find(" equ ");
+ if (equ != std::string::npos) {
+
+ std::string macro_name = trim_spaces(line.substr(0, equ).substr());
+
+ if (!valid_label(macro_name))
+ return std::string("bad label on line ") + std::to_string(on_line);
+ if (macro_definitions.contains(macro_name) || label_offsets.contains(macro_name))
+ return std::string("duplicate label on line ") + std::to_string(on_line);
+
+ auto macro_def = to_number_expr(line.substr(equ + 5));
+ if (!macro_def.has_value())
+ return std::string("bad expression on line ") + std::to_string(on_line);
+
+ macro_definitions.emplace(macro_name,
+ (macro_definition){
+ .source_line = on_line,
+ .definition = std::move(macro_def.value()),
+ .offset = (number_t)instructions.size()
+ }
+ );
+
+ continue;
+
+ }
+
future_instruction instr;
instr.source_line = on_line;
std::string opcode_str = line.substr(0, 3);
line = trim_spaces(line.substr(3));
- if (opcode_str == "org") {
+ if (opcode_str == "org" || opcode_str == "end") {
if (org.has_value())
return std::string("duplicate org on line ") + std::to_string(on_line);
@@ -436,8 +546,25 @@ namespace lib94 {
if (w->author == "")
return "no author";
+ std::map<std::string, number_t> macro_values;
+ for (const auto &macro : macro_definitions) {
+ auto result = macro.second.definition->to_number(label_offsets, macro_values, macro.second.offset);
+ if (result.has_value())
+ macro_values[macro.first] = result.value();
+ else
+ return std::string("bad expression on line ") + std::to_string(macro.second.source_line);
+ }
+
+ for (const auto &a : assertions) {
+ auto result = a.expr->is_true(label_offsets, macro_values, a.offset);
+ if (!result.has_value())
+ return std::string("bad expression on line ") + std::to_string(a.source_line);
+ if (!result.value())
+ return std::string("failed assertion on line ") + std::to_string(a.source_line);
+ }
+
if (org.has_value()) {
- std::optional<number_t> org_number = org.value()->to_number(label_offsets, org_offset);
+ std::optional<number_t> org_number = org.value()->to_number(label_offsets, macro_values, org_offset);
if (org_number.has_value())
w->org = org_number.value() + org_offset;
else
@@ -446,8 +573,8 @@ namespace lib94 {
for (size_t i = 0; i < instructions.size(); ++i) {
const future_instruction &instr = instructions[i];
- std::optional<number_t> anumber = instr.anumber->to_number(label_offsets, i);
- std::optional<number_t> bnumber = instr.bnumber->to_number(label_offsets, i);
+ std::optional<number_t> anumber = instr.anumber->to_number(label_offsets, macro_values, i);
+ std::optional<number_t> bnumber = instr.bnumber->to_number(label_offsets, macro_values, i);
if (!anumber.has_value() || !bnumber.has_value())
return std::string("bad expression on line ") + std::to_string(instr.source_line);
w->instructions.push_back({
diff --git a/warriors/dwarf.red b/warriors/dwarf.red
index cfa3b86..17c075c 100644
--- a/warriors/dwarf.red
+++ b/warriors/dwarf.red
@@ -1,6 +1,10 @@
;author standard
;name dwarf
+;assert (0 - bomb_step) % bomb_step == 0
+
+bomb_step equ 4
+
mov 0-1, 3
-add.ab #4, 0-1
+add.ab #bomb_step, 0-1
jmp 0-2