#include <stdio.h>
#include <memory>
#include <vector>

class VM
{
public:
    struct Obj;

private:
    enum ObjType
    {
        INT,
        FLOAT,
    };

    union Val {
        long ival;

        double dval;

        Val() {}
        Val(long i) { ival = i; }
        Val(double d) { dval = d; }
    };

    static constexpr unsigned long obj_table_size = 1024 * 128;

    static constexpr unsigned long stack_size = 1024 * 128;

    std::vector<unsigned long> iseq;

    std::vector<Obj> const_table;

    inline Obj GetStack(unsigned long &sc, const std::unique_ptr<Obj[]> &stack)
    {
        if (sc == 0)
            return Obj();
        return stack[--sc];
    }

    inline void PushStack(unsigned long &sc, const std::unique_ptr<Obj[]> &stack, const Obj &obj)
    {
        if (sc == stack_size - 1)
            return;
        stack[sc++] = obj;
    }

public:
    struct Obj
    {
    private:
        ObjType type;

        Val value;

    public:
        Obj()
        {
            type = INT;
            value.ival = 0;
        };

        Obj(int val)
        {
            type = INT;
            value.ival = val;
        }

        Obj(long val)
        {
            type = INT;
            value.ival = val;
        };

        Obj(double val)
        {
            type = FLOAT;
            value.dval = val;
        };

        inline ObjType Type()
        {
            return type;
        };

        void SetInt(int val)
        {
            type = INT;

            value.ival = val;
        };

        void SetFloat(double val)
        {
            type = FLOAT;

            value.dval = val;
        };

        int GetInt()
        {
            switch (type)
            {
            case INT:
                return value.ival;

            case FLOAT:
                return value.dval;

            default:
                break;
            }

            return 0;
        };

        double GetFloat()
        {
            switch (type)
            {
            case INT:
                return value.ival;

            case FLOAT:
                return value.dval;

            default:
                break;
            }

            return 0.0;
        };

        void Out();
    };

    enum Inst
    {
        PUSH,
        PUSH_OBJ,
        PUSH_CONST,
        SET_OBJ,

        BOPE,
        ADD,
        SUB,
        MUL,
        DIV,
        MOD,
        EQUAL,
        NOT_EQUAL,
        GREATER_THAN,
        GREATER_THAN_OR_EQUAL,
        LESS_THAN,
        LESS_THAN_OR_EQUAL,
        AND,
        OR,
        NOT,

        INPUT,
        OUT,

        YAY,

        JUMP,
        JUMP_IF,

        START,
        END,
    };

    VM(std::vector<unsigned long> iseq, std::vector<Obj> const_table)
    {
        this->iseq = iseq;
        this->const_table = const_table;
    };

    void Run();

    void Run(unsigned long startIndex);
};

void VM::Obj::Out()
{
    switch (type)
    {
    case INT:
        printf("%ld\n", value.ival);
        break;

    case FLOAT:
        printf("%lf\n", value.dval);
        break;

    default:
        break;
    }
}

void VM::Run()
{
    Run(0);
}

void VM::Run(unsigned long startIndex)
{
    std::unique_ptr<Obj[]> obj_table(new Obj[obj_table_size]);

    std::unique_ptr<Obj[]> stack(new Obj[stack_size]);

    unsigned long pc = startIndex;

    unsigned long sc = 0;

    if (iseq[pc] != START)
        return;

    pc += 1;

    while (true)
    {
        unsigned long inst = iseq[pc];

        if (inst == END)
            break;

        if (inst == START)
            break;

        switch (inst)
        {
        case PUSH:
            PushStack(sc, stack, Obj((long)iseq[pc + 1]));
            pc += 2;

            break;

        case PUSH_OBJ:
            PushStack(sc, stack, obj_table[iseq[pc + 1]]);
            pc += 2;

            break;

        case PUSH_CONST:
            PushStack(sc, stack, const_table[iseq[pc + 1]]);
            pc += 2;

            break;

        case SET_OBJ:
            obj_table[iseq[pc + 1]] = GetStack(sc, stack);
            pc += 2;

            break;

        case BOPE:
        {
            unsigned long ope = iseq[pc + 1];

            Obj right = GetStack(sc, stack);
            Obj left = GetStack(sc, stack);

            ObjType type;
            if (left.Type() == INT && right.Type() == INT)
                type = INT;
            else
                type = FLOAT;

            Obj obj;

            switch (ope)
            {
            case ADD:
                switch (type)
                {
                case INT:
                    obj.SetInt(left.GetInt() + right.GetInt());
                    break;

                case FLOAT:
                    obj.SetFloat(left.GetFloat() + right.GetFloat());
                    break;

                default:
                    break;
                }

                break;

            case SUB:
                switch (type)
                {
                case INT:
                    obj.SetInt(left.GetInt() - right.GetInt());
                    break;

                case FLOAT:
                    obj.SetFloat(left.GetFloat() - right.GetFloat());
                    break;

                default:
                    break;
                }

                break;

            case MUL:
                switch (type)
                {
                case INT:
                    obj.SetInt(left.GetInt() * right.GetInt());
                    break;

                case FLOAT:
                    obj.SetFloat(left.GetFloat() * right.GetFloat());
                    break;

                default:
                    break;
                }

                break;

            case DIV:
                switch (type)
                {
                case INT:
                    if (right.GetInt() == 0)
                    {
                        obj.SetInt(0);
                    }
                    else
                    {
                        unsigned long lv = left.GetInt();
                        unsigned long rv = right.GetInt();
                        if (lv % rv == 0)
                            obj.SetInt(lv / rv);
                        else
                            obj.SetFloat((double)lv / rv);
                    }
                    break;

                case FLOAT:
                    if (right.GetFloat() == 0)
                        obj.SetFloat(0);
                    else
                        obj.SetFloat(left.GetFloat() / right.GetFloat());
                    break;

                default:
                    break;
                }

                break;

            case MOD:
                switch (type)
                {
                case INT:
                    if (right.GetInt() == 0)
                        obj.SetInt(0);
                    else
                        obj.SetInt(left.GetInt() % right.GetInt());
                    break;

                case FLOAT:
                    obj.SetFloat(0);
                    break;

                default:
                    break;
                }

                break;

            case EQUAL:
                switch (type)
                {
                case INT:
                    obj.SetInt(left.GetInt() == right.GetInt() ? 1 : 0);
                    break;

                case FLOAT:
                    obj.SetInt(left.GetFloat() == right.GetFloat() ? 1 : 0);
                    break;

                default:
                    break;
                }

                break;

            case NOT_EQUAL:
                switch (type)
                {
                case INT:
                    obj.SetInt(left.GetInt() != right.GetInt() ? 1 : 0);
                    break;

                case FLOAT:
                    obj.SetInt(left.GetFloat() != right.GetFloat() ? 1 : 0);
                    break;

                default:
                    break;
                }

                break;

            case GREATER_THAN:
                switch (type)
                {
                case INT:
                    obj.SetInt(left.GetInt() > right.GetInt() ? 1 : 0);
                    break;

                case FLOAT:
                    obj.SetInt(left.GetFloat() > right.GetFloat() ? 1 : 0);
                    break;

                default:
                    break;
                }

                break;

            case GREATER_THAN_OR_EQUAL:
                switch (type)
                {
                case INT:
                    obj.SetInt(left.GetInt() >= right.GetInt() ? 1 : 0);
                    break;

                case FLOAT:
                    obj.SetInt(left.GetFloat() >= right.GetFloat() ? 1 : 0);
                    break;

                default:
                    break;
                }

                break;

            case LESS_THAN:
                switch (type)
                {
                case INT:
                    obj.SetInt(left.GetInt() < right.GetInt() ? 1 : 0);
                    break;

                case FLOAT:
                    obj.SetInt(left.GetFloat() < right.GetFloat() ? 1 : 0);
                    break;

                default:
                    break;
                }

                break;

            case LESS_THAN_OR_EQUAL:
                switch (type)
                {
                case INT:
                    obj.SetInt(left.GetInt() <= right.GetInt() ? 1 : 0);
                    break;

                case FLOAT:
                    obj.SetInt(left.GetFloat() <= right.GetFloat() ? 1 : 0);
                    break;

                default:
                    break;
                }

                break;

            case AND:
                switch (type)
                {
                case INT:
                    obj.SetInt((left.GetInt() > 0 && right.GetInt() > 0) ? 1 : 0);
                    break;

                case FLOAT:
                    obj.SetInt((left.GetFloat() > 0 + right.GetFloat() > 0) ? 1 : 0);
                    break;

                default:
                    break;
                }

                break;

            case OR:
                switch (type)
                {
                case INT:
                    obj.SetInt((left.GetInt() > 0 || right.GetInt() > 0) ? 1 : 0);
                    break;

                case FLOAT:
                    obj.SetInt((left.GetFloat() > 0 || right.GetFloat() > 0) ? 1 : 0);
                    break;

                default:
                    break;
                }

                break;

            default:
                break;
            }

            PushStack(sc, stack, obj);
            pc += 2;
        }

        break;

        case NOT:
        {
            Obj left = GetStack(sc, stack);

            Obj obj;

            switch (left.Type())
            {
            case INT:
                obj.SetInt(left.GetInt() <= 0);
                break;

            case FLOAT:
                obj.SetInt(left.GetFloat() <= 0);
                break;

            default:
                break;
            }

            PushStack(sc, stack, obj);
            pc += 1;
        }

        break;

        case INPUT:
        {
            double val;
            scanf("%lf", &val);

            Obj obj;

            if ((long)val == val)
                obj.SetInt((long)val);
            else
                obj.SetFloat(val);

            PushStack(sc, stack, obj);

            pc += 1;
        }

        break;

        case OUT:
            GetStack(sc, stack).Out();
            pc += 1;

            break;

        case YAY:
            printf("Yay\n");
            pc += 1;

            break;

        case JUMP:
            pc = GetStack(sc, stack).GetInt();

            break;

        case JUMP_IF:
            if (GetStack(sc, stack).GetInt() > 0)
            {
                pc = GetStack(sc, stack).GetInt();
            }
            else
            {
                GetStack(sc, stack);
                pc += 1;
            }

        default:
            break;
        }
    }
}

int main()
{
    std::vector<unsigned long> iseq = {VM::START,
                                       VM::PUSH_CONST,
                                       0,
                                       VM::INPUT,
                                       VM::BOPE,
                                       VM::SUB,
                                       VM::INPUT,
                                       VM::BOPE,
                                       VM::SUB,
                                       VM::OUT,
                                       VM::END};

    std::vector<VM::Obj> const_table = {VM::Obj(6)};

    VM eval = VM(iseq, const_table);

    eval.Run(0);

    return 0;
}

Measured memory_bytes: 4352