mirror of
https://github.com/ksherlock/wdc-utils.git
synced 2024-12-14 01:29:11 +00:00
expr_error - handle precedence when pretty-printing expression.
sanity check the expression can reduce to a single value when parsing.
This commit is contained in:
parent
adafabd419
commit
c08c84c593
241
link.cpp
241
link.cpp
@ -223,7 +223,145 @@ std::vector<symbol> symbols;
|
|||||||
|
|
||||||
std::set<std::string> undefined_symbols;
|
std::set<std::string> undefined_symbols;
|
||||||
|
|
||||||
|
inline std::string parenthesize(const std::string &s) {
|
||||||
|
std::string tmp;
|
||||||
|
tmp.push_back('(');
|
||||||
|
tmp.append(s);
|
||||||
|
tmp.push_back(')');
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void expr_error(bool fatal, const expression &e, const char *msg) {
|
||||||
|
warnx("%s:%04x %s", sections[e.section].name.c_str(), e.offset, msg);
|
||||||
|
|
||||||
|
// pretty-print the expression...
|
||||||
|
bool underflow = false;
|
||||||
|
|
||||||
|
struct pair { std::string name; int precedence = 0; };
|
||||||
|
|
||||||
|
std::vector<pair> stack;
|
||||||
|
|
||||||
|
int p;
|
||||||
|
for (auto &x : e.stack) {
|
||||||
|
auto tag = x.tag;
|
||||||
|
switch(tag) {
|
||||||
|
|
||||||
|
case OP_VAL: {
|
||||||
|
p = 0;
|
||||||
|
char buffer[6];
|
||||||
|
snprintf(buffer, sizeof(buffer), "$%02x", x.value);
|
||||||
|
stack.emplace_back(pair{buffer, p});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OP_SYM: {
|
||||||
|
p = 0;
|
||||||
|
stack.emplace_back(pair{symbols[x.section].name, p});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OP_LOC: {
|
||||||
|
p = 0;
|
||||||
|
std::string tmp = sections[x.section].name;
|
||||||
|
if (x.value) {
|
||||||
|
char buffer[6];
|
||||||
|
snprintf(buffer, sizeof(buffer), "$%02x", x.value);
|
||||||
|
tmp.push_back('+');
|
||||||
|
tmp.append(buffer);
|
||||||
|
p = 3;
|
||||||
|
}
|
||||||
|
stack.emplace_back(pair{tmp, p});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OP_NOT:
|
||||||
|
case OP_NEG:
|
||||||
|
case OP_FLP: {
|
||||||
|
static const std::string ops[] = {
|
||||||
|
".NOT.", "-", "\\"
|
||||||
|
};
|
||||||
|
p = 0;
|
||||||
|
if (stack.empty()) {
|
||||||
|
underflow = true;
|
||||||
|
} else {
|
||||||
|
auto &back = stack.back();
|
||||||
|
if (p < back.precedence) {
|
||||||
|
back.name = parenthesize(back.name);
|
||||||
|
}
|
||||||
|
back.name = ops[tag - OP_UNA] + back.name;
|
||||||
|
back.precedence = p;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OP_EXP:
|
||||||
|
case OP_MUL:
|
||||||
|
case OP_DIV:
|
||||||
|
case OP_MOD:
|
||||||
|
case OP_SHR:
|
||||||
|
case OP_SHL:
|
||||||
|
case OP_ADD:
|
||||||
|
case OP_SUB:
|
||||||
|
case OP_AND:
|
||||||
|
case OP_OR:
|
||||||
|
case OP_XOR:
|
||||||
|
case OP_EQ:
|
||||||
|
case OP_GT:
|
||||||
|
case OP_LT:
|
||||||
|
case OP_UGT:
|
||||||
|
case OP_ULT: {
|
||||||
|
static const pair ops[] = {
|
||||||
|
{ "**", 1 },
|
||||||
|
{ "*", 2 },
|
||||||
|
{ "/", 2 },
|
||||||
|
{ ".MOD.", 2 },
|
||||||
|
{ ">>", 2 },
|
||||||
|
{ "<<", 2 },
|
||||||
|
{ "+", 3 },
|
||||||
|
{ "-", 3 },
|
||||||
|
{ "&", 4 },
|
||||||
|
{ "|", 5 },
|
||||||
|
{ "^", 5 },
|
||||||
|
{ "=", 6 },
|
||||||
|
{ ">", 6},
|
||||||
|
{ "<", 6},
|
||||||
|
{ ".UGT.", 6},
|
||||||
|
{ ".ULT.", 6 }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
p = ops[tag - OP_BIN].precedence;
|
||||||
|
if (stack.size() < 2) {
|
||||||
|
underflow = true;
|
||||||
|
} else {
|
||||||
|
pair b = std::move(stack.back());
|
||||||
|
stack.pop_back();
|
||||||
|
pair &a = stack.back();
|
||||||
|
|
||||||
|
if (p < b.precedence) b.name = parenthesize(b.name);
|
||||||
|
if (p < a.precedence) a.name = parenthesize(a.name);
|
||||||
|
|
||||||
|
a.name += ops[tag - OP_BIN].name + b.name;
|
||||||
|
a.precedence = p;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Unrecognized expression op %02x\n", tag);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (stack.size() == 1) {
|
||||||
|
fprintf(stderr, "Expression: %s\n", stack.front().name.c_str());
|
||||||
|
} else if (stack.empty() || underflow) {
|
||||||
|
fprintf(stderr, "Expression underflow error.\n");
|
||||||
|
fatal = true;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Expression overflow error.\n");
|
||||||
|
fatal = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fatal) flags._errors++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -456,6 +594,7 @@ void one_module(const std::vector<uint8_t> &data,
|
|||||||
|
|
||||||
data_ptr->insert(data_ptr->end(), e.size, 0);
|
data_ptr->insert(data_ptr->end(), e.size, 0);
|
||||||
|
|
||||||
|
int reduced_size = 0;
|
||||||
/**/
|
/**/
|
||||||
for(;;) {
|
for(;;) {
|
||||||
op = read_8(iter);
|
op = read_8(iter);
|
||||||
@ -463,11 +602,13 @@ void one_module(const std::vector<uint8_t> &data,
|
|||||||
|
|
||||||
switch(op) {
|
switch(op) {
|
||||||
case OP_VAL: {
|
case OP_VAL: {
|
||||||
|
reduced_size++;
|
||||||
uint32_t offset = read_32(iter);
|
uint32_t offset = read_32(iter);
|
||||||
e.stack.emplace_back(op, offset);
|
e.stack.emplace_back(op, offset);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OP_SYM: {
|
case OP_SYM: {
|
||||||
|
reduced_size++;
|
||||||
uint16_t symbol = read_16(iter);
|
uint16_t symbol = read_16(iter);
|
||||||
assert(symbol < local_symbols.size());
|
assert(symbol < local_symbols.size());
|
||||||
auto &s = local_symbols[symbol];
|
auto &s = local_symbols[symbol];
|
||||||
@ -492,6 +633,7 @@ void one_module(const std::vector<uint8_t> &data,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OP_LOC: {
|
case OP_LOC: {
|
||||||
|
reduced_size++;
|
||||||
uint8_t section = read_8(iter);
|
uint8_t section = read_8(iter);
|
||||||
uint32_t offset = read_32(iter);
|
uint32_t offset = read_32(iter);
|
||||||
int real_section = remap_section[section];
|
int real_section = remap_section[section];
|
||||||
@ -504,6 +646,8 @@ void one_module(const std::vector<uint8_t> &data,
|
|||||||
case OP_NOT:
|
case OP_NOT:
|
||||||
case OP_NEG:
|
case OP_NEG:
|
||||||
case OP_FLP:
|
case OP_FLP:
|
||||||
|
e.stack.emplace_back(op);
|
||||||
|
break;
|
||||||
// binary
|
// binary
|
||||||
case OP_EXP:
|
case OP_EXP:
|
||||||
case OP_MUL:
|
case OP_MUL:
|
||||||
@ -521,12 +665,17 @@ void one_module(const std::vector<uint8_t> &data,
|
|||||||
case OP_LT:
|
case OP_LT:
|
||||||
case OP_UGT:
|
case OP_UGT:
|
||||||
case OP_ULT:
|
case OP_ULT:
|
||||||
|
reduced_size--;
|
||||||
e.stack.emplace_back(op);
|
e.stack.emplace_back(op);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert(!"unsupported expression opcode.");
|
assert(!"unsupported expression opcode.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (reduced_size != 1) {
|
||||||
|
expr_error(true, e, "Malformed expression");
|
||||||
|
}
|
||||||
sections[current_section].expressions.emplace_back(std::move(e));
|
sections[current_section].expressions.emplace_back(std::move(e));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -677,98 +826,6 @@ inline bool in_range(int value, int low, int high) {
|
|||||||
return value >= low && value <= high;
|
return value >= low && value <= high;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void expr_error(bool fatal, const expression &e, const char *msg) {
|
|
||||||
warnx("%s:%04x %s", sections[e.section].name.c_str(), e.offset, msg);
|
|
||||||
|
|
||||||
// pretty-print the expression...
|
|
||||||
bool underflow = false;
|
|
||||||
std::vector<std::string> stack;
|
|
||||||
for (auto &x : e.stack) {
|
|
||||||
auto tag = x.tag;
|
|
||||||
switch(tag) {
|
|
||||||
|
|
||||||
case OP_VAL: {
|
|
||||||
char buffer[6];
|
|
||||||
snprintf(buffer, sizeof(buffer), "$%02x", x.value);
|
|
||||||
stack.emplace_back(buffer);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case OP_SYM: {
|
|
||||||
stack.emplace_back(symbols[x.section].name);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case OP_LOC: {
|
|
||||||
std::string tmp = sections[x.section].name;
|
|
||||||
if (x.value) {
|
|
||||||
char buffer[6];
|
|
||||||
snprintf(buffer, sizeof(buffer), "$%02x", x.value);
|
|
||||||
tmp.push_back('+');
|
|
||||||
tmp.append(buffer);
|
|
||||||
}
|
|
||||||
stack.emplace_back(std::move(tmp));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case OP_NOT:
|
|
||||||
case OP_NEG:
|
|
||||||
case OP_FLP: {
|
|
||||||
static const std::string ops[] = {
|
|
||||||
".NOT.", "-", "\\"
|
|
||||||
};
|
|
||||||
if (stack.empty()) {
|
|
||||||
underflow = true;
|
|
||||||
} else {
|
|
||||||
stack.back() = ops[tag - OP_UNA] + stack.back();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case OP_EXP:
|
|
||||||
case OP_MUL:
|
|
||||||
case OP_DIV:
|
|
||||||
case OP_MOD:
|
|
||||||
case OP_SHR:
|
|
||||||
case OP_SHL:
|
|
||||||
case OP_ADD:
|
|
||||||
case OP_SUB:
|
|
||||||
case OP_AND:
|
|
||||||
case OP_OR:
|
|
||||||
case OP_XOR:
|
|
||||||
case OP_EQ:
|
|
||||||
case OP_GT:
|
|
||||||
case OP_LT:
|
|
||||||
case OP_UGT:
|
|
||||||
case OP_ULT: {
|
|
||||||
static const std::string ops[] = {
|
|
||||||
"**", "*", "/", ".MOD.", ">>", "<<", "+", "-", "&", "|", "^", "=", ">", "<", ">", "<"
|
|
||||||
};
|
|
||||||
|
|
||||||
if (stack.size() < 2) {
|
|
||||||
underflow = true;
|
|
||||||
} else {
|
|
||||||
std::string tmp = std::move(stack.back());
|
|
||||||
stack.pop_back();
|
|
||||||
stack.back() += ops[tag - OP_BIN] + tmp;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "Unrecognized expression op %02x\n", tag);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (stack.size() == 1) {
|
|
||||||
fprintf(stderr, "Expression: %s\n", stack.front().c_str());
|
|
||||||
} else if (stack.empty() || underflow) {
|
|
||||||
fprintf(stderr, "Expression underflow error.\n");
|
|
||||||
fatal = true;
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Expression overflow error.\n");
|
|
||||||
fatal = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (fatal) flags._errors++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void to_omf(const expression &e, omf::segment &seg) {
|
void to_omf(const expression &e, omf::segment &seg) {
|
||||||
if (e.stack.empty() || e.size == 0) {
|
if (e.stack.empty() || e.size == 0) {
|
||||||
expr_error(false, e, "Expression empty");
|
expr_error(false, e, "Expression empty");
|
||||||
|
Loading…
Reference in New Issue
Block a user