diff --git a/expression.cpp b/expression.cpp new file mode 100644 index 0000000..abb1c58 --- /dev/null +++ b/expression.cpp @@ -0,0 +1,169 @@ +#include "expression.h" +#include +#include "obj816.h" + +/* a ** b */ +uint32_t power(uint32_t a, uint32_t b) { + + uint32_t rv = 1; + for( ; b; b >>= 1) { + if (b & 0x01) rv *= a; + a = a * a; + } + return rv; +} + +bool unary_op(unsigned op, std::vector &v) { + if (v.size() >=1 ) { + expr &a = v.back(); + if (a.tag == OP_VAL) { + switch(a.tag) { + case OP_NOT: a.value = !a.value; break; + case OP_NEG: a.value = -a.value; break; + case OP_FLP: a.value = ~a.value; break; + } + return true; + } + } + v.emplace_back(op); + return false; +} + + +bool binary_op(unsigned op, std::vector &v) { + if (v.size() >= 2) { + expr &a = v[v.size() - 2]; + expr &b = v[v.size() - 1]; + + if (a.tag == OP_VAL && b.tag == OP_VAL) { + uint32_t value = 0; + switch(op) { + case OP_EXP: value = power(a.value, b.value); break; + case OP_MUL: value = a.value * b.value; break; + case OP_DIV: value = a.value / b.value; break; + case OP_MOD: value = a.value % b.value; break; + case OP_SHR: value = a.value >> b.value; break; + case OP_SHL: value = a.value << b.value; break; + case OP_ADD: value = a.value + b.value; break; + case OP_SUB: value = a.value - b.value; break; + case OP_AND: value = a.value & b.value; break; + case OP_OR: value = a.value | b.value; break; + case OP_XOR: value = a.value ^ b.value; break; + case OP_EQ: value = a.value == b.value; break; + case OP_GT: value = (int32_t)a.value > (int32_t)b.value; break; + case OP_LT: value = (int32_t)a.value < (int32_t)b.value; break; + case OP_UGT: value = a.value > b.value; break; + case OP_ULT: value = a.value < b.value; break; + } + v.pop_back(); + v.back().value = value; + return true; + } + if (a.tag == OP_VAL && b.tag == OP_LOC) { + switch(op) { + case OP_ADD: { + // constant + symbol + expr tmp = b; + tmp.value = a.value + b.value; + v.pop_back(); + v.pop_back(); + v.emplace_back(tmp); + return true; + } + #if 0 + case OP_SUB: { + // constant - symbol .. does this even make sense? + expr tmp = b; + tmp.value = a.value - b.value; + v.pop_back(); + v.pop_back(); + v.emplace_back(tmp); + return true; + } + #endif + } + } + if (a.tag == OP_LOC && b.tag == OP_VAL) { + switch(op) { + case OP_ADD: a.value += b.value; return true; + case OP_SUB: a.value -= b.value; return true; + } + } + + if (a.tag == OP_LOC && b.tag == OP_LOC && a.section == b.section) { + uint32_t value = 0; + bool rv = false; + switch (op) { + case OP_SUB: + // end - start + value = a.value - b.value; + rv = true; break; + case OP_EQ: + value = a.value == b.value; + rv = true; break; + case OP_GT: + case OP_UGT: + value = a.value > b.value; + rv = true; break; + case OP_LT: + case OP_ULT: + value = a.value < b.value; + rv = true; break; + } + if (rv) { + v.pop_back(); + v.pop_back(); + v.emplace_back(OP_VAL, value); + return true; + } + } + + + } + v.emplace_back(op); + return false; +} + + +bool simplify_expression(expression &e) { + std::vector tmp; + bool rv = false; + for (auto &t : e.stack) { + if (t.tag >= OP_BIN) { + rv = binary_op(t.tag, tmp) || rv; + } else if (t.tag >= OP_UNA) { + rv = unary_op(t.tag, tmp) || rv; + } else { + tmp.emplace_back(t); + } + } + if (rv) e.stack = std::move(tmp); + return rv; +} + +/* + * if force is true, treat OP_LOC records as OP_VAL (for omf) + */ + +// should return std::optional... + +uint32_t evaluate_expression(expression &e, bool force) { + std::vector tmp; + for (const auto &t : e.stack) { + if (t.tag == OP_LOC && force) { + tmp.emplace_back(OP_VAL, t.value); + continue; + } + if (t.tag >= OP_BIN) { + binary_op(t.tag, tmp); + } else if (t.tag >= OP_UNA) { + unary_op(t.tag, tmp); + } else { + tmp.emplace_back(t); + } + } + + if (tmp.size() == 1 && tmp.front().tag == OP_VAL) return tmp.front().value; + return 0; +} + diff --git a/expression.h b/expression.h new file mode 100644 index 0000000..db3c56d --- /dev/null +++ b/expression.h @@ -0,0 +1,32 @@ +#ifndef __expression_h__ +#define __expression_h__ + +#include +#include + +struct expr { + expr(int t = 0, uint32_t v = 0, uint32_t s = 0) + : tag(t), value(v), section(s) + {} + int tag = 0; + uint32_t value = 0; + unsigned section = 0; +}; + + +struct expression { + unsigned section = 0; + uint32_t offset = 0; + uint8_t size = 0; + uint8_t relative = false; + bool undefined = false; + + std::vector stack; + +}; + +uint32_t evaluate_expression(expression &e, bool force = false); + +bool simplify_expression(expression &e); + +#endif