← index
MXVM/src/icode_exec.cpp
Source: MXVM/src/icode_exec.cpp
#include "mxvm/icode.hpp"
#include <cstring>
#include <iomanip>
#include <iostream>

namespace mxvm {

    static inline void releaseOwnedPointer(Variable &v) {
        if (v.type == VarType::VAR_POINTER && v.var_value.ptr_value && v.var_value.owns) {
            std::free(v.var_value.ptr_value);
            v.var_value.ptr_value = nullptr;
            v.var_value.owns = false;
            v.var_value.ptr_size = 0;
            v.var_value.ptr_count = 0;
        }
    }

    void Program::stop() {
        running = false;
    }

    void Program::flatten_inc(Program *root, Instruction &i) {
        if (root != this) {
            auto qualifyVar = [&](Operand &op) {
                if (op.op.empty())
                    return;
                if (op.type != OperandType::OP_VARIABLE)
                    return;
                if (!op.object.empty())
                    return;
                if (op.op.find('.') != std::string::npos)
                    return;

                std::string qualified = this->name + "." + op.op;
                if (vars.find(qualified) != vars.end()) {
                    op.object = this->name;
                    op.label = op.op;
                    op.op = qualified;
                }
            };
            auto qualifyLabel = [&](Operand &op) {
                if (op.op.empty())
                    return;
                if (op.op.find('.') != std::string::npos)
                    return;
                if (labels.find(op.op) != labels.end()) {
                    op.object = this->name;
                    op.label = op.op;
                    op.op = this->name + "." + op.op;
                }
            };
            Instruction ci = i;
            qualifyVar(ci.op1);
            qualifyVar(ci.op2);
            qualifyVar(ci.op3);
            for (auto &vo : ci.vop)
                qualifyVar(vo);
            switch (ci.instruction) {
            case CALL:
            case JMP:
            case JE:
            case JNE:
            case JL:
            case JLE:
            case JG:
            case JGE:
            case JZ:
            case JNZ:
            case JA:
            case JB:
                qualifyLabel(ci.op1);
                break;
            default:
                break;
            }
            root->add_instruction(ci);
            return;
        }
        root->add_instruction(i);
    }

    void Program::flatten_label(Program *root, int64_t offset, const std::string &label, bool func) {

        if (root != this) {
            root->add_label(this->name + "." + label, offset, func);
            return;
        }
        root->add_label(label, offset, func);
    }

    void Program::flatten_external(Program *root, const std::string &e, RuntimeFunction &r) {
        if (root->external_functions.find(e) == root->external_functions.end()) {
            root->external_functions[e] = r;
        }
    }

    void Program::flatten(Program *program) {
        if (program != this) {
            int64_t size = program->inc.size();
            for (auto &i : inc) {
                flatten_inc(program, i);
            }
            for (auto &lbl : labels) {
                flatten_label(program, lbl.second.first + size, lbl.first, lbl.second.second);
            }
            for (auto &e : external_functions) {
                flatten_external(program, e.first, e.second);
            }
        }

        for (auto &obj : objects) {
            if (obj.get() != program)
                obj->flatten(program);
        }
    }

    int Program::exec() {

        this->add_standard();

        if (inc.empty()) {
            std::cerr << "No instructions to execute\n";
            return EXIT_FAILURE;
        }
        pc = 0;
        running = true;

        while (running && pc < inc.size()) {
            const Instruction &instr = inc.at(pc);
            if (mxvm::instruct_mode)
                std::cout << instr << "\n";

            switch (instr.instruction) {
            case MOV:
                exec_mov(instr);
                break;
            case ADD:
                exec_add(instr);
                break;
            case SUB:
                exec_sub(instr);
                break;
            case MUL:
                exec_mul(instr);
                break;
            case DIV:
                exec_div(instr);
                break;
            case CMP:
                exec_cmp(instr);
                break;
            case FCMP:
                exec_fcmp(instr);
                break;
            case JMP:
                exec_jmp(instr);
                continue;
            case JE:
                exec_je(instr);
                continue;
            case JNE:
                exec_jne(instr);
                continue;
            case JL:
                exec_jl(instr);
                continue;
            case JLE:
                exec_jle(instr);
                continue;
            case JG:
                exec_jg(instr);
                continue;
            case JGE:
                exec_jge(instr);
                continue;
            case JZ:
                exec_jz(instr);
                continue;
            case JNZ:
                exec_jnz(instr);
                continue;
            case JA:
                exec_ja(instr);
                continue;
            case JB:
                exec_jb(instr);
                continue;
            case JAE:
                exec_jae(instr);
                continue;
            case JBE:
                exec_jbe(instr);
                continue;
            case JC:
                exec_jc(instr);
                continue;
            case JNC:
                exec_jnc(instr);
                continue;
            case JP:
                exec_jp(instr);
                continue;
            case JNP:
                exec_jnp(instr);
                continue;
            case JO:
                exec_jo(instr);
                continue;
            case JNO:
                exec_jno(instr);
                continue;
            case JS:
                exec_js(instr);
                continue;
            case JNS:
                exec_jns(instr);
                continue;
            case LOAD:
                exec_load(instr);
                break;
            case STORE:
                exec_store(instr);
                break;
            case OR:
                exec_or(instr);
                break;
            case AND:
                exec_and(instr);
                break;
            case XOR:
                exec_xor(instr);
                break;
            case NOT:
                exec_not(instr);
                break;
            case MOD:
                exec_mod(instr);
                break;
            case PRINT:
                exec_print(instr);
                break;
            case ALLOC:
                exec_alloc(instr);
                break;
            case FREE:
                exec_free(instr);
                break;
            case EXIT:
                exec_exit(instr);
                return getExitCode();
            case GETLINE:
                exec_getline(instr);
                break;
            case PUSH:
                exec_push(instr);
                break;
            case POP:
                exec_pop(instr);
                break;
            case STACK_LOAD:
                exec_stack_load(instr);
                break;
            case STACK_STORE:
                exec_stack_store(instr);
                break;
            case STACK_SUB:
                exec_stack_sub(instr);
                break;
            case CALL:
                exec_call(instr);
                continue;
            case RET:
                exec_ret(instr);
                break;
            case STRING_PRINT:
                exec_string_print(instr);
                break;
            case DONE:
                exec_done(instr);
                return EXIT_SUCCESS;
            case TO_INT:
                exec_to_int(instr);
                break;
            case TO_FLOAT:
                exec_to_float(instr);
                break;
            case INVOKE:
                exec_invoke(instr);
                break;
            case RETURN:
                exec_return(instr);
                break;
            case NEG:
                exec_neg(instr);
                break;
            default:
                throw mx::Exception("Unknown instruction: " + std::to_string(instr.instruction));
                break;
            }
            pc++;
        }
        return getExitCode();
    }

    void Program::exec_mov(const Instruction &instr) {
        if (!isVariable(instr.op1.op)) {
            std::cerr << "Error: MOV destination: " + instr.op1.op + "  must be a variable, not a constant\n";
            return;
        }
        Variable &dest = getVariable(instr.op1.op);

        releaseOwnedPointer(dest);

        if (isVariable(instr.op2.op)) {
            Variable &src = getVariable(instr.op2.op);

            if (dest.type == VarType::VAR_INTEGER && src.type == VarType::VAR_FLOAT) {
                dest.var_value.int_value = static_cast<int64_t>(src.var_value.float_value);
                dest.var_value.type = VarType::VAR_INTEGER;
                return;
            } else if (dest.type == VarType::VAR_FLOAT && src.type == VarType::VAR_INTEGER) {
                dest.var_value.float_value = static_cast<double>(src.var_value.int_value);
                dest.var_value.type = VarType::VAR_FLOAT;
                return;
            }

            dest.var_value = src.var_value;
            dest.type = src.type;
            if (dest.type == VarType::VAR_POINTER || dest.type == VarType::VAR_EXTERN) {
                dest.var_value.owns = false;
            }
        } else {

            if (dest.type == VarType::VAR_POINTER) {
                std::string v = instr.op2.op;
                if (v == "null" || v == "NULL" || v == "0") {
                    dest.var_value.ptr_value = nullptr;
                } else {
                    uintptr_t addr = std::stoull(v, nullptr, 0);
                    dest.var_value.ptr_value = reinterpret_cast<void *>(addr);
                }
                dest.var_value.type = VarType::VAR_POINTER;
                dest.var_value.owns = false;
            } else {
                setVariableFromConstant(dest, instr.op2.op);
            }
        }
    }

    void Program::exec_add(const Instruction &instr) {
        if (!isVariable(instr.op1.op)) {
            std::cerr << "Error: ADD destination: " + instr.op1.op + " must be a variable, not a constant\n";
            return;
        }
        Variable &dest = getVariable(instr.op1.op);
        Variable *src1 = nullptr, *src2 = nullptr;
        Variable temp1, temp2;

        {
            VarType constType = (dest.type == VarType::VAR_POINTER) ? VarType::VAR_INTEGER : dest.type;
            if (instr.op3.op.empty()) {
                src1 = &dest;
                if (isVariable(instr.op2.op)) {
                    src2 = &getVariable(instr.op2.op);
                } else {
                    temp2 = createTempVariable(constType, instr.op2.op);
                    src2 = &temp2;
                }
            } else {
                if (isVariable(instr.op2.op)) {
                    src1 = &getVariable(instr.op2.op);
                } else {
                    temp1 = createTempVariable(constType, instr.op2.op);
                    src1 = &temp1;
                }
                if (isVariable(instr.op3.op)) {
                    src2 = &getVariable(instr.op3.op);
                } else {
                    temp2 = createTempVariable(constType, instr.op3.op);
                    src2 = &temp2;
                }
            }
        }

        addVariables(dest, *src1, *src2);
    }

    void Program::exec_sub(const Instruction &instr) {
        if (!isVariable(instr.op1.op)) {
            std::cerr << "Error: SUB destination must be a variable, not a constant\n";
            return;
        }
        Variable &dest = getVariable(instr.op1.op);

        Variable *src1 = nullptr, *src2 = nullptr;
        Variable temp1, temp2;

        {
            VarType constType = (dest.type == VarType::VAR_POINTER) ? VarType::VAR_INTEGER : dest.type;
            if (instr.op3.op.empty()) {
                src1 = &dest;
                if (isVariable(instr.op2.op)) {
                    src2 = &getVariable(instr.op2.op);
                } else {
                    temp2 = createTempVariable(constType, instr.op2.op);
                    src2 = &temp2;
                }
            } else {
                if (isVariable(instr.op2.op)) {
                    src1 = &getVariable(instr.op2.op);
                } else {
                    temp1 = createTempVariable(constType, instr.op2.op);
                    src1 = &temp1;
                }
                if (isVariable(instr.op3.op)) {
                    src2 = &getVariable(instr.op3.op);
                } else {
                    temp2 = createTempVariable(constType, instr.op3.op);
                    src2 = &temp2;
                }
            }
        }

        subVariables(dest, *src1, *src2);
    }

    void Program::exec_mul(const Instruction &instr) {
        if (!isVariable(instr.op1.op)) {
            std::cerr << "Error: MUL destination must be a variable, not a constant\n";
            return;
        }
        Variable &dest = getVariable(instr.op1.op);

        Variable *src1 = nullptr, *src2 = nullptr;
        Variable temp1, temp2;

        if (instr.op3.op.empty()) {
            src1 = &dest;
            if (isVariable(instr.op2.op)) {
                src2 = &getVariable(instr.op2.op);
            } else {
                temp2 = createTempVariable(dest.type, instr.op2.op);
                src2 = &temp2;
            }
        } else {
            if (isVariable(instr.op2.op)) {
                src1 = &getVariable(instr.op2.op);
            } else {
                temp1 = createTempVariable(dest.type, instr.op2.op);
                src1 = &temp1;
            }
            if (isVariable(instr.op3.op)) {
                src2 = &getVariable(instr.op3.op);
            } else {
                temp2 = createTempVariable(dest.type, instr.op3.op);
                src2 = &temp2;
            }
        }

        mulVariables(dest, *src1, *src2);
    }

    void Program::exec_div(const Instruction &instr) {
        if (!isVariable(instr.op1.op)) {
            std::cerr << "Error: DIV destination must be a variable, not a constant\n";
            return;
        }
        Variable &dest = getVariable(instr.op1.op);

        Variable *src1 = nullptr, *src2 = nullptr;
        Variable temp1, temp2;

        if (instr.op3.op.empty()) {
            src1 = &dest;
            if (isVariable(instr.op2.op)) {
                src2 = &getVariable(instr.op2.op);
            } else {
                temp2 = createTempVariable(dest.type, instr.op2.op);
                src2 = &temp2;
            }
        } else {
            if (isVariable(instr.op2.op)) {
                src1 = &getVariable(instr.op2.op);
            } else {
                temp1 = createTempVariable(dest.type, instr.op2.op);
                src1 = &temp1;
            }
            if (isVariable(instr.op3.op)) {
                src2 = &getVariable(instr.op3.op);
            } else {
                temp2 = createTempVariable(dest.type, instr.op3.op);
                src2 = &temp2;
            }
        }

        divVariables(dest, *src1, *src2);
    }

    void Program::exec_cmp(const Instruction &instr) {
        Variable *var1 = nullptr;
        Variable *var2 = nullptr;
        Variable temp1, temp2;

        if (isVariable(instr.op1.op)) {
            var1 = &getVariable(instr.op1.op);
        } else {
            temp1 = createTempVariable(VarType::VAR_INTEGER, instr.op1.op);
            var1 = &temp1;
        }
        if (isVariable(instr.op2.op)) {
            var2 = &getVariable(instr.op2.op);
        } else {
            temp2 = createTempVariable(VarType::VAR_INTEGER, instr.op2.op);
            var2 = &temp2;
        }
        zero_flag = false;
        less_flag = false;
        greater_flag = false;
        if ((var1->type == VarType::VAR_INTEGER || var1->type == VarType::VAR_BYTE) &&
            (var2->type == VarType::VAR_INTEGER || var2->type == VarType::VAR_BYTE)) {
            int64_t val1 = var1->var_value.int_value;
            int64_t val2 = var2->var_value.int_value;
            if (val1 == val2)
                zero_flag = true;
            else if (val1 < val2)
                less_flag = true;
            else
                greater_flag = true;
        } else if (var1->type == VarType::VAR_FLOAT && var2->type == VarType::VAR_FLOAT) {
            double val1 = var1->var_value.float_value;
            double val2 = var2->var_value.float_value;
            if (val1 == val2)
                zero_flag = true;
            else if (val1 < val2)
                less_flag = true;
            else
                greater_flag = true;
        } else if (var1->type == VarType::VAR_FLOAT && (var2->type == VarType::VAR_INTEGER || var2->type == VarType::VAR_BYTE)) {
            double val1 = var1->var_value.float_value;
            double val2 = static_cast<double>(var2->var_value.int_value);
            if (val1 == val2)
                zero_flag = true;
            else if (val1 < val2)
                less_flag = true;
            else
                greater_flag = true;
        } else if ((var1->type == VarType::VAR_INTEGER || var1->type == VarType::VAR_BYTE) && var2->type == VarType::VAR_FLOAT) {
            double val1 = static_cast<double>(var1->var_value.int_value);
            double val2 = var2->var_value.float_value;
            if (val1 == val2)
                zero_flag = true;
            else if (val1 < val2)
                less_flag = true;
            else
                greater_flag = true;
        } else if (var1->type == VarType::VAR_POINTER && var2->type == VarType::VAR_POINTER) {
            uintptr_t val1 = reinterpret_cast<uintptr_t>(var1->var_value.ptr_value);
            uintptr_t val2 = reinterpret_cast<uintptr_t>(var2->var_value.ptr_value);
            if (val1 == val2)
                zero_flag = true;
            else if (val1 < val2)
                less_flag = true;
            else
                greater_flag = true;
        } else if (var1->type == VarType::VAR_POINTER && (var2->type == VarType::VAR_INTEGER || var2->type == VarType::VAR_BYTE)) {
            uintptr_t val1 = reinterpret_cast<uintptr_t>(var1->var_value.ptr_value);
            uint64_t val2 = var2->var_value.int_value;
            if (val1 == val2)
                zero_flag = true;
            else if (val1 < val2)
                less_flag = true;
            else
                greater_flag = true;
        } else if ((var1->type == VarType::VAR_INTEGER || var1->type == VarType::VAR_BYTE) && var2->type == VarType::VAR_POINTER) {
            uint64_t val1 = var1->var_value.int_value;
            uintptr_t val2 = reinterpret_cast<uintptr_t>(var2->var_value.ptr_value);
            if (val1 == val2)
                zero_flag = true;
            else if (val1 < val2)
                less_flag = true;
            else
                greater_flag = true;
        } else {
            throw mx::Exception("cmp: unsupported type combination: " +
                                var1->toString() + " vs " + var2->toString());
        }
    }

    void Program::exec_jmp(const Instruction &instr) {
        auto it = labels.find(instr.op1.op);
        if (it != labels.end()) {
            pc = it->second.first;
        } else {
            throw mx::Exception("Label not found: " + instr.op1.op);
        }
    }

    void Program::exec_print(const Instruction &instr) {
        std::string format;
        std::vector<Variable> tempArgs;
        std::vector<Variable *> args;
        if (isVariable(instr.op1.op)) {
            Variable &fmt = getVariable(instr.op1.op);
            if (fmt.type != VarType::VAR_STRING)
                throw mx::Exception("PRINT format must be a string variable");
            format = fmt.var_value.str_value;
        } else {
            format = instr.op1.op;
        }
        auto getArgVariable = [&](const Operand &op, VarType type = VarType::VAR_INTEGER) -> Variable * {
            if (isVariable(op.op)) {
                return &getVariable(op.op);
            } else {
                if (op.type == OperandType::OP_VARIABLE) {
                    throw mx::Exception("Instruction variable not defined: " + op.op);
                }
                tempArgs.push_back(createTempVariable(type, op.op));
                return &tempArgs.back();
            }
        };
        if (!instr.op2.op.empty()) {
            args.push_back(getArgVariable(instr.op2));
        }
        if (!instr.op3.op.empty()) {
            args.push_back(getArgVariable(instr.op3));
        }
        for (const auto &vop : instr.vop) {
            if (!vop.op.empty()) {
                args.push_back(getArgVariable(vop));
            }
        }
        printFormatted(format, args);
    }

    void Program::exec_exit(const Instruction &instr) {
        int exit_code = 0;
        if (!instr.op1.op.empty()) {
            if (isVariable(instr.op1.op)) {
                exit_code = getVariable(instr.op1.op).var_value.int_value;
            } else {
                exit_code = std::stoll(instr.op1.op, nullptr, 0);
            }
        }
        exitCode = exit_code;
        stop();
    }

    Variable &Program::getVariable(const std::string &n) {
        auto rax_pos = n.find("%");
        if (rax_pos != std::string::npos) {
            auto dot = n.find(".");
            if (dot != std::string::npos) {
                std::string n_ = n.substr(dot + 1);
                auto e = vars.find(n_);
                if (e != vars.end())
                    return e->second;
            } else {
                auto e = vars.find(n);
                if (e != vars.end())
                    return e->second;
            }
        }
        auto pos = n.find(".");
        if (pos == std::string::npos) {
            auto it = vars.find(name + "." + n);
            if (it != vars.end()) {
                return it->second;
            }
        } else {
            auto it = vars.find(n);
            if (it != vars.end())
                return it->second;
        }

        if (Program::base != nullptr) {
            for (auto &obj : Base::base->object_map) {
                if (pos == std::string::npos) {
                    auto it = obj.second->vars.find(name + "." + n);
                    if (it != obj.second->vars.end())
                        return it->second;
                } else {
                    auto it = obj.second->vars.find(n);
                    if (it != obj.second->vars.end())
                        return it->second;
                }
            }
        }
        throw mx::Exception("Variable not found: " + name + "." + n);
    }

    bool Program::isVariable(const std::string &n) {

        auto rax_pos = n.find("%");

        if (rax_pos != std::string::npos) {
            return true;
        }

        if (Program::base != nullptr) {
            for (auto &obj : Base::base->object_map) {
                auto it = obj.second->vars.find(n);
                if (it != obj.second->vars.end()) {
                    return true;
                }

                it = obj.second->vars.find(name + "." + n);
                if (it != obj.second->vars.end())
                    return true;
            }
        }

        if (vars.find(name + "." + n) != vars.end())
            return true;

        if (vars.find(n) != vars.end())
            return true;

        return false;
    }

    bool Program::validateNames(Validator &v) {
        for (auto &variable : v.var_names) {
            auto it = vars.find(variable.second->getTokenValue());
            if (it == vars.end()) {
                for (auto &o : objects) {
                    if (o->name == variable.first && !o->isVariable(variable.second->getTokenValue())) {
                        throw mx::Exception("Syntax Error: Argument variable not defined: Object: " +
                                            variable.first + " variable: " +
                                            variable.second->getTokenValue() +
                                            " at line " + std::to_string(variable.second->getLine()));
                    }
                }
            }
        }
        return true;
    }

    void Program::setVariableFromString(Variable &var, const std::string &value) {
        if (var.type == VarType::VAR_INTEGER) {
            if (value.starts_with("0x") || value.starts_with("0X")) {
                var.var_value.int_value = std::stoll(value, nullptr, 16);
            } else {
                var.var_value.int_value = std::stoll(value);
            }
            var.var_value.type = VarType::VAR_INTEGER;
        } else if (var.type == VarType::VAR_FLOAT) {
            var.var_value.float_value = std::stod(value);
            var.var_value.type = VarType::VAR_FLOAT;
        } else if (var.type == VarType::VAR_STRING) {
            var.var_value.str_value = value;
            var.var_value.type = VarType::VAR_STRING;
        }
    }
    void Program::addVariables(Variable &dest, Variable &src1, Variable &src2) {
        if (dest.type == VarType::VAR_POINTER) {
            char *base = static_cast<char *>(src1.var_value.ptr_value);
            int64_t offset = (src2.type == VarType::VAR_FLOAT) ? static_cast<int64_t>(src2.var_value.float_value) : src2.var_value.int_value;
            dest.var_value.ptr_value = base + offset;
            dest.var_value.type = VarType::VAR_POINTER;
            dest.var_value.owns = false;
        } else if (dest.type == VarType::VAR_INTEGER) {
            int64_t v1 = (src1.type == VarType::VAR_FLOAT) ? static_cast<int64_t>(src1.var_value.float_value) : src1.var_value.int_value;
            int64_t v2 = (src2.type == VarType::VAR_FLOAT) ? static_cast<int64_t>(src2.var_value.float_value) : src2.var_value.int_value;
            dest.var_value.int_value = v1 + v2;
            dest.var_value.type = VarType::VAR_INTEGER;
        } else if (dest.type == VarType::VAR_FLOAT) {
            double v1 = (src1.type == VarType::VAR_INTEGER) ? static_cast<double>(src1.var_value.int_value) : src1.var_value.float_value;
            double v2 = (src2.type == VarType::VAR_INTEGER) ? static_cast<double>(src2.var_value.int_value) : src2.var_value.float_value;
            dest.var_value.float_value = v1 + v2;
            dest.var_value.type = VarType::VAR_FLOAT;
        }
    }

    void Program::subVariables(Variable &dest, Variable &src1, Variable &src2) {
        if (dest.type == VarType::VAR_POINTER) {
            char *base = static_cast<char *>(src1.var_value.ptr_value);
            int64_t offset = (src2.type == VarType::VAR_FLOAT) ? static_cast<int64_t>(src2.var_value.float_value) : src2.var_value.int_value;
            dest.var_value.ptr_value = base - offset;
            dest.var_value.type = VarType::VAR_POINTER;
            dest.var_value.owns = false;
        } else if (dest.type == VarType::VAR_INTEGER) {
            int64_t v1 = (src1.type == VarType::VAR_FLOAT) ? static_cast<int64_t>(src1.var_value.float_value) : src1.var_value.int_value;
            int64_t v2 = (src2.type == VarType::VAR_FLOAT) ? static_cast<int64_t>(src2.var_value.float_value) : src2.var_value.int_value;
            dest.var_value.int_value = v1 - v2;
            dest.var_value.type = VarType::VAR_INTEGER;
        } else if (dest.type == VarType::VAR_FLOAT) {
            double v1 = (src1.type == VarType::VAR_INTEGER) ? static_cast<double>(src1.var_value.int_value) : src1.var_value.float_value;
            double v2 = (src2.type == VarType::VAR_INTEGER) ? static_cast<double>(src2.var_value.int_value) : src2.var_value.float_value;
            dest.var_value.float_value = v1 - v2;
            dest.var_value.type = VarType::VAR_FLOAT;
        }
    }

    void Program::mulVariables(Variable &dest, Variable &src1, Variable &src2) {
        if (dest.type == VarType::VAR_INTEGER) {
            int64_t v1 = (src1.type == VarType::VAR_FLOAT) ? static_cast<int64_t>(src1.var_value.float_value) : src1.var_value.int_value;
            int64_t v2 = (src2.type == VarType::VAR_FLOAT) ? static_cast<int64_t>(src2.var_value.float_value) : src2.var_value.int_value;
            dest.var_value.int_value = v1 * v2;
            dest.var_value.type = VarType::VAR_INTEGER;
        } else if (dest.type == VarType::VAR_FLOAT) {
            double v1 = (src1.type == VarType::VAR_INTEGER) ? static_cast<double>(src1.var_value.int_value) : src1.var_value.float_value;
            double v2 = (src2.type == VarType::VAR_INTEGER) ? static_cast<double>(src2.var_value.int_value) : src2.var_value.float_value;
            dest.var_value.float_value = v1 * v2;
            dest.var_value.type = VarType::VAR_FLOAT;
        }
    }

    void Program::divVariables(Variable &dest, Variable &src1, Variable &src2) {
        if (dest.type == VarType::VAR_INTEGER) {
            int64_t v1 = (src1.type == VarType::VAR_FLOAT) ? static_cast<int64_t>(src1.var_value.float_value) : src1.var_value.int_value;
            int64_t v2 = (src2.type == VarType::VAR_FLOAT) ? static_cast<int64_t>(src2.var_value.float_value) : src2.var_value.int_value;
            if (v2 != 0) {
                dest.var_value.int_value = v1 / v2;
            } else {

                dest.var_value.int_value = 0;
            }
            dest.var_value.type = VarType::VAR_INTEGER;
        } else if (dest.type == VarType::VAR_FLOAT) {
            double v1 = (src1.type == VarType::VAR_INTEGER) ? static_cast<double>(src1.var_value.int_value) : src1.var_value.float_value;
            double v2 = (src2.type == VarType::VAR_INTEGER) ? static_cast<double>(src2.var_value.int_value) : src2.var_value.float_value;
            if (v2 != 0.0) {
                dest.var_value.float_value = v1 / v2;
            } else {
                dest.var_value.float_value = 0.0;
            }
            dest.var_value.type = VarType::VAR_FLOAT;
        }
    }

    void Program::exec_load(const Instruction &instr) {
        if (!isVariable(instr.op1.op)) {
            throw mx::Exception("LOAD destination must be a variable");
        }
        Variable &dest = getVariable(instr.op1.op);
        void *ptr = nullptr;
        size_t allocated_size = 0;

        bool is_string_source = false;

        if (isVariable(instr.op2.op)) {
            Variable &ptrVar = getVariable(instr.op2.op);
            if (ptrVar.type != VarType::VAR_POINTER && ptrVar.type != VarType::VAR_STRING) {
                throw mx::Exception("LOAD source must be a valid pointer/string buffer");
            }
            if (ptrVar.type == VarType::VAR_POINTER) {
                ptr = ptrVar.var_value.ptr_value;
                allocated_size = ptrVar.var_value.ptr_size * ptrVar.var_value.ptr_count;
            } else {

                ptr = (void *)ptrVar.var_value.str_value.data();
                allocated_size = ptrVar.var_value.str_value.size() + 1;
                is_string_source = true;
            }
        } else {
            throw mx::Exception("LOAD source must be a pointer variable");
        }

        if (ptr == nullptr) {

            switch (dest.type) {
            case VarType::VAR_INTEGER:
            case VarType::VAR_BYTE:
                dest.var_value.int_value = 0;
                break;
            case VarType::VAR_FLOAT:
                dest.var_value.float_value = 0.0;
                break;
            case VarType::VAR_POINTER:
                dest.var_value.ptr_value = nullptr;
                break;
            case VarType::VAR_STRING:
                dest.var_value.str_value = "";
                break;
            default:

                break;
            }
            dest.var_value.type = dest.type;
            return;
        }

        size_t index = 0;
        if (!instr.op3.op.empty()) {
            if (isVariable(instr.op3.op)) {
                index = static_cast<size_t>(getVariable(instr.op3.op).var_value.int_value);
            } else {
                index = static_cast<size_t>(std::stoll(instr.op3.op, nullptr, 0));
            }
        }

        size_t stride = 8;
        if (!instr.vop.empty() && !instr.vop[0].op.empty()) {
            const auto &sizeOp = instr.vop[0];
            if (isVariable(sizeOp.op)) {
                stride = static_cast<size_t>(getVariable(sizeOp.op).var_value.int_value);
            } else {
                stride = static_cast<size_t>(std::stoll(sizeOp.op, nullptr, 0));
            }
        }

        size_t offset = index * stride;
        if (allocated_size > 0 && (stride == 0 || index > (allocated_size - stride) / stride || offset + stride > allocated_size)) {
            throw mx::Exception("LOAD: index out of bounds, offset " + std::to_string(offset) +
                                " + stride " + std::to_string(stride) +
                                " exceeds allocated size " + std::to_string(allocated_size));
        }

        try {
            char *base = static_cast<char *>(ptr) + offset;

            switch (dest.type) {
            case VarType::VAR_INTEGER:
            case VarType::VAR_BYTE:
                std::memcpy(&dest.var_value.int_value, base, sizeof(int64_t));
                dest.var_value.type = dest.type;
                break;
            case VarType::VAR_FLOAT:
                std::memcpy(&dest.var_value.float_value, base, sizeof(double));
                dest.var_value.type = VarType::VAR_FLOAT;
                break;
            case VarType::VAR_POINTER:
                std::memcpy(&dest.var_value.ptr_value, base, sizeof(void *));
                dest.var_value.type = VarType::VAR_POINTER;
                dest.var_value.owns = false;
                break;
            case VarType::VAR_STRING:
                if (is_string_source && index < allocated_size) {

                    dest.var_value.str_value = std::string(1, *(base));
                } else {

                    const char *str_ptr = nullptr;
                    std::memcpy(&str_ptr, base, sizeof(const char *));
                    if (str_ptr != nullptr) {

                        dest.var_value.str_value = str_ptr;
                    } else {
                        dest.var_value.str_value = "";
                    }
                }
                dest.var_value.type = VarType::VAR_STRING;
                break;
            default:
                throw mx::Exception("LOAD: unsupported destination type");
            }
        } catch (const std::exception &e) {
            throw mx::Exception(std::string("LOAD: memory access error: ") + e.what());
        } catch (...) {
            throw mx::Exception("LOAD: unknown memory access error");
        }
    }

    void Program::exec_store(const Instruction &instr) {
        void *ptr = nullptr;
        size_t allocated_size = 0;
        bool is_owned = false;

        if (!isVariable(instr.op2.op)) {
            throw mx::Exception("STORE destination must be a variable or register");
        }

        Variable &ptrVar = getVariable(instr.op2.op);

        if (ptrVar.type == VarType::VAR_POINTER) {
            if (ptrVar.var_value.ptr_value == nullptr) {
                throw mx::Exception("STORE destination pointer is null: " + ptrVar.var_name);
            }
            ptr = ptrVar.var_value.ptr_value;
            allocated_size = ptrVar.var_value.ptr_size * ptrVar.var_value.ptr_count;
            is_owned = ptrVar.var_value.owns;
        } else if (ptrVar.type == VarType::VAR_INTEGER) {
            if (ptrVar.var_value.int_value == 0) {
                throw mx::Exception("STORE destination contains null pointer: " + ptrVar.var_name);
            }
            ptr = reinterpret_cast<void *>(static_cast<uintptr_t>(ptrVar.var_value.int_value));

        } else {
            throw mx::Exception("STORE destination must be a pointer or integer containing a pointer address");
        }

        size_t index = 0;
        if (!instr.op3.op.empty()) {
            if (isVariable(instr.op3.op)) {
                index = static_cast<size_t>(getVariable(instr.op3.op).var_value.int_value);
            } else {
                index = static_cast<size_t>(std::stoll(instr.op3.op, nullptr, 0));
            }
        }

        size_t stride = 8;
        if (!instr.vop.empty() && !instr.vop[0].op.empty()) {
            const auto &sizeOp = instr.vop[0];
            if (isVariable(sizeOp.op)) {
                stride = static_cast<size_t>(getVariable(sizeOp.op).var_value.int_value);
            } else {
                stride = static_cast<size_t>(std::stoll(sizeOp.op, nullptr, 0));
            }
        }

        size_t offset = index * stride;
        if (is_owned && allocated_size > 0 && (stride == 0 || index > (allocated_size - stride) / stride || offset + stride > allocated_size)) {
            throw mx::Exception("STORE: index out of bounds, offset " + std::to_string(offset) +
                                " + stride " + std::to_string(stride) +
                                " exceeds allocated size " + std::to_string(allocated_size));
        }

        char *base = static_cast<char *>(ptr) + offset;

        if (instr.op1.type == OperandType::OP_CONSTANT) {
            int64_t cval = std::stoll(instr.op1.op, nullptr, 0);
            std::memcpy(base, &cval, sizeof(int64_t));
        } else {
            Variable &src = getVariable(instr.op1.op);
            switch (src.type) {
            case VarType::VAR_INTEGER:
            case VarType::VAR_BYTE:
                std::memcpy(base, &src.var_value.int_value, sizeof(int64_t));
                break;
            case VarType::VAR_FLOAT:
                std::memcpy(base, &src.var_value.float_value, sizeof(double));
                break;
            case VarType::VAR_POINTER:
                std::memcpy(base, &src.var_value.ptr_value, sizeof(void *));
                break;
            case VarType::VAR_STRING: {

                if (is_owned && stride >= sizeof(char *)) {
                    char *old_str = nullptr;
                    std::memcpy(&old_str, base, sizeof(char *));
                    size_t str_len = src.var_value.str_value.size() + 1;

                    if (old_str != nullptr) {
                        std::free(old_str);
                    }

                    char *new_str = static_cast<char *>(std::malloc(str_len));
                    if (new_str == nullptr) {
                        throw mx::Exception("STORE: failed to allocate memory for string copy");
                    }
                    std::strncpy(new_str, src.var_value.str_value.c_str(), str_len);
                    new_str[str_len - 1] = '\0';
                    std::memcpy(base, &new_str, sizeof(char *));
                } else {
                    const char *cstr = src.var_value.str_value.c_str();
                    std::memcpy(base, &cstr, sizeof(const char *));
                }
                break;
            }
            default:
                throw mx::Exception("STORE: unsupported source type");
            }
        }
    }
    void Program::exec_and(const Instruction &instr) {
        if (!isVariable(instr.op1.op)) {
            throw mx::Exception("AND destination must be a variable");
            return;
        }
        Variable &dest = getVariable(instr.op1.op);
        int64_t v1, v2;
        if (instr.op3.op.empty()) {
            v1 = dest.var_value.int_value;
            v2 = isVariable(instr.op2.op) ? getVariable(instr.op2.op).var_value.int_value : std::stoll(instr.op2.op, nullptr, 0);
        } else {
            v1 = isVariable(instr.op2.op) ? getVariable(instr.op2.op).var_value.int_value : std::stoll(instr.op2.op, nullptr, 0);
            v2 = isVariable(instr.op3.op) ? getVariable(instr.op3.op).var_value.int_value : std::stoll(instr.op3.op, nullptr, 0);
        }
        dest.var_value.int_value = v1 & v2;
        dest.var_value.type = VarType::VAR_INTEGER;
    }

    void Program::exec_or(const Instruction &instr) {
        if (!isVariable(instr.op1.op)) {
            throw mx::Exception("OR destination must be a variable");
            return;
        }
        Variable &dest = getVariable(instr.op1.op);
        int64_t v1, v2;
        if (instr.op3.op.empty()) {
            v1 = dest.var_value.int_value;
            v2 = isVariable(instr.op2.op) ? getVariable(instr.op2.op).var_value.int_value : std::stoll(instr.op2.op, nullptr, 0);
        } else {
            v1 = isVariable(instr.op2.op) ? getVariable(instr.op2.op).var_value.int_value : std::stoll(instr.op2.op, nullptr, 0);
            v2 = isVariable(instr.op3.op) ? getVariable(instr.op3.op).var_value.int_value : std::stoll(instr.op3.op, nullptr, 0);
        }
        dest.var_value.int_value = v1 | v2;
        dest.var_value.type = VarType::VAR_INTEGER;
    }

    void Program::exec_xor(const Instruction &instr) {
        if (!isVariable(instr.op1.op)) {
            throw mx::Exception("XOR destination must be a variable");
            return;
        }
        Variable &dest = getVariable(instr.op1.op);
        int64_t v1, v2;
        if (instr.op3.op.empty()) {
            v1 = dest.var_value.int_value;
            v2 = isVariable(instr.op2.op) ? getVariable(instr.op2.op).var_value.int_value : std::stoll(instr.op2.op, nullptr, 0);
        } else {
            v1 = isVariable(instr.op2.op) ? getVariable(instr.op2.op).var_value.int_value : std::stoll(instr.op2.op, nullptr, 0);
            v2 = isVariable(instr.op3.op) ? getVariable(instr.op3.op).var_value.int_value : std::stoll(instr.op3.op, nullptr, 0);
        }
        dest.var_value.int_value = v1 ^ v2;
        dest.var_value.type = VarType::VAR_INTEGER;
    }

    void Program::exec_alloc(const Instruction &instr) {
        if (!isVariable(instr.op1.op)) {
            throw mx::Exception("ALLOC destination must be a variable");
            return;
        }
        Variable &dest = getVariable(instr.op1.op);
        int64_t size = 0;
        int64_t count = 1;

        if (!instr.op2.op.empty()) {
            if (isVariable(instr.op2.op)) {
                size = getVariable(instr.op2.op).var_value.int_value;
            } else {
                size = std::stoll(instr.op2.op, nullptr, 0);
            }
        }

        if (!instr.op3.op.empty()) {
            if (isVariable(instr.op3.op)) {
                count = getVariable(instr.op3.op).var_value.int_value;
            } else {
                count = std::stoll(instr.op3.op, nullptr, 0);
            }
        }
        if (size <= 0 || count <= 0) {
            throw mx::Exception("ALLOC: size and count must be positive");
        }
        releaseOwnedPointer(dest);
        dest.type = VarType::VAR_POINTER;
        dest.var_value.type = VarType::VAR_POINTER;
        dest.var_value.ptr_value = calloc(static_cast<size_t>(count), static_cast<size_t>(size));
        if (dest.var_value.ptr_value == nullptr) {
            throw mx::Exception("ALLOC failed: calloc returned nullptr");
        }
        dest.var_value.ptr_size = size;
        dest.var_value.ptr_count = count;
        dest.var_value.owns = true;
    }
    void Program::exec_free(const Instruction &instr) {
        if (!isVariable(instr.op1.op)) {
            throw mx::Exception("FREE argument must be a variable");
            return;
        }
        Variable &var = getVariable(instr.op1.op);
        if (var.type == VarType::VAR_POINTER && var.var_value.owns && var.var_value.ptr_value != nullptr) {
            std::free(var.var_value.ptr_value);
            var.var_value.ptr_value = nullptr;
            var.var_value.owns = false;
            var.var_value.ptr_size = 0;
            var.var_value.ptr_count = 0;
        }
    }

    void Program::exec_not(const Instruction &instr) {
        if (!isVariable(instr.op1.op)) {
            throw mx::Exception("NOT destination must be a variable");
            return;
        }
        Variable &dest = getVariable(instr.op1.op);
        if (dest.var_value.type != VarType::VAR_INTEGER) {
            throw mx::Exception("Error NOT bitwise operation must be on integer value");
        }
        dest.var_value.int_value = (dest.var_value.int_value == 0) ? 1 : 0;
        dest.var_value.type = VarType::VAR_INTEGER;
    }

    void Program::exec_mod(const Instruction &instr) {
        if (!isVariable(instr.op1.op)) {
            std::cerr << "Error: MOD destination must be a variable, not a constant\n";
            return;
        }
        Variable &dest = getVariable(instr.op1.op);

        Variable *src1 = nullptr, *src2 = nullptr;
        Variable temp1, temp2;

        if (instr.op3.op.empty()) {
            src1 = &dest;
            if (isVariable(instr.op2.op)) {
                src2 = &getVariable(instr.op2.op);
            } else {
                temp2 = createTempVariable(dest.type, instr.op2.op);
                src2 = &temp2;
            }
        } else {
            if (isVariable(instr.op2.op)) {
                src1 = &getVariable(instr.op2.op);
            } else {
                temp1 = createTempVariable(dest.type, instr.op2.op);
                src1 = &temp1;
            }
            if (isVariable(instr.op3.op)) {
                src2 = &getVariable(instr.op3.op);
            } else {
                temp2 = createTempVariable(dest.type, instr.op3.op);
                src2 = &temp2;
            }
        }

        if (dest.type == VarType::VAR_INTEGER || dest.type == VarType::VAR_BYTE) {
            int64_t v1 = (src1->type == VarType::VAR_FLOAT) ? static_cast<int64_t>(src1->var_value.float_value) : src1->var_value.int_value;
            int64_t v2 = (src2->type == VarType::VAR_FLOAT) ? static_cast<int64_t>(src2->var_value.float_value) : src2->var_value.int_value;
            if (v2 == 0) {
                dest.var_value.int_value = 0;
            } else {
                dest.var_value.int_value = v1 % v2;
            }
            dest.var_value.type = VarType::VAR_INTEGER;
        } else {
            std::cerr << "MOD only supports integer types\n";
        }
    }

    void Program::exec_je(const Instruction &instr) {
        if (zero_flag)
            exec_jmp(instr);
        else
            pc++;
    }

    void Program::exec_jne(const Instruction &instr) {
        if (!zero_flag)
            exec_jmp(instr);
        else
            pc++;
    }

    void Program::exec_jl(const Instruction &instr) {
        if (less_flag)
            exec_jmp(instr);
        else
            pc++;
    }

    void Program::exec_jle(const Instruction &instr) {
        if (less_flag || zero_flag)
            exec_jmp(instr);
        else
            pc++;
    }

    void Program::exec_jg(const Instruction &instr) {
        if (greater_flag)
            exec_jmp(instr);
        else
            pc++;
    }

    void Program::exec_jge(const Instruction &instr) {
        if (greater_flag || zero_flag)
            exec_jmp(instr);
        else
            pc++;
    }

    void Program::exec_jz(const Instruction &instr) {
        if (zero_flag)
            exec_jmp(instr);
        else
            pc++;
    }

    void Program::exec_jnz(const Instruction &instr) {
        if (!zero_flag)
            exec_jmp(instr);
        else
            pc++;
    }

    void Program::exec_ja(const Instruction &instr) {
        if (greater_flag)
            exec_jmp(instr);
        else
            pc++;
    }

    void Program::exec_jb(const Instruction &instr) {
        if (less_flag)
            exec_jmp(instr);
        else
            pc++;
    }

    void Program::exec_string_print(const Instruction &instr) {
        if (!isVariable(instr.op1.op)) {
            throw mx::Exception("STRING_PRINT destination must be a variable");
            return;
        }
        Variable &dest = getVariable(instr.op1.op);

        if (dest.type != VarType::VAR_STRING) {
            throw mx::Exception("STRING_PRINT destination must be a string variable");
            return;
        }

        std::string format;
        std::vector<Variable> tempArgs;
        std::vector<Variable *> args;
        if (isVariable(instr.op2.op)) {
            Variable &fmtVar = getVariable(instr.op2.op);
            if (fmtVar.type != VarType::VAR_STRING)
                throw mx::Exception("STRING_PRINT format must be a string variable");
            format = fmtVar.var_value.str_value;
        } else {
            format = instr.op2.op;
        }

        auto getArgVariable = [&](const Operand &op, VarType type = VarType::VAR_INTEGER) -> Variable * {
            if (isVariable(op.op)) {
                return &getVariable(op.op);
            } else {
                if (op.type == OperandType::OP_VARIABLE) {
                    throw mx::Exception("string_print instruction variable not defined: " + op.op);
                }
                tempArgs.push_back(createTempVariable(type, op.op));
                return &tempArgs.back();
            }
        };

        if (!instr.op3.op.empty()) {
            args.push_back(getArgVariable(instr.op3));
        }
        for (const auto &vop : instr.vop) {
            if (!vop.op.empty()) {
                args.push_back(getArgVariable(vop));
            }
        }

        std::ostringstream oss;
        size_t argIndex = 0;
        const char *fmt = format.c_str();
        char buffer[4096];

        for (size_t i = 0; i < format.length(); ++i) {
            if (fmt[i] == '%' && i + 1 < format.length()) {
                size_t start = i;
                size_t j = i + 1;
                while (j < format.length() &&
                       (fmt[j] == '-' || fmt[j] == '+' || fmt[j] == ' ' || fmt[j] == '#' || fmt[j] == '0' ||
                        (fmt[j] >= '0' && fmt[j] <= '9') || fmt[j] == '.' ||
                        fmt[j] == 'l' || fmt[j] == 'h' || fmt[j] == 'z' || fmt[j] == 'j' || fmt[j] == 't')) {
                    ++j;
                }
                if (j < format.length() && fmt[j] == '%') {
                    oss << '%';
                    i = j;
                    continue;
                }
                if (j >= format.length())
                    break;
                if (!std::isalpha(fmt[j])) {
                    oss << fmt[i];
                    continue;
                }
                std::string spec(fmt + start, fmt + j + 1);
                if (argIndex < args.size()) {
                    Variable *arg = args[argIndex++];
                    if (arg->type == VarType::VAR_INTEGER) {
                        std::snprintf(buffer, sizeof(buffer), spec.c_str(), arg->var_value.int_value);
                    } else if (arg->type == VarType::VAR_POINTER || arg->var_value.type == VarType::VAR_EXTERN) {
                        if (spec.find("%s") != std::string::npos) {
                            std::snprintf(buffer, sizeof(buffer), spec.c_str(), static_cast<char *>(arg->var_value.ptr_value));
                        } else {
                            std::snprintf(buffer, sizeof(buffer), spec.c_str(), arg->var_value.ptr_value);
                        }
                    } else if (arg->type == VarType::VAR_FLOAT) {
                        std::snprintf(buffer, sizeof(buffer), spec.c_str(), arg->var_value.float_value);
                    } else if (arg->type == VarType::VAR_STRING) {
                        std::snprintf(buffer, sizeof(buffer), spec.c_str(), arg->var_value.str_value.c_str());
                    } else if (arg->type == VarType::VAR_BYTE) {
                        std::snprintf(buffer, sizeof(buffer), spec.c_str(), arg->var_value.int_value);
                    } else {
                        std::snprintf(buffer, sizeof(buffer), "%s", "(unsupported)");
                    }
                    oss << buffer;
                } else {
                    oss << spec;
                }
                i = j;
            } else {
                oss << fmt[i];
            }
        }

        dest.var_value.str_value = oss.str();
        dest.var_value.type = VarType::VAR_STRING;
    }

    std::string Program::printFormatted(const std::string &format, const std::vector<Variable *> &args, bool output) {
        std::ostringstream oss;
        size_t argIndex = 0;
        const char *fmt = format.c_str();
        char buffer[4096];
        for (size_t i = 0; i < format.length(); ++i) {
            if (fmt[i] == '%' && i + 1 < format.length()) {
                size_t start = i;
                size_t j = i + 1;
                while (j < format.length() &&
                       (fmt[j] == '-' || fmt[j] == '+' || fmt[j] == ' ' || fmt[j] == '#' || fmt[j] == '0' ||
                        (fmt[j] >= '0' && fmt[j] <= '9') || fmt[j] == '.' ||
                        fmt[j] == 'l' || fmt[j] == 'h' || fmt[j] == 'z' || fmt[j] == 'j' || fmt[j] == 't')) {
                    ++j;
                }
                if (j < format.length() && fmt[j] == '%') {
                    oss << '%';
                    i = j;
                    continue;
                }
                if (j >= format.length())
                    break;
                if (!std::isalpha(fmt[j])) {
                    oss << fmt[i];
                    continue;
                }
                std::string spec(fmt + start, fmt + j + 1);
                if (argIndex < args.size()) {

                    Variable *arg = args[argIndex++];
                    if (arg->type == VarType::VAR_INTEGER) {
                        std::snprintf(buffer, sizeof(buffer), spec.c_str(), arg->var_value.int_value);
                    } else if (arg->type == VarType::VAR_POINTER || arg->var_value.type == VarType::VAR_EXTERN) {
                        if (spec.find("%s") != std::string::npos) {
                            std::snprintf(buffer, sizeof(buffer), spec.c_str(), static_cast<char *>(arg->var_value.ptr_value));
                        } else {
                            std::snprintf(buffer, sizeof(buffer), spec.c_str(), arg->var_value.ptr_value);
                        }
                    } else if (arg->type == VarType::VAR_FLOAT) {
                        std::snprintf(buffer, sizeof(buffer), spec.c_str(), arg->var_value.float_value);
                    } else if (arg->type == VarType::VAR_STRING) {
                        std::snprintf(buffer, sizeof(buffer), spec.c_str(), arg->var_value.str_value.c_str());
                    } else if (arg->type == VarType::VAR_BYTE) {
                        std::snprintf(buffer, sizeof(buffer), spec.c_str(), arg->var_value.int_value);
                    } else {
                        std::snprintf(buffer, sizeof(buffer), "%s", "(unsupported)");
                    }
                    oss << buffer;
                } else {
                    oss << spec;
                }
                i = j;
            } else {
                oss << fmt[i];
            }
        }
        if (output)
            std::cout << oss.str();
        return oss.str();
    }
    void Program::exec_getline(const Instruction &instr) {
        if (!isVariable(instr.op1.op)) {
            throw mx::Exception("GETLINE destination must be a variable");
            return;
        }
        Variable &dest = getVariable(instr.op1.op);
        std::string input;
        std::getline(std::cin, input);

        switch (dest.type) {
        case VarType::VAR_STRING:
            dest.var_value.str_value = input;
            dest.var_value.type = VarType::VAR_STRING;
            break;
        default:
            throw mx::Exception("GETLINE: unsupported variable type");
        }
    }

    void Program::exec_push(const Instruction &instr) {
        if (!isVariable(instr.op1.op)) {
            try {
                int64_t int_val = std::stoll(instr.op1.op, nullptr, 0);
                stack.push(int_val);
                return;
            } catch (...) {
                throw mx::Exception("PUSH argument must be a variable or integer constant");
                return;
            }
        }
        Variable &var = getVariable(instr.op1.op);
        if (var.var_value.type == VarType::VAR_INTEGER) {
            stack.push(var.var_value.int_value);
        } else if (var.var_value.type == VarType::VAR_POINTER || var.var_value.type == VarType::VAR_EXTERN) {
            stack.push(var.var_value.ptr_value);
        } else {
            throw mx::Exception("PUSH only supports integer or pointer types");
        }
    }

    void Program::exec_pop(const Instruction &instr) {
        if (!isVariable(instr.op1.op)) {
            throw mx::Exception("POP destination must be a variable");
            return;
        }
        Variable &var = getVariable(instr.op1.op);

        if (stack.empty()) {
            throw mx::Exception("POP from empty stack");
            return;
        }

        StackValue value = stack.pop();
        if (var.type == VarType::VAR_INTEGER) {
            if (!std::holds_alternative<int64_t>(value)) {
                throw mx::Exception("POP type mismatch: expected integer, pointer found.");
            }
            var.var_value.int_value = std::get<int64_t>(value);
            var.var_value.type = VarType::VAR_INTEGER;
        } else if (var.type == VarType::VAR_POINTER) {
            if (!std::holds_alternative<void *>(value)) {
                throw mx::Exception("POP type mismatch: expected pointer, integer found.");
            }
            var.var_value.ptr_value = std::get<void *>(value);
            var.var_value.type = VarType::VAR_POINTER;
        } else if (var.type == VarType::VAR_EXTERN) {
            if (!std::holds_alternative<void *>(value)) {
                throw mx::Exception("POP type mismatch: expected pointer, integer found.");
            }
            var.var_value.ptr_value = std::get<void *>(value);
            var.var_value.type = VarType::VAR_EXTERN;
        } else {
            throw mx::Exception("POP only supports integer or pointer variables");
        }
    }

    void Program::exec_stack_load(const Instruction &instr) {
        if (!isVariable(instr.op1.op)) {
            throw mx::Exception("STACK_LOAD destination must be a variable");
            return;
        }
        Variable &dest = getVariable(instr.op1.op);

        size_t index = 0;
        if (!instr.op2.op.empty()) {
            if (isVariable(instr.op2.op)) {
                index = static_cast<size_t>(getVariable(instr.op2.op).var_value.int_value);
            } else {
                index = static_cast<size_t>(std::stoll(instr.op2.op, nullptr, 0));
            }
        }

        if (index >= stack.size()) {
            throw mx::Exception("STACK_LOAD: index out of bounds");
            return;
        }

        StackValue &value = stack[index];
        if (dest.type == VarType::VAR_INTEGER) {
            if (!std::holds_alternative<int64_t>(value)) {
                throw mx::Exception("STACK_LOAD type mismatch: expected integer, found pointer");
            }
            dest.var_value.int_value = std::get<int64_t>(value);
            dest.var_value.type = VarType::VAR_INTEGER;
        } else if (dest.type == VarType::VAR_POINTER) {
            if (!std::holds_alternative<void *>(value)) {
                throw mx::Exception("STACK_LOAD type mismatch: expected pointer, found integer");
            }
            dest.var_value.ptr_value = std::get<void *>(value);
            dest.var_value.type = VarType::VAR_POINTER;
        } else {
            throw mx::Exception("STACK_LOAD only supports integer or pointer variables");
        }
    }

    void Program::exec_stack_store(const Instruction &instr) {
        if (!isVariable(instr.op1.op)) {
            throw mx::Exception("STACK_STORE source must be a variable");
            return;
        }
        Variable &src = getVariable(instr.op1.op);

        size_t index = 0;
        if (!instr.op2.op.empty()) {
            if (isVariable(instr.op2.op)) {
                index = static_cast<size_t>(getVariable(instr.op2.op).var_value.int_value);
            } else {
                index = static_cast<size_t>(std::stoll(instr.op2.op, nullptr, 0));
            }
        }

        if (index >= stack.size()) {
            throw mx::Exception("STACK_STORE: index out of bounds");
            return;
        }
        StackValue &value = stack[index];
        if (src.type == VarType::VAR_INTEGER) {
            if (!std::holds_alternative<int64_t>(value)) {
                throw mx::Exception("STACK_STORE type mismatch: expected integer slot");
            }
            value = src.var_value.int_value;
        } else if (src.type == VarType::VAR_POINTER) {
            if (!std::holds_alternative<void *>(value)) {
                throw mx::Exception("STACK_STORE type mismatch: expected pointer slot");
            }
            value = src.var_value.ptr_value;
        } else {
            throw mx::Exception("STACK_STORE only supports integer or pointer variables");
        }
    }

    void Program::exec_stack_sub(const Instruction &instr) {
        size_t count = 1;
        if (!instr.op1.op.empty()) {
            if (isVariable(instr.op1.op)) {
                count = static_cast<size_t>(getVariable(instr.op1.op).var_value.int_value);
            } else {
                count = static_cast<size_t>(std::stoll(instr.op1.op, nullptr, 0));
            }
        }
        if (count > stack.size()) {
            throw mx::Exception("STACK_SUB: not enough values on stack to pop " + std::to_string(count));
            return;
        }
        for (size_t i = 0; i < count; ++i) {
            stack.pop();
        }
    }

    void Program::exec_call(const Instruction &instr) {
        if (instr.op1.op.empty()) {
            throw mx::Exception("CALL requires a label operand");
            return;
        }
        auto it = labels.find(instr.op1.op);
        if (it != labels.end()) {
            stack.push(static_cast<int64_t>(pc + 1));
            pc = it->second.first;
        } else {
            throw mx::Exception("CALL Label not found: " + instr.op1.op);
        }
    }

    void Program::exec_ret(const Instruction &instr) {
        if (stack.empty()) {
            throw mx::Exception("RET: stack is empty, no return address");
            return;
        }
        StackValue value = stack.pop();
        if (!std::holds_alternative<int64_t>(value)) {
            throw mx::Exception("RET: return address on stack is not an integer");
            return;
        }
        pc = static_cast<size_t>(std::get<int64_t>(value)) - 1;
    }

    void Program::exec_done(const Instruction &i) {
        exitCode = 0;
        stop();
    }

    void Program::exec_to_int(const Instruction &instr) {
        if (!instr.op1.op.empty() && isVariable(instr.op1.op)) {
            Variable &v = getVariable(instr.op1.op);
            if (v.type == VarType::VAR_INTEGER) {
                if (isVariable(instr.op2.op)) {
                    Variable &s = getVariable(instr.op2.op);
                    if (s.type == VarType::VAR_STRING) {
                        try {
                            v.var_value.int_value = std::stoll(s.var_value.str_value, nullptr, 0);
                        } catch (...) {
                            v.var_value.int_value = 0;
                        }
                    } else if (s.type == VarType::VAR_FLOAT) {
                        v.var_value.int_value = static_cast<int64_t>(s.var_value.float_value);
                    }
                } else {
                    throw mx::Exception("to_int second argument must be a variable");
                }
            } else {
                throw mx::Exception("to_int first argument must be an integer variable");
            }
        } else {
            throw mx::Exception("to_int first argument must be a variable");
        }
    }

    void Program::exec_to_float(const Instruction &instr) {
        if (!instr.op1.op.empty() && isVariable(instr.op1.op)) {
            Variable &v = getVariable(instr.op1.op);
            if (v.type == VarType::VAR_FLOAT) {
                if (isVariable(instr.op2.op)) {
                    Variable &s = getVariable(instr.op2.op);
                    if (s.type == VarType::VAR_STRING) {
                        try {
                            v.var_value.float_value = std::stod(s.var_value.str_value);
                            v.var_value.type = VarType::VAR_FLOAT;
                        } catch (...) {
                            v.var_value.float_value = 0.0;
                            v.var_value.type = VarType::VAR_FLOAT;
                        }
                    } else if (s.type == VarType::VAR_INTEGER || s.type == VarType::VAR_BYTE) {
                        v.var_value.float_value = static_cast<double>(s.var_value.int_value);
                        v.var_value.type = VarType::VAR_FLOAT;
                    } else if (s.type == VarType::VAR_FLOAT) {
                        v.var_value.float_value = s.var_value.float_value;
                        v.var_value.type = VarType::VAR_FLOAT;
                    } else if (s.type == VarType::VAR_POINTER || s.type == VarType::VAR_EXTERN) {
                        v.var_value.float_value = static_cast<double>(reinterpret_cast<uintptr_t>(s.var_value.ptr_value));
                        v.var_value.type = VarType::VAR_FLOAT;
                    } else {
                        throw mx::Exception("to_float second argument must be a variable");
                    }
                } else {
                    v.var_value.float_value = static_cast<double>(std::stoll(instr.op2.op, nullptr, 0));
                    v.var_value.type = VarType::VAR_FLOAT;
                }
            } else {
                throw mx::Exception("to_float first argument must be a float variable");
            }
        } else {
            throw mx::Exception("to_float first argument must be a variable");
        }
    }

    std::string toStringFromVarType(const VarType &v) {
        switch (v) {
        case VarType::VAR_BYTE:
            return "Byte";
        case VarType::VAR_INTEGER:
            return "Integer";
        case VarType::VAR_FLOAT:
            return "Float";
        case VarType::VAR_STRING:
            return "String";
        case VarType::VAR_POINTER:
            return "Pointer";
        case VarType::VAR_EXTERN:
            return "Extern";
        default:
            return "Unknown";
        }
        return "Unknown";
    }

    void Program::exec_return(const Instruction &instr) {
        if (!instr.op1.op.empty() && isVariable(instr.op1.op)) {
            Variable &v = getVariable(instr.op1.op);
            std::string name = v.var_name;
            Variable &r = getVariable(result.op);
            std::string v_type_str = toStringFromVarType(v.type);
            std::string r_type_str = toStringFromVarType(r.type);
            if (v.type != r.type) {
                throw mx::Exception("Invalid return type: " + instr.op1.op + ":" + v_type_str + " != " + result.op + ":" + r_type_str + " type mismatch.\n");
            }
            releaseOwnedPointer(v);
            v = r;
            v.var_name = name;
            if (r.type == VarType::VAR_POINTER) {
                r.var_value.owns = false;
            }
        }
    }
    void Program::exec_neg(const Instruction &instr) {
        if (!instr.op1.op.empty() && isVariable(instr.op1.op)) {
            Variable &v = getVariable(instr.op1.op);
            switch (v.type) {
            case VarType::VAR_INTEGER:
            case VarType::VAR_BYTE:
                v.var_value.int_value = -v.var_value.int_value;
                break;
            case VarType::VAR_FLOAT:
                v.var_value.float_value = -v.var_value.float_value;
                break;
            default:
                throw mx::Exception("NEG: unsupported variable type");
            }
        }
    }

    Variable Program::createTempVariable(VarType type, const std::string &value) {
        Variable temp;
        temp.type = type;
        temp.var_name = "";
        if (type == VarType::VAR_INTEGER) {
            if (value.empty())
                throw mx::Exception("empty integer constant: " + value);
            temp.var_value.int_value = std::stoll(value, nullptr, 0);
            temp.var_value.type = VarType::VAR_INTEGER;
        } else if (type == VarType::VAR_FLOAT) {
            temp.var_value.float_value = std::stod(value);
            temp.var_value.type = VarType::VAR_FLOAT;
        } else if (type == VarType::VAR_STRING) {
            temp.var_value.str_value = value;
            temp.var_value.type = VarType::VAR_STRING;
        }
        return temp;
    }

    void Program::setVariableFromConstant(Variable &var, const std::string &value) {
        if (var.type == VarType::VAR_INTEGER) {
            var.var_value.int_value = std::stoll(value, nullptr, 0);
            var.var_value.type = VarType::VAR_INTEGER;
        } else if (var.type == VarType::VAR_FLOAT) {
            var.var_value.float_value = std::stod(value);
            var.var_value.type = VarType::VAR_FLOAT;
        } else if (var.type == VarType::VAR_STRING) {
            var.var_value.str_value = value;
            var.var_value.type = VarType::VAR_STRING;
        } else if (var.type == VarType::VAR_POINTER) {
            if (value == "null" || value == "NULL" || value == "0") {
                var.var_value.ptr_value = nullptr;
            } else {
                uintptr_t addr = std::stoull(value, nullptr, 0);
                var.var_value.ptr_value = reinterpret_cast<void *>(addr);
            }
            var.var_value.type = VarType::VAR_POINTER;
            var.var_value.owns = false;
        }
    }

    void Program::print(std::ostream &out) {
        out << "Debug Information..\n";
        out << "=== INSTRUCTIONS ===\n";
        if (inc.empty()) {
            out << "  (no instructions)\n";
        } else {
            out << std::left << std::setw(10) << "Addr"
                << std::setw(20) << "Instruction"
                << std::setw(25) << "Operand1"
                << std::setw(25) << "Operand2"
                << std::setw(25) << "Operand3"
                << std::setw(30) << "Extra Operands" << "\n";
            out << std::string(130, '-') << "\n";

            for (size_t i = 0; i < inc.size(); ++i) {
                const auto &instr = inc[i];
                out << std::setw(10) << i;
                if (instr.instruction >= 0 && instr.instruction < static_cast<int>(IncType.size())) {
                    out << std::setw(12) << IncType[instr.instruction];
                } else {
                    out << std::setw(12) << "UNKNOWN";
                }
                out << std::setw(25) << (instr.op1.op.empty() ? "-" : instr.op1.op);
                out << std::setw(25) << (instr.op2.op.empty() ? "-" : instr.op2.op);
                out << std::setw(25) << (instr.op3.op.empty() ? "-" : instr.op3.op);
                if (!instr.vop.empty()) {
                    std::string extraOps;
                    for (size_t j = 0; j < instr.vop.size(); ++j) {
                        if (j > 0)
                            extraOps += ", ";
                        extraOps += instr.vop[j].op;
                    }
                    out << std::setw(30) << extraOps;
                } else {
                    out << std::setw(30) << "-";
                }

                out << "\n";
            }
        }
        out << "\n";
    }

    void Program::exec_invoke(const Instruction &instr) {
        auto it = external_functions.find(instr.op1.op);
        if (it == external_functions.end()) {
            throw mx::Exception("INVOKE: external function not found: " + instr.op1.op);
        }

        std::vector<Operand> args;

        auto process_operand = [&](Operand op) {
            if (op.op.empty())
                return;

            if (isVariable(op.op)) {
                Variable &v = getVariable(op.op);
                if ((v.type == VarType::VAR_POINTER || v.type == VarType::VAR_EXTERN)) {
                    if (v.var_value.ptr_value == nullptr) {
                        if (instr.op1.op == "strlen" || instr.op1.op == "strncpy" ||
                            instr.op1.op == "strncat" || instr.op1.op == "draw_text") {
                            op.op = "";
                            op.type = OperandType::OP_CONSTANT;
                        }
                    }
                }
            }
            args.push_back(op);
        };

        process_operand(instr.op2);
        process_operand(instr.op3);
        for (const auto &vop : instr.vop) {
            process_operand(vop);
        }

        it->second.call(this, args);
        result.op = "%rax";
    }

    void Program::post(std::ostream &out) {
        if (stack.empty()) {
            out << "Stack aligned.\n";
        } else {
            out << "Stack unaligned. {\n";
            for (size_t i = 0; i < stack.size(); ++i) {
                out << "\tAddress: [" << i << "] = ";
                const StackValue &value = stack[i];
                if (std::holds_alternative<int64_t>(value)) {
                    out << std::get<int64_t>(value);
                } else if (std::holds_alternative<void *>(value)) {
                    void *ptr = std::get<void *>(value);
                    if (ptr == nullptr) {
                        out << "null";
                    } else {
                        out << "0x" << std::hex << reinterpret_cast<uintptr_t>(ptr) << std::dec;
                    }
                } else {
                    out << "(unknown)";
                }
                out << "\n";
            }
            out << "}\n";
        }
    }

    Variable Program::variableFromOperand(const Operand &op) {
        if (isVariable(op.op)) {
            return getVariable(op.op);
        } else if (op.type == OperandType::OP_CONSTANT) {
            return createTempVariable(VarType::VAR_INTEGER, op.op);
        }
        throw mx::Exception("Could not create variable from operand: " + op.op);
    }

    void Program::exec_fcmp(const Instruction &instr) {
        Variable *var1 = nullptr;
        Variable *var2 = nullptr;
        Variable temp1, temp2;

        if (isVariable(instr.op1.op)) {
            var1 = &getVariable(instr.op1.op);
        } else {
            temp1 = createTempVariable(VarType::VAR_FLOAT, instr.op1.op);
            var1 = &temp1;
        }
        if (isVariable(instr.op2.op)) {
            var2 = &getVariable(instr.op2.op);
        } else {
            temp2 = createTempVariable(VarType::VAR_FLOAT, instr.op2.op);
            var2 = &temp2;
        }

        zero_flag = false;
        less_flag = false;
        greater_flag = false;

        double val1, val2;
        if (var1->type == VarType::VAR_FLOAT) {
            val1 = var1->var_value.float_value;
        } else if (var1->type == VarType::VAR_INTEGER || var1->type == VarType::VAR_BYTE) {
            val1 = static_cast<double>(var1->var_value.int_value);
        } else {
            throw mx::Exception("FCMP: unsupported operand type for var1");
        }

        if (var2->type == VarType::VAR_FLOAT) {
            val2 = var2->var_value.float_value;
        } else if (var2->type == VarType::VAR_INTEGER || var2->type == VarType::VAR_BYTE) {
            val2 = static_cast<double>(var2->var_value.int_value);
        } else {
            throw mx::Exception("FCMP: unsupported operand type for var2");
        }

        if (val1 == val2) {
            zero_flag = true;
        } else if (val1 < val2) {
            less_flag = true;
        } else {
            greater_flag = true;
        }
    }

    void Program::exec_jae(const Instruction &instr) {
        if (greater_flag || zero_flag)
            exec_jmp(instr);
        else
            pc++;
    }

    void Program::exec_jbe(const Instruction &instr) {
        if (less_flag || zero_flag)
            exec_jmp(instr);
        else
            pc++;
    }

    void Program::exec_jc(const Instruction &instr) {
        if (carry_flag)
            exec_jmp(instr);
        else
            pc++;
    }

    void Program::exec_jnc(const Instruction &instr) {
        if (!carry_flag)
            exec_jmp(instr);
        else
            pc++;
    }

    void Program::exec_jp(const Instruction &instr) {
        pc++;
    }

    void Program::exec_jnp(const Instruction &instr) {
        exec_jmp(instr);
    }

    void Program::exec_jo(const Instruction &instr) {
        pc++;
    }

    void Program::exec_jno(const Instruction &instr) {
        exec_jmp(instr);
    }

    void Program::exec_js(const Instruction &instr) {
        pc++;
    }

    void Program::exec_jns(const Instruction &instr) {
        exec_jmp(instr);
    }

} // namespace mxvm