16#include <unordered_set>
23 auto dot_pos = var.find(
'.');
24 if (dot_pos != std::string::npos) {
25 std::string sym = var;
26 std::replace(sym.begin(), sym.end(),
'.',
'_');
28 if (var ==
"stdout" || var ==
"stdin" || var ==
"stderr") {
56 if (op.
op.find(
'.') == std::string::npos) {
63 if (op.
op ==
"stdout" || op.
op ==
"stderr" || op.
op ==
"stdin") {
73 :
name(std::move(other.name)),
inc(std::move(other.inc)),
vars(std::move(other.vars)),
labels(std::move(other.labels)),
external(std::move(other.external)),
external_functions(std::move(other.external_functions)) {
78 name = std::move(other.name);
79 inc = std::move(other.inc);
80 vars = std::move(other.vars);
81 labels = std::move(other.labels);
82 external = std::move(other.external);
129 std::copy(
argv.begin(),
argv.end(), std::back_inserter(
args));
137 if (
base !=
nullptr) {
138 auto it =
base->object_map.find(
name);
139 if (it ==
base->object_map.end())
145 std::unordered_set<void *> freed_ptrs;
146 for (
auto &i :
vars) {
147 if (i.second.var_value.ptr_value !=
nullptr && i.second.var_value.owns) {
148 if (freed_ptrs.find(i.second.var_value.ptr_value) == freed_ptrs.end()) {
149 freed_ptrs.insert(i.second.var_value.ptr_value);
150 free(i.second.var_value.ptr_value);
152 std::cerr <<
Col(
"MXVM: Warning ",
mx::Color::RED) <<
"Possible Memory Leak, Pointer: " <<
name <<
"." << i.first <<
"\n";
155 i.second.var_value.ptr_value =
nullptr;
156 i.second.var_value.owns =
false;
164 char *errf = dlerror();
165 if (errf !=
nullptr) {
166 std::cerr <<
"Error releaseing module: " << errf <<
"\n";
169 std::cout <<
"Released module: " << h.first <<
"\n";
176 auto dot_pos = label.find(
'.');
177 if (dot_pos != std::string::npos) {
178 std::string obj_name = label.substr(0, dot_pos);
179 std::string func_name = label.substr(dot_pos + 1);
182 if (it !=
object_map.end() && it->second !=
nullptr) {
183 Program *obj_prog = it->second;
184 auto label_it = obj_prog->
labels.find(func_name);
185 return label_it != obj_prog->
labels.end() && label_it->second.second;
190 auto it =
labels.find(label);
191 if (it !=
labels.end() && it->second.second) {
205 handle = dlopen(mod.c_str(), RTLD_LAZY);
211 throw mx::Exception(
"Error could not open module: " + mod +
" try using --path to point to module path");
214 if (
func ==
nullptr) {
215 char *dl_e = dlerror();
216 throw mx::Exception(
"Error could not find symbol: " + name +
" in: " + mod +
" Error: " + ((dl_e !=
nullptr) ? dl_e :
""));
218 char *dl_err = dlerror();
219 if (dl_err !=
nullptr) {
228 using FuncType = void (*)(
Program *program, std::vector<Operand> &);
229 FuncType f =
reinterpret_cast<FuncType
>(
func);
231 f(program, operands);
258 if (
base !=
nullptr) {
259 auto it = std::find(
base->filenames.begin(),
base->filenames.end(), fname);
260 if (it ==
base->filenames.end()) {
261 base->filenames.push_back(fname);
274 if (mod_name.empty() || mod.empty() || func_name.empty() ||
name.empty()) {
275 throw mx::Exception(
"External function missing information.");
278 if (
base !=
nullptr) {
279 if (
base->external_functions.find(
name) ==
base->external_functions.end()) {
281 base->external_functions[
name].mod_name = mod_name;
286 if (this->
name == searchName)
289 Program *found = obj->getObjectByName(searchName);
298 for (
char c : input) {
317 out <<
"Current working directory: ";
319 out << std::filesystem::current_path().string() <<
"\n";
320 }
catch (
const std::exception &e) {
321 out <<
"(unable to retrieve: " << e.what() <<
")\n";
324 std::function<void(
Program *, std::ostream &,
int)> dumpProgram;
325 dumpProgram = [&](
Program *prog, std::ostream &out,
int depth = 0) {
326 std::string indent(depth * 2,
' ');
327 out << indent <<
"=== MEMORY DUMP for " << prog->
name <<
" ===\n";
328 if (!prog->
labels.empty()) {
329 out << indent <<
" Labels:\n";
330 out << indent <<
" " << std::left << std::setw(20) <<
"Name"
331 << std::setw(15) <<
"Address"
332 << std::setw(12) <<
"IsFunc"
334 out << indent <<
" " << std::string(42,
'-') <<
"\n";
335 for (
const auto &label : prog->
labels) {
336 out << indent <<
" " << std::setw(20) << label.first
337 << std::setw(15) << label.second.first
338 << std::setw(10) << (label.second.second ?
"yes" :
"no")
342 if (prog->
vars.empty()) {
343 out << indent <<
" (no variables)\n";
345 out << indent << std::left << std::setw(25) <<
"Name"
346 << std::setw(18) <<
"Type"
347 << std::setw(30) <<
"Value"
348 << std::setw(18) <<
"PtrSize"
349 << std::setw(18) <<
"PtrCount"
350 << std::setw(12) <<
"Owns"
352 out << indent << std::string(121,
'-') <<
"\n";
353 for (
const auto &var : prog->
vars) {
354 out << indent << std::setw(25) << var.first;
356 switch (var.second.type) {
373 typeStr =
"external";
385 out << std::setw(18) << typeStr;
386 switch (var.second.type) {
389 out << std::setw(30) << var.second.var_value.int_value;
392 out << std::setw(30) << std::fixed << std::setprecision(6)
393 << var.second.var_value.float_value;
400 if (var.second.var_value.ptr_value ==
nullptr)
401 out << std::setw(30) <<
"null";
403 std::ostringstream ptr_oss;
404 ptr_oss << var.second.var_value.ptr_value;
405 out << std::setw(30) << ptr_oss.str() << std::dec;
409 out << std::setw(30) << var.second.var_value.label_value;
412 out << std::setw(30) << var.second.var_value.int_value;
416 out << std::setw(18) << var.second.var_value.ptr_size
417 << std::setw(18) << var.second.var_value.ptr_count
418 << std::setw(12) << (var.second.var_value.owns ?
"yes" :
"no");
420 out << std::setw(18) <<
"-"
421 << std::setw(18) <<
"-"
422 << std::setw(12) <<
"-";
428 for (
const auto &obj : prog->
objects) {
430 dumpProgram(obj.get(), out, depth + 1);
433 dumpProgram(
this, out, 0);
437 if (value ==
false) {
General-purpose exception with errno-aware factory method.
Base class for instruction storage, variables, labels, and external function registrations.
static std::unordered_map< std::string, Program * > object_map
object name -> Program mapping
void add_global(const std::string &objname, const std::string &name, const Variable &v)
Declare a global variable scoped to an object.
void add_filename(const std::string &fname)
Record a source filename for debug/error reporting.
std::unordered_map< std::string, std::pair< uint64_t, bool > > labels
label -> (address, is_function)
std::vector< Instruction > inc
instruction stream
void add_runtime_extern(const std::string &mod_name, const std::string &mod, const std::string &func_name, const std::string &name)
Register and resolve a runtime-loaded external function.
void add_variable(const std::string &name, const Variable &v)
Declare a local variable in the symbol table.
void add_allocated(const std::string &name, Variable &v)
Track a heap-allocated variable for cleanup.
void add_extern(const std::string &mod, const std::string &name, bool module)
Register an external function import.
void add_object(const std::string &name, Program *prog)
Register a child object program.
std::unordered_map< std::string, Variable > vars
variable symbol table
Base & operator=(Base &&other) noexcept
Move-assignment operator.
void add_label(const std::string &name, uint64_t address, bool f)
Register a label at the given instruction address.
static Base * base
pointer to the main program base
static std::vector< std::string > filenames
std::unordered_map< std::string, RuntimeFunction > external_functions
resolved runtime function bindings
static std::unordered_map< std::string, Variable > allocated
heap-allocated variables
void add_instruction(const Instruction &i)
Append an instruction to the instruction stream.
static std::string root_name
std::vector< ExternalFunction > external
declared external function imports
Complete MXVM program: instruction interpreter and native x64 code generator.
Variable & getVariable(const std::string &name)
Look up a variable by name, searching local scope then global.
bool isFunctionValid(const std::string &label)
Check whether a label exists and is marked as a function entry.
Program * getObjectByName(const std::string &name)
Look up a child object program by name.
void add_standard()
Register standard library runtime functions.
bool isVariable(const std::string &name)
Check whether a variable exists in local or global scope.
std::vector< std::string > args
~Program()
Destructor — frees any heap-allocated variables.
static std::string escapeNewLines(const std::string &text)
Escape newline characters in a string literal for assembly output.
std::vector< std::unique_ptr< Program > > objects
void setObject(bool obj)
Mark this program as an object (no main entry point).
std::string getMangledName(const std::string &var)
Mangle a variable name with its owning object prefix.
void memoryDump(std::ostream &out)
Dump all variable values to a stream for debugging.
Operand result
return value operand from last invoke
Program()
Default constructor — initializes execution state (pc, flags, etc.).
void setArgs(const std::vector< std::string > &argv)
Set the command-line arguments available to the program.
bool running
interpreter running flag
Wraps a dynamically loaded native function from a shared library module.
RuntimeFunction()
Default constructor — null function pointer and handle.
std::string fname
function symbol name
void * handle
dlopen handle
void call(Program *program, std::vector< Operand > &operands)
Invoke the loaded function.
static std::unordered_map< std::string, void * > handles
cached library handles
void * func
resolved function pointer
std::string mod_name
module name
Exception class, hex formatting utilities, and terminal color definitions.
std::string Col(const std::string &col, std::string color)
Wrap a string with ANSI color codes if terminal supports color.
Intermediate code representation, execution engine, and native x64 code generation (SysV + Win64).
Parser that tokenizes and parses MXVM source into programs, handles modules/objects,...
const char * argv(int idx)
Return the command-line argument at the given index.
bool debug_mode
enable verbose debug output during parsing
void except_assert(std::string reason, bool value)
Assert a condition, throwing an Exception with the given reason on failure.
Describes an external function imported from a module or object.
A complete MXVM instruction with opcode, operands, and optional label.
A single instruction operand (constant value or variable reference).
std::string op
textual operand value
std::string object
owning object name for member access
std::string label
label target for jump/call operands
A named variable with type, value, and optional object association.
void setExtern(std::string name, void *value)
Configure this variable as an external pointer reference.