121 lines
No EOL
4.2 KiB
C++
121 lines
No EOL
4.2 KiB
C++
#include "node.h"
|
|
#include <sstream>
|
|
#include <iomanip>
|
|
#include <algorithm>
|
|
|
|
string Node::toString() const {
|
|
std::ostringstream oss;
|
|
if (!_label.empty()) oss << _label << " ";
|
|
if (_mnemonic) oss << _mnemonic->toString() << " ";
|
|
if (!_comment.empty()) oss << "." << _comment;
|
|
return oss.str();
|
|
}
|
|
|
|
std::string Mnemonic::toString() const {
|
|
std::ostringstream oss;
|
|
oss << "[OP:" << std::hex << (int)_opcode << "]";
|
|
if (_extended) oss << "+";
|
|
// Print operands
|
|
for (size_t i = 0; i < _operands.size(); ++i) {
|
|
if (i > 0) oss << ",";
|
|
std::visit([&](auto&& arg) {
|
|
using T = std::decay_t<decltype(arg)>;
|
|
if constexpr (std::is_same_v<T, Empty>) {
|
|
// nothing
|
|
} else if constexpr (std::is_same_v<T, Register>) {
|
|
oss << "R" << arg.num;
|
|
} else if constexpr (std::is_same_v<T, Immediate>) {
|
|
oss << "#" << arg.value;
|
|
} else if constexpr (std::is_same_v<T, SymbolRef>) {
|
|
oss << arg.name;
|
|
if (arg.indexed) oss << ",X";
|
|
}
|
|
}, _operands[i]);
|
|
}
|
|
return oss.str();
|
|
}
|
|
|
|
string InstructionNode::toString() const {
|
|
std::ostringstream oss;
|
|
if (!_label.empty()) oss << _label << " ";
|
|
if (_mnemonic) oss << _mnemonic->toString();
|
|
if (!_comment.empty()) oss << " ." << _comment;
|
|
return oss.str();
|
|
}
|
|
|
|
string CommentNode::toString() const {
|
|
return "." + _comment;
|
|
}
|
|
|
|
string DirectiveNode::toString() const {
|
|
std::ostringstream oss;
|
|
if (!_label.empty()) oss << _label << " ";
|
|
switch (_kind) {
|
|
case DirectiveKind::START: oss << "START"; break;
|
|
case DirectiveKind::END: oss << "END"; break;
|
|
case DirectiveKind::BASE: oss << "BASE"; break;
|
|
case DirectiveKind::NOBASE: oss << "NOBASE"; break;
|
|
case DirectiveKind::EQU: oss << "EQU"; break;
|
|
case DirectiveKind::ORG: oss << "ORG"; break;
|
|
case DirectiveKind::LTORG: oss << "LTORG"; break;
|
|
case DirectiveKind::EXTDEF: oss << "EXTDEF"; break;
|
|
case DirectiveKind::EXTREF: oss << "EXTREF"; break;
|
|
case DirectiveKind::CSECT: oss << "CSECT"; break;
|
|
}
|
|
std::visit([&](auto&& arg) {
|
|
using T = std::decay_t<decltype(arg)>;
|
|
if constexpr (std::is_same_v<T, std::monostate>) {
|
|
// no arg
|
|
} else if constexpr (std::is_same_v<T, int>) {
|
|
oss << " " << std::hex << arg;
|
|
} else if constexpr (std::is_same_v<T, std::string>) {
|
|
oss << " " << arg;
|
|
} else if constexpr (std::is_same_v<T, std::vector<std::string>>) {
|
|
for (size_t i = 0; i < arg.size(); ++i) {
|
|
if (i > 0) oss << ",";
|
|
oss << arg[i];
|
|
}
|
|
}
|
|
}, _arg);
|
|
if (!_comment.empty()) oss << " ." << _comment;
|
|
return oss.str();
|
|
}
|
|
|
|
string DataNode::toString() const {
|
|
std::ostringstream oss;
|
|
if (!_label.empty()) oss << _label << " ";
|
|
switch (_kind) {
|
|
case DataKind::WORD: oss << "WORD"; break;
|
|
case DataKind::BYTE: oss << "BYTE"; break;
|
|
case DataKind::RESW: oss << "RESW"; break;
|
|
case DataKind::RESB: oss << "RESB"; break;
|
|
}
|
|
std::visit([&](auto&& arg) {
|
|
using T = std::decay_t<decltype(arg)>;
|
|
if constexpr (std::is_same_v<T, std::monostate>) {
|
|
// no value
|
|
} else if constexpr (std::is_same_v<T, int>) {
|
|
oss << " " << arg;
|
|
} else if constexpr (std::is_same_v<T, std::vector<uint8_t>>) {
|
|
// Try to display as string if all printable ASCII
|
|
bool isPrintable = !arg.empty() && std::all_of(arg.begin(), arg.end(),
|
|
[](uint8_t b) { return b >= 32 && b <= 126; });
|
|
|
|
if (isPrintable) {
|
|
oss << " C'";
|
|
for (uint8_t b : arg) oss << static_cast<char>(b);
|
|
oss << "'";
|
|
} else {
|
|
// Display as hex
|
|
oss << " X'";
|
|
for (uint8_t b : arg) {
|
|
oss << std::hex << std::setw(2) << std::setfill('0') << (int)b;
|
|
}
|
|
oss << "'";
|
|
}
|
|
}
|
|
}, _value);
|
|
if (!_comment.empty()) oss << " ." << _comment;
|
|
return oss.str();
|
|
}
|
|
|