Last active
          December 31, 2015 20:29 
        
      - 
      
- 
        Save vittorioromeo/8040926 to your computer and use it in GitHub Desktop. 
    Simple virtual machine created for fun (now with WIP function magic)
  
        
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | namespace ssvvm | |
| { | |
| class Value | |
| { | |
| public: | |
| enum class Type{Null, Int, Float}; | |
| private: | |
| Type type{Type::Null}; | |
| union { int implInt; float implFloat; }; | |
| public: | |
| template<typename T> inline static Value create(T mContents) noexcept { return {mContents}; } | |
| inline Value() = default; | |
| template<typename T> inline Value(T mContents) noexcept { setType<T>(); set<T>(mContents); } | |
| template<typename T> inline void setType() noexcept { type = Value::getType<T>(); } | |
| template<typename T> inline void set(T mContents) noexcept; | |
| template<typename T> inline T get() const noexcept; | |
| inline Type getType() const noexcept { return type; } | |
| template<typename T> inline static Type getType() noexcept; | |
| }; | |
| template<> inline void Value::set<int>(int mContents) noexcept { assert(type == Type::Int); implInt = mContents; } | |
| template<> inline void Value::set<float>(float mContents) noexcept { assert(type == Type::Float); implFloat = mContents; } | |
| template<> inline int Value::get<int>() const noexcept { assert(type == Type::Int); return implInt; } | |
| template<> inline float Value::get<float>() const noexcept { assert(type == Type::Float); return implFloat; } | |
| template<> inline Value::Type Value::getType<int>() noexcept { return Type::Int; } | |
| template<> inline Value::Type Value::getType<float>() noexcept { return Type::Float; } | |
| struct Register { using Idx = int; Value value; }; | |
| namespace Internal | |
| { | |
| template<typename T, std::size_t TIdx, typename TArg> inline void arrayFillHelper(T& mArray, const TArg& mArg) { mArray[TIdx] = Value::create<TArg>(mArg); } | |
| template<typename T, std::size_t TIdx, typename TArg, typename... TArgs> inline void arrayFillHelper(T& mArray, const TArg& mArg, const TArgs&... mArgs) | |
| { | |
| arrayFillHelper<T, TIdx>(mArray, mArg); arrayFillHelper<T, TIdx + 1>(mArray, std::forward<const TArgs&>(mArgs)...); | |
| } | |
| } | |
| class Params | |
| { | |
| public: | |
| static constexpr std::size_t valueCount{3}; | |
| private: | |
| std::array<Value, valueCount> values; | |
| public: | |
| inline Params() = default; | |
| template<typename... TArgs> inline Params(const TArgs&... mArgs) noexcept { Internal::arrayFillHelper<decltype(values), 0>(values, mArgs...); } | |
| inline const Value& operator[](std::size_t mIdx) const noexcept { assert(mIdx < valueCount); return values[mIdx]; } | |
| inline const decltype(values)& getValues() const noexcept { return values; } // TODO: remove | |
| }; | |
| template<std::size_t TSize> class Registry | |
| { | |
| private: | |
| std::array<Register, TSize> registers; | |
| public: | |
| inline Register& get(std::size_t mIdx) noexcept { assert(mIdx < TSize); return registers[mIdx]; } | |
| inline const Register& get(std::size_t mIdx) const noexcept { assert(mIdx < TSize); return registers[mIdx]; } | |
| inline Value& getValue(std::size_t mIdx) noexcept { return get(mIdx).value; } | |
| inline const Value& getValue(std::size_t mIdx) const noexcept { return get(mIdx).value; } | |
| inline std::size_t getSize() const noexcept { return TSize; } | |
| }; | |
| class Stack | |
| { | |
| private: | |
| std::vector<Value> stack; | |
| int baseOffset{0}; // Distance between top and base | |
| public: | |
| inline void pushBaseOffset() noexcept { push(Value::create<int>(baseOffset)); baseOffset = 0; } | |
| inline void popBaseOffset() noexcept { baseOffset = getPop().get<int>(); } | |
| inline void push(Value mValue) noexcept { stack.push_back(mValue); ++baseOffset; } | |
| inline Value getPop() noexcept { assert(!stack.empty()); auto result(stack.back()); stack.pop_back(); --baseOffset; return result; } | |
| inline const Value& getTop() const noexcept { return stack.back(); } | |
| inline Value& getTop() noexcept { return stack.back(); } | |
| inline const Value& getTop(int mOffset) const noexcept { return *(std::end(stack) - mOffset - 1); } | |
| inline Value& getTop(int mOffset) noexcept { return *(std::end(stack) - mOffset - 1); } | |
| inline void pop() noexcept { assert(!stack.empty()); stack.pop_back(); } | |
| inline Value getFromBase(int mOffset) noexcept { return *(std::end(stack) - baseOffset - mOffset - 1); } | |
| inline int getBaseOffset() const { return baseOffset; } | |
| inline const decltype(stack)& getStack() const noexcept { return stack; } | |
| }; | |
| enum class OpCode : std::size_t | |
| { | |
| // Virtual machine control | |
| Halt = 0, | |
| // Register instructions | |
| LoadIntCVToR, | |
| LoadFloatCVToR, | |
| MoveRVToR, | |
| // Register-stack instructions | |
| PushRVToS, | |
| PopSVToR, | |
| MoveSBOVToR, | |
| // Stack instructions | |
| PushIntCVToS, | |
| PushFloatCVToS, | |
| PushSVToS, | |
| PopSV, | |
| // Program logic | |
| GoToPI, | |
| GoToPIIfIntRV, | |
| GoToPIIfCompareRVGreater, | |
| GoToPIIfCompareRVSmaller, | |
| GoToPIIfCompareRVEqual, | |
| CallPI, | |
| ReturnPI, | |
| // Register basic arithmetic | |
| IncrementIntRV, | |
| DecrementIntRV, | |
| // Stack basic arithmetic | |
| AddInt2SVs, | |
| AddFloat2SVs, | |
| SubtractInt2SVs, | |
| SubtractFloat2SVs, | |
| MultiplyInt2SVs, | |
| MultiplyFloat2SVs, | |
| DivideInt2SVs, | |
| DivideFloat2SVs, | |
| // Comparisons | |
| CompareIntRVIntRVToR, | |
| CompareIntRVIntSVToR, | |
| CompareIntSVIntSVToR, | |
| CompareIntRVIntCVToR, | |
| CompareIntSVIntCVToR | |
| }; | |
| template<typename T> using VMFnPtr = void(T::*)(); | |
| template<typename T> inline VMFnPtr<T> getVMFnPtr(OpCode mOpCode) noexcept | |
| { | |
| static VMFnPtr<T> fnPtrs[] | |
| { | |
| // Virtual machine control | |
| &T::halt, | |
| // Register instructions | |
| &T::loadIntCVToR, | |
| &T::loadFloatCVToR, | |
| &T::moveRVToR, | |
| // Register-stack instructions | |
| &T::pushRVToS, | |
| &T::popSVToR, | |
| &T::moveSBOVToR, | |
| // Stack instructions | |
| &T::pushIntCVToS, | |
| &T::pushFloatCVToS, | |
| &T::pushSVToS, | |
| &T::popSV, | |
| // Program logic | |
| &T::goToPI, | |
| &T::goToPIIfIntRV, | |
| &T::goToPIIfCompareRVGreater, | |
| &T::goToPIIfCompareRVSmaller, | |
| &T::goToPIIfCompareRVEqual, | |
| &T::callPI, | |
| &T::returnPI, | |
| // Register basic arithmetic | |
| &T::incrementIntRV, | |
| &T::decrementIntRV, | |
| // Stack basic arithmetic | |
| &T::addInt2SVs, | |
| &T::addFloat2SVs, | |
| &T::subtractInt2SVs, | |
| &T::subtractFloat2SVs, | |
| &T::multiplyInt2SVs, | |
| &T::multiplyFloat2SVs, | |
| &T::divideInt2SVs, | |
| &T::divideFloat2SVs, | |
| // Comparisons | |
| &T::compareIntRVIntRVToR, | |
| &T::compareIntRVIntSVToR, | |
| &T::compareIntSVIntSVToR, | |
| &T::compareIntRVIntCVToR, | |
| &T::compareIntSVIntCVToR | |
| }; | |
| return fnPtrs[std::size_t(mOpCode)]; | |
| } | |
| struct Instruction | |
| { | |
| using Idx = int; | |
| OpCode opCode; | |
| Params params; | |
| inline Instruction() = default; | |
| template<typename... TArgs> inline Instruction(OpCode mOpCode, TArgs... mArgs) noexcept : opCode{mOpCode}, params{mArgs...} { } | |
| }; | |
| struct Program | |
| { | |
| private: | |
| std::vector<Instruction> instructions; | |
| public: | |
| inline Program& operator+=(Instruction mInstruction) { instructions.emplace_back(std::move(mInstruction)); return *this; } | |
| inline const Instruction& operator[](std::size_t mIdx) const noexcept { assert(mIdx < instructions.size()); return instructions[mIdx]; } | |
| inline std::size_t getSize() const noexcept { return instructions.size(); } | |
| }; | |
| struct VMOperations | |
| { | |
| inline static Value getIntAddition(const Value& mA, const Value& mB) noexcept { return Value::create<int>(mA.get<int>() + mB.get<int>()); } | |
| inline static Value getFloatAddition(const Value& mA, const Value& mB) noexcept { return Value::create<float>(mA.get<float>() + mB.get<float>()); } | |
| inline static Value getIntSubtraction(const Value& mA, const Value& mB) noexcept { return Value::create<int>(mA.get<int>() - mB.get<int>()); } | |
| inline static Value getFloatSubtraction(const Value& mA, const Value& mB) noexcept { return Value::create<float>(mA.get<float>() - mB.get<float>()); } | |
| inline static Value getIntMultiplication(const Value& mA, const Value& mB) noexcept { return Value::create<int>(mA.get<int>() * mB.get<int>()); } | |
| inline static Value getFloatMultiplication(const Value& mA, const Value& mB) noexcept { return Value::create<float>(mA.get<float>() * mB.get<float>()); } | |
| inline static Value getIntDivision(const Value& mA, const Value& mB) noexcept { return Value::create<int>(mA.get<int>() / mB.get<int>()); } | |
| inline static Value getFloatDivision(const Value& mA, const Value& mB) noexcept { return Value::create<float>(mA.get<float>() / mB.get<float>()); } | |
| inline static Value getIntComparison(const Value& mA, const Value& mB) noexcept | |
| { | |
| if(mA.get<int>() > mB.get<int>()) return {1}; | |
| if(mA.get<int>() < mB.get<int>()) return {-1}; | |
| return {0}; | |
| } | |
| }; | |
| namespace Internal | |
| { | |
| template<std::size_t TRegistrySize, bool TDebug> class VMImpl | |
| { | |
| public: | |
| Registry<TRegistrySize> registry; | |
| Stack stack; | |
| Instruction::Idx programCounter{0}; | |
| Program program; | |
| Instruction programInstruction; | |
| VMFnPtr<VMImpl> fnPtr; | |
| Params params; | |
| bool running{false}; | |
| // Helper functions | |
| inline Value& getRV(const Value& mValueIdx) noexcept { return registry.getValue(mValueIdx.get<Register::Idx>()); } | |
| template<typename T> inline Value execOnStack2(const T& mFn) noexcept | |
| { | |
| Value a{stack.getPop()}, b{stack.getPop()}; | |
| if(TDebug) | |
| { | |
| ssvu::lo("execOnStack2") << "Value A\t" << a << "\n"; | |
| ssvu::lo("execOnStack2") << "Value B\t" << b << "\n"; | |
| } | |
| return mFn(a, b); | |
| } | |
| // Instructions | |
| inline void halt() noexcept | |
| { | |
| running = false; | |
| if(TDebug) ssvu::lo("halt") << "Execution halted" << "\n"; | |
| } | |
| inline void loadIntCVToR() noexcept | |
| { | |
| assert(params[1].getType() == Value::Type::Int); | |
| auto& regValue(getRV(params[0])); | |
| regValue = params[1]; | |
| if(TDebug) | |
| { | |
| const auto& dbgIdxReg(params[0].get<Register::Idx>()); | |
| ssvu::lo("loadIntCVToR") << "Loaded " << params[1] << " into register " << dbgIdxReg << "\n"; | |
| } | |
| } | |
| inline void loadFloatCVToR() noexcept | |
| { | |
| assert(params[1].getType() == Value::Type::Float); | |
| auto& regValue(getRV(params[0])); | |
| regValue = params[1]; | |
| if(TDebug) | |
| { | |
| const auto& dbgIdxReg(params[0].get<Register::Idx>()); | |
| ssvu::lo("loadFloatCVToR") << "Loaded " << params[1] << " into register " << dbgIdxReg << "\n"; | |
| } | |
| } | |
| inline void moveRVToR() noexcept | |
| { | |
| const auto& idxDst(params[0].get<Register::Idx>()); | |
| const auto& idxSrc(params[1].get<Register::Idx>()); | |
| registry.get(idxDst) = registry.get(idxSrc); | |
| if(TDebug) | |
| { | |
| ssvu::lo("moveRVToR") << "Moved register " << idxSrc << " into register " << idxDst << "\n"; | |
| ssvu::lo("moveRVToR") << "Both registers' value is now " << registry.get(idxSrc).value << "\n"; | |
| } | |
| } | |
| inline void pushRVToS() noexcept | |
| { | |
| const auto& toPush(getRV(params[0])); | |
| stack.push(toPush); | |
| if(TDebug) | |
| { | |
| const auto& dbgIdxReg(params[0].get<Register::Idx>()); | |
| ssvu::lo("pushRVToS") << "Pushed register " << dbgIdxReg << " value " << toPush << " onto stack" << "\n"; | |
| } | |
| } | |
| inline void popSVToR() noexcept | |
| { | |
| auto& popDst(getRV(params[0])); | |
| popDst = stack.getPop(); | |
| if(TDebug) | |
| { | |
| const auto& dbgIdxReg(params[0].get<Register::Idx>()); | |
| ssvu::lo("popSVToR") << "Popped value " << popDst << " in register " << dbgIdxReg << " from stack" << "\n"; | |
| } | |
| } | |
| inline void moveSBOVToR() noexcept | |
| { | |
| const auto& sbOffset(stack.getFromBase(params[1].get<int>())); | |
| if(TDebug) | |
| { | |
| const auto& dbgIdxReg(params[0].get<Register::Idx>()); | |
| ssvu::lo("moveSBOVToR") << "Moved SBO value " << sbOffset << " into register " << dbgIdxReg << " from stack base offset" << "\n"; | |
| } | |
| getRV(params[0]) = sbOffset; | |
| } | |
| inline void pushIntCVToS() noexcept | |
| { | |
| if(TDebug) | |
| { | |
| ssvu::lo("pushIntCVToS") << "Pushing constant int value " << params[0] << " on stack" << "\n"; | |
| } | |
| assert(params[0].getType() == Value::Type::Int); | |
| stack.push(params[0]); | |
| } | |
| inline void pushFloatCVToS() noexcept | |
| { | |
| if(TDebug) | |
| { | |
| ssvu::lo("pushFloatCVToS") << "Pushing constant float value " << params[0] << " on stack" << "\n"; | |
| } | |
| assert(params[0].getType() == Value::Type::Float); | |
| stack.push(params[0]); | |
| } | |
| inline void pushSVToS() noexcept | |
| { | |
| if(TDebug) | |
| { | |
| ssvu::lo("pushSVToS") << "Pushing stack top (duplicating) value " << stack.getTop() << "\n"; | |
| } | |
| stack.push(stack.getTop()); | |
| } | |
| inline void popSV() noexcept | |
| { | |
| if(TDebug) | |
| { | |
| ssvu::lo("popSV") << "Popping stack top (removing) value " << stack.getTop() << "\n"; | |
| } | |
| stack.pop(); | |
| } | |
| inline void goToPI() noexcept | |
| { | |
| const auto& jmpDst(params[0].get<Instruction::Idx>()); | |
| if(TDebug) | |
| { | |
| ssvu::lo("goToPI") << "Unconditional jump to instruction " << jmpDst << "\n"; | |
| } | |
| programCounter = jmpDst; | |
| } | |
| inline void goToPIIfIntRV() noexcept | |
| { | |
| const auto& jmpDst(params[0].get<Instruction::Idx>()); | |
| const auto& cndVal(getRV(params[1])); | |
| if(TDebug) | |
| { | |
| const auto& dbgIdxReg(params[1].get<Register::Idx>()); | |
| ssvu::lo("goToPIIfIntRV") << "Conditional jump to instruction " << jmpDst << "\n"; | |
| ssvu::lo("goToPIIfIntRV") << "Condition: register " << dbgIdxReg << " value " << cndVal << " != 0\n"; | |
| } | |
| if(cndVal.template get<int>() != 0) | |
| { | |
| programCounter = jmpDst; | |
| if(TDebug) ssvu::lo("goToPIIfIntRV") << "Conditional jump SUCCESS" << "\n"; | |
| } | |
| else if(TDebug) ssvu::lo("goToPIIfIntRV") << "Conditional jump FAILURE" << "\n"; | |
| } | |
| inline void goToPIIfCompareRVGreater() noexcept | |
| { | |
| const auto& jmpDst(params[0].get<Instruction::Idx>()); | |
| const auto& cndVal(getRV(params[1])); | |
| if(TDebug) | |
| { | |
| const auto& dbgIdxReg(params[1].get<Register::Idx>()); | |
| ssvu::lo("goToPIIfCompareRVGreater") << "Conditional jump to instruction " << jmpDst << "\n"; | |
| ssvu::lo("goToPIIfCompareRVGreater") << "Condition GREATER: register " << dbgIdxReg << " compare value " << cndVal << " == 1\n"; | |
| } | |
| if(cndVal.template get<int>() == 1) | |
| { | |
| programCounter = jmpDst; | |
| if(TDebug) ssvu::lo("goToPIIfCompareRVGreater") << "Conditional jump SUCCESS" << "\n"; | |
| } | |
| else if(TDebug) ssvu::lo("goToPIIfCompareRVGreater") << "Conditional jump FAILURE" << "\n"; | |
| } | |
| inline void goToPIIfCompareRVSmaller() noexcept | |
| { | |
| const auto& jmpDst(params[0].get<Instruction::Idx>()); | |
| const auto& cndVal(getRV(params[1])); | |
| if(TDebug) | |
| { | |
| const auto& dbgIdxReg(params[1].get<Register::Idx>()); | |
| ssvu::lo("goToPIIfCompareRVSmaller") << "Conditional jump to instruction " << jmpDst << "\n"; | |
| ssvu::lo("goToPIIfCompareRVSmaller") << "Condition SMALLER: register " << dbgIdxReg << " compare value " << cndVal << " == -1\n"; | |
| } | |
| if(cndVal.template get<int>() == -1) | |
| { | |
| programCounter = jmpDst; | |
| if(TDebug) ssvu::lo("goToPIIfCompareRVSmaller") << "Conditional jump SUCCESS" << "\n"; | |
| } | |
| else if(TDebug) ssvu::lo("goToPIIfCompareRVSmaller") << "Conditional jump FAILURE" << "\n"; | |
| } | |
| inline void goToPIIfCompareRVEqual() noexcept | |
| { | |
| const auto& jmpDst(params[0].get<Instruction::Idx>()); | |
| const auto& cndVal(getRV(params[1])); | |
| if(TDebug) | |
| { | |
| const auto& dbgIdxReg(params[1].get<Register::Idx>()); | |
| ssvu::lo("goToPIIfCompareRVEqual") << "Conditional jump to instruction " << jmpDst << "\n"; | |
| ssvu::lo("goToPIIfCompareRVEqual") << "Condition EQUAL: register " << dbgIdxReg << " compare value " << cndVal << " == 0\n"; | |
| } | |
| if(cndVal.template get<int>() == 1) | |
| { | |
| programCounter = jmpDst; | |
| if(TDebug) ssvu::lo("goToPIIfCompareRVEqual") << "Conditional jump SUCCESS" << "\n"; | |
| } | |
| else if(TDebug) ssvu::lo("goToPIIfCompareRVEqual") << "Conditional jump FAILURE" << "\n"; | |
| } | |
| inline void callPI() noexcept | |
| { | |
| const auto& callDst(params[0].get<Instruction::Idx>()); | |
| if(TDebug) ssvu::lo("callPI") << "Preparing to call function at instruction " << callDst << "\n"; | |
| if(TDebug) ssvu::lo("callPI") << "Push current instruction (" << programCounter << ") on stack (for return)\n"; | |
| stack.push(Value::create<Instruction::Idx>(programCounter)); | |
| if(TDebug) ssvu::lo("callPI") << "Push current stack base (" << stack.getBaseOffset() << ") and reset it\n"; | |
| stack.pushBaseOffset(); | |
| if(TDebug) ssvu::lo("callPI") << "Calling function (jumping) at instruction " << callDst << "\n"; | |
| programCounter = callDst; | |
| } | |
| inline void returnPI() noexcept | |
| { | |
| if(TDebug) | |
| { | |
| ssvu::lo("returnPI") << "Returning from a function - restoring stack base\n"; | |
| ssvu::lo("returnPI") << "\tBefore: " << stack.getBaseOffset() << "\n"; | |
| } | |
| stack.popBaseOffset(); | |
| const auto& returnDst(stack.getPop().get<Instruction::Idx>()); | |
| if(TDebug) | |
| { | |
| ssvu::lo("returnPI") << "\tAfter: " << stack.getBaseOffset() << "\n"; | |
| ssvu::lo("callPI") << "Returning (jumping) to instruction at the top of the stack (" << returnDst << ")" << "\n"; | |
| } | |
| programCounter = returnDst; | |
| } | |
| inline void incrementIntRV() noexcept | |
| { | |
| auto& regVal(getRV(params[0])); | |
| if(TDebug) | |
| { | |
| const auto& dbgIdxReg(params[0].get<Register::Idx>()); | |
| ssvu::lo("incrementIntRV") << "Incrementing value " << regVal << " in register " << dbgIdxReg << "\n"; | |
| } | |
| regVal.template set<int>(regVal.template get<int>() + 1); | |
| } | |
| inline void decrementIntRV() noexcept | |
| { | |
| auto& regVal(getRV(params[0])); | |
| if(TDebug) | |
| { | |
| const auto& dbgIdxReg(params[0].get<Register::Idx>()); | |
| ssvu::lo("decrementIntRV") << "Decrementing value " << regVal << " in register " << dbgIdxReg << "\n"; | |
| } | |
| regVal.template set<int>(regVal.template get<int>() - 1); | |
| } | |
| inline void addInt2SVs() noexcept | |
| { | |
| if(TDebug) ssvu::lo("addInt2SVs") << "Adding 2 ints" << "\n"; | |
| stack.push(execOnStack2(VMOperations::getIntAddition)); | |
| } | |
| inline void addFloat2SVs() noexcept | |
| { | |
| if(TDebug) ssvu::lo("addFloat2SVs") << "Adding 2 floats" << "\n"; | |
| stack.push(execOnStack2(VMOperations::getFloatAddition)); | |
| } | |
| inline void subtractInt2SVs() noexcept | |
| { | |
| if(TDebug) ssvu::lo("subtractInt2SVs") << "Subtracting 2 ints" << "\n"; | |
| stack.push(execOnStack2(VMOperations::getIntSubtraction)); | |
| } | |
| inline void subtractFloat2SVs() noexcept | |
| { | |
| if(TDebug) ssvu::lo("subtractFloat2SVs") << "Subtracting 2 floats" << "\n"; | |
| stack.push(execOnStack2(VMOperations::getFloatSubtraction)); | |
| } | |
| inline void multiplyInt2SVs() noexcept | |
| { | |
| if(TDebug) ssvu::lo("multiplyInt2SVs") << "Multiplying 2 ints" << "\n"; | |
| stack.push(execOnStack2(VMOperations::getIntMultiplication)); | |
| } | |
| inline void multiplyFloat2SVs() noexcept | |
| { | |
| if(TDebug) ssvu::lo("multiplyFloat2SVs") << "Multiplying 2 floats" << "\n"; | |
| stack.push(execOnStack2(VMOperations::getFloatMultiplication)); | |
| } | |
| inline void divideInt2SVs() noexcept | |
| { | |
| if(TDebug) ssvu::lo("divideInt2SVs") << "Dividing 2 ints" << "\n"; | |
| stack.push(execOnStack2(VMOperations::getIntDivision)); | |
| } | |
| inline void divideFloat2SVs() noexcept | |
| { | |
| if(TDebug) ssvu::lo("divideFloat2SVs") << "Dividing 2 floats" << "\n"; | |
| stack.push(execOnStack2(VMOperations::getFloatDivision)); | |
| } | |
| inline void compareIntRVIntRVToR() noexcept | |
| { | |
| const auto& idxDst(params[0].get<Register::Idx>()); | |
| const auto& idxA(params[1].get<Register::Idx>()); | |
| const auto& idxB(params[2].get<Register::Idx>()); | |
| const auto& valA(registry.get(idxA).value.template get<int>()); | |
| const auto& valB(registry.get(idxB).value.template get<int>()); | |
| const auto& result(VMOperations::getIntComparison(valA, valB)); | |
| registry.get(idxDst).value = result; | |
| if(TDebug) | |
| { | |
| ssvu::lo("compareIntRVIntRVToR") << "Comparing register value " << valA << " with register value " << valB << " into register " << idxDst << "\n"; | |
| ssvu::lo("compareIntRVIntRVToR") << "Register value is now " << result << "\n"; | |
| } | |
| } | |
| inline void compareIntRVIntSVToR() noexcept | |
| { | |
| const auto& idxDst(params[0].get<Register::Idx>()); | |
| const auto& idxA(params[1].get<Register::Idx>()); | |
| const auto& valA(registry.get(idxA).value.template get<int>()); | |
| const auto& valB(stack.getTop()); | |
| const auto& result(VMOperations::getIntComparison(valA, valB)); | |
| registry.get(idxDst).value = result; | |
| if(TDebug) | |
| { | |
| ssvu::lo("compareIntRVIntSVToR") << "Comparing register value " << valA << " with stack value " << valB << " into register " << idxDst << "\n"; | |
| ssvu::lo("compareIntRVIntSVToR") << "Register value is now " << result << "\n"; | |
| } | |
| } | |
| inline void compareIntSVIntSVToR() noexcept | |
| { | |
| const auto& idxDst(params[0].get<Register::Idx>()); | |
| const auto& valA(stack.getTop()); | |
| const auto& valB(stack.getTop(1)); | |
| const auto& result(VMOperations::getIntComparison(valA, valB)); | |
| registry.get(idxDst).value = result; | |
| if(TDebug) | |
| { | |
| ssvu::lo("compareIntRVIntSVToR") << "Comparing stack value " << valA << " with stack value " << valB << " into register " << idxDst << "\n"; | |
| ssvu::lo("compareIntRVIntSVToR") << "Register value is now " << result << "\n"; | |
| } | |
| } | |
| inline void compareIntRVIntCVToR() noexcept | |
| { | |
| const auto& idxDst(params[0].get<Register::Idx>()); | |
| const auto& idxA(params[1].get<Register::Idx>()); | |
| const auto& valA(registry.get(idxA).value.template get<int>()); | |
| const auto& valB(params[2].get<int>()); | |
| const auto& result(VMOperations::getIntComparison(valA, valB)); | |
| registry.get(idxDst).value = result; | |
| if(TDebug) | |
| { | |
| ssvu::lo("compareIntRVIntCVToR") << "Comparing register value " << valA << " with constant int " << valB << " into register " << idxDst << "\n"; | |
| ssvu::lo("compareIntRVIntCVToR") << "Register value is now " << result << "\n"; | |
| } | |
| } | |
| inline void compareIntSVIntCVToR() noexcept | |
| { | |
| const auto& idxDst(params[0].get<Register::Idx>()); | |
| const auto& valA(stack.getTop()); | |
| const auto& valB(params[1].get<int>()); | |
| const auto& result(VMOperations::getIntComparison(valA, valB)); | |
| registry.get(idxDst).value = result; | |
| if(TDebug) | |
| { | |
| ssvu::lo("compareIntSVIntCVToR") << "Comparing stack value " << valA << " with constant int " << valB << " into register " << idxDst << "\n"; | |
| ssvu::lo("compareIntSVIntCVToR") << "Register value is now " << result << "\n"; | |
| } | |
| } | |
| // Execution impl | |
| inline void fetch() noexcept | |
| { | |
| if(TDebug) ssvu::lo("fetch") << "Fetching instruction at " << programCounter << "\n"; | |
| programInstruction = program[programCounter++]; | |
| } | |
| inline void decode() noexcept | |
| { | |
| if(TDebug) ssvu::lo("decode") << "Decoding instruction: OPCODE(" << int(programInstruction.opCode) << ")" << "\n"; | |
| fnPtr = getVMFnPtr<VMImpl>(programInstruction.opCode); params = programInstruction.params; | |
| } | |
| inline void eval() noexcept { (this->*fnPtr)(); } | |
| // Execution interface | |
| inline void run() noexcept | |
| { | |
| running = true; | |
| while(running) | |
| { | |
| fetch(); decode(); eval(); | |
| if(TDebug) | |
| { | |
| ssvu::lo() << "\n"; | |
| ssvu::lo("run()") << "Printing VM state...\n\n"; | |
| const auto& st(stack.getStack()); | |
| for(int i{0}; i < int(std::max(st.size(), registry.getSize())); ++i) | |
| { | |
| std::size_t sIdx(st.size() - i - 1); | |
| ssvu::lo() << ((sIdx < st.size()) ? "\t|--------------------|" : "\t "); | |
| if(i < int(registry.getSize())) ssvu::lo() << "\t\tRegister " << i << ": " << registry.get(i).value; | |
| ssvu::lo() << "\n"; | |
| if(sIdx < st.size()) | |
| { | |
| ssvu::lo() << ((i == int(stack.getBaseOffset())) ? "--->\t" : "\t") << i << "(" << -(int(stack.getBaseOffset()) - i) << ")" << "\t" << st.at(sIdx) << "\n"; | |
| } | |
| if(sIdx == 0) ssvu::lo() << "\t|--------------------|\n"; | |
| } | |
| ssvu::lo() << std::endl; | |
| } | |
| } | |
| } | |
| inline void setProgram(Program mProgram) noexcept { program = std::move(mProgram); } | |
| template<typename T, typename TTpl, std::size_t TIdx, typename TArg> inline static void makeParamsTuple(TTpl& mTpl, const T& mArray) { std::get<TIdx>(mTpl) = mArray.getValues()[TIdx].template get<TArg>(); } | |
| template<typename T, typename TTpl, std::size_t TIdx, typename TArg1, typename TArg2, typename... TArgs> inline static void makeParamsTuple(TTpl& mTpl, const T& mArray) | |
| { | |
| makeParamsTuple<T, TIdx, TArg1>(mTpl, mArray); makeParamsTuple<T, TIdx + 1, TArg2, TArgs...>(mTpl, mArray); | |
| } | |
| struct AnyFunctionBase | |
| { | |
| inline virtual Value call(const Params& mParams) = 0; | |
| inline virtual ~AnyFunctionBase() { } | |
| }; | |
| template<typename TReturn, typename... TArgs> struct AnyFunction : public AnyFunctionBase | |
| { | |
| TReturn(*ptr)(TArgs...); | |
| inline AnyFunction(TReturn(*mPtr)(TArgs...)) : ptr{mPtr} { } | |
| inline Value call(const Params& mParams) override | |
| { | |
| std::tuple<TArgs...> paramsTuple; | |
| makeParamsTuple<Params, std::tuple<TArgs...>, 0, TArgs...>(paramsTuple, mParams); | |
| return ssvu::explode(*ptr, paramsTuple); | |
| } | |
| }; | |
| struct BoundFunction | |
| { | |
| Value::Type returnType; | |
| Value::Type paramTypes[Params::valueCount]; | |
| std::unique_ptr<AnyFunctionBase> function; | |
| }; | |
| template<typename T, std::size_t TIdx, typename TArg> inline static void bfArrayFillHelper(T& mArray) { mArray[TIdx] = Value::getType<TArg>(); } | |
| template<typename T, std::size_t TIdx, typename TArg1, typename TArg2, typename... TArgs> inline static void bfArrayFillHelper(T& mArray) | |
| { | |
| bfArrayFillHelper<T, TIdx, TArg1>(mArray); bfArrayFillHelper<T, TIdx + 1, TArg2, TArgs...>(mArray); | |
| } | |
| template<typename TReturn, typename... TArgs> inline BoundFunction bindCFunction(TReturn(*mCFunctionPtr)(TArgs...)) | |
| { | |
| BoundFunction boundFunction; | |
| boundFunction.returnType = Value::getType<TReturn>(); | |
| bfArrayFillHelper<decltype(boundFunction.paramTypes), 0, TArgs...>(boundFunction.paramTypes); | |
| boundFunction.function = std::unique_ptr<AnyFunctionBase>(new AnyFunction<TReturn, TArgs...>(mCFunctionPtr)); | |
| return boundFunction; | |
| } | |
| }; | |
| } | |
| class VirtualMachine : public Internal::VMImpl<6, true> { }; | |
| } | |
| namespace ssvu | |
| { | |
| template<> struct Stringifier<ssvvm::Value> | |
| { | |
| template<bool TFmt> inline static void impl(std::ostream& mStream, const ssvvm::Value& mValue) | |
| { | |
| if(mValue.getType() == ssvvm::Value::Type::Int) | |
| { | |
| Internal::printBold<TFmt>(mStream, "INT["); | |
| Internal::callStringifyImpl<TFmt>(mStream, mValue.get<int>()); | |
| } | |
| else if(mValue.getType() == ssvvm::Value::Type::Float) | |
| { | |
| Internal::printBold<TFmt>(mStream, "FLOAT["); | |
| Internal::callStringifyImpl<TFmt>(mStream, mValue.get<float>()); | |
| } | |
| else Internal::printBold<TFmt>(mStream, "NULL["); | |
| Internal::printBold<TFmt>(mStream, "]"); | |
| } | |
| }; | |
| } | |
| /* | |
| int main() | |
| { | |
| using IT = ssvvm::OpCode; | |
| ssvvm::VirtualMachine vm; | |
| // 2.f * 15 | |
| vm.program += {IT::LoadFloatCVToR, 0, 2.f}; | |
| vm.program += {IT::LoadFloatCVToR, 2, 12.f}; | |
| vm.program += {IT::LoadIntCVToR, 1, 14}; | |
| vm.program += {IT::PushRVToS, 0}; | |
| vm.program += {IT::PushRVToS, 2}; | |
| vm.program += {IT::MultiplyFloat2SVs}; | |
| vm.program += {IT::PopSVToR, 0}; | |
| vm.program += {IT::PushRVToS, 0}; | |
| vm.program += {IT::PushRVToS, 2}; | |
| vm.program += {IT::AddFloat2SVs}; | |
| vm.program += {IT::PopSVToR, 0}; | |
| vm.program += {IT::DecrementIntRV, 1}; | |
| vm.program += {IT::GoToPIIfIntRV, 3, 1}; | |
| vm.run(); | |
| ssvu::lo() << vm.registry.getValue(0).get<float>() << "\n"; | |
| return 0; | |
| } | |
| */ | |
| std::string source{ | |
| R"( | |
| //!ssvasm | |
| $require_registers(4); | |
| $define(R0, 0); | |
| $define(R1, 1); | |
| $define(R2, 2); | |
| $define(ROutput, 3); | |
| // _______________________________ | |
| // FN_MAIN function | |
| // * entrypoint | |
| // * returns in ROutput | |
| // _______________________________ | |
| $label(FN_MAIN); | |
| // Compute the 10th fibonacci number | |
| // Load constants | |
| loadIntCVToR(R0, 10); | |
| // Save registers | |
| pushRVToS(R0); | |
| pushRVToS(R1); | |
| // Push args | |
| pushRVToS(R0); | |
| // Call func | |
| callPI(FN_FIB); | |
| // Get return value | |
| moveRVToR(ROutput, R0); | |
| // Pop args | |
| popSV(); | |
| // Restore registers | |
| popSVToR(R1); | |
| popSVToR(R0); | |
| // Push output to stack | |
| pushRVToS(ROutput); | |
| halt(); | |
| // _______________________________ | |
| // FN_FIB function | |
| // * needs 1 int argument | |
| // * uses R0, R1 | |
| // * returns in R0 | |
| // _______________________________ | |
| $label(FN_FIB); | |
| // Get arg from stack | |
| moveSBOVToR(R0, 2); | |
| // Check if arg is < 2 (put compare result in R1) | |
| compareIntRVIntCVToR(R1, R0, 2); | |
| // Return arg if arg < 2 | |
| goToPIIfCompareRVSmaller(FN_FIB_RET_ARG, R1); | |
| // Else return fib(arg - 1) + fib(arg - 2) | |
| // Calculate fib(arg - 1) | |
| // Save registers | |
| pushRVToS(R0); | |
| // Push args | |
| pushIntCVToS(1); | |
| pushRVToS(R0); | |
| subtractInt2SVs(); | |
| // Call func | |
| callPI(FN_FIB); | |
| // Get return value | |
| // Return value is in R0, move it to R2 | |
| moveRVToR(R2, R0); | |
| // Pop args | |
| popSV(); | |
| // Restore registers | |
| popSVToR(R0); | |
| // Push fib(arg - 1) on stack | |
| pushRVToS(R2); | |
| // Calculate fib(arg - 2) | |
| // Save registers | |
| pushRVToS(R0); | |
| // Push args | |
| pushIntCVToS(2); | |
| pushRVToS(R0); | |
| subtractInt2SVs(); | |
| // Call func | |
| callPI(FN_FIB); | |
| // Get return value | |
| // Return value is in R0, move it to R2 | |
| moveRVToR(R2, R0); | |
| // Pop args | |
| popSV(); | |
| // Restore registers | |
| popSVToR(R0); | |
| // Push fib(arg - 2) on stack | |
| pushRVToS(R2); | |
| // Return fib(arg - 1) + fib(arg + 1) | |
| addInt2SVs(); | |
| popSVToR(R0); | |
| returnPI(); | |
| $label(FN_FIB_RET_ARG); | |
| returnPI(); | |
| )"}; | |
| ssvvm::Program makeProgram(std::string mSource) | |
| { | |
| struct Tkn | |
| { | |
| std::string str; | |
| bool toDel{false}; | |
| Tkn(std::string mStr) : str(std::move(mStr)) { } | |
| }; | |
| auto expectTkns = [](std::vector<Tkn>& mTkns, std::size_t mIdxStart, const std::vector<std::string>& mExpect) -> bool | |
| { | |
| if(mIdxStart + mExpect.size() >= mTkns.size()) return false; | |
| std::size_t ei{0u}; | |
| for(auto i(mIdxStart); i < mIdxStart + mExpect.size(); ++i) | |
| { | |
| if(mExpect[ei] != "?" && mTkns[i].str != mExpect[ei]) return false; | |
| ++ei; | |
| } | |
| return true; | |
| }; | |
| auto delTkns = [](std::vector<Tkn>& mTkns, std::size_t mIdxStart, const std::vector<std::string>& mExpect) | |
| { | |
| if(mIdxStart + mExpect.size() >= mTkns.size()) return; | |
| std::size_t ei{0u}; | |
| for(auto i(mIdxStart); i < mIdxStart + mExpect.size(); ++i) | |
| { | |
| if(mExpect[ei] == "?" || mTkns[i].str == mExpect[ei]) mTkns[i].toDel = true; | |
| ++ei; | |
| } | |
| }; | |
| std::vector<std::string> lineByLine; | |
| ssvu::split(lineByLine, mSource, "\n"); | |
| // Get rid of comments | |
| for(auto& l : lineByLine) | |
| { | |
| std::size_t commentPos; | |
| while((commentPos = l.find("//")) != std::string::npos) l.erase(commentPos, l.size() - commentPos); | |
| } | |
| mSource = ""; for(auto& s : lineByLine) mSource += s; | |
| // Tokenize | |
| std::vector<std::string> splits{"\n", "\t", " "}, splitsKeep{"(", ")", ";", ","}; | |
| std::vector<Tkn> tokens; | |
| for(const auto& x : ssvu::getSplit<ssvu::Split::Normal>(mSource, splits)) tokens.emplace_back(x); | |
| mSource = ""; for(auto& s : tokens) mSource += s.str; tokens.clear(); | |
| for(const auto& x : ssvu::getSplit<ssvu::Split::KeepSeparatorAsToken>(mSource, splitsKeep)) tokens.emplace_back(x); | |
| //for(auto& s : tokens) ssvu::lo()<<s.c_str()<<std::endl; | |
| // Preprocess stage 1: $require directives | |
| int requireRegisters{-1}; | |
| for(auto i(0u); i < tokens.size(); ++i) | |
| { | |
| if(expectTkns(tokens, i, {"$require_registers", "(", "?", ")", ";"})) | |
| { | |
| requireRegisters = std::atoi(tokens[i + 2].str.c_str()); | |
| delTkns(tokens, i, {"$require_registers", "(", "?", ")", ";"}); | |
| } | |
| } | |
| ssvu::eraseRemoveIf(tokens, [](const Tkn& mTkn){ return mTkn.toDel; }); | |
| // Preprocess stage2: $define directives | |
| std::map<std::string, std::string> defines; | |
| //for(auto& s : tokens) ssvu::lo()<<s.str.c_str()<<std::endl; | |
| for(auto i(0u); i < tokens.size(); ++i) | |
| { | |
| if(expectTkns(tokens, i, {"$define", "(", "?", ",", "?", ")", ";"})) | |
| { | |
| std::string alias{tokens[i + 2].str}; | |
| if(defines.count(alias) > 0) throw; | |
| defines[alias] = tokens[i + 4].str; | |
| delTkns(tokens, i, {"$define", "(", "?", ",", "?", ")", ";"}); | |
| } | |
| } | |
| ssvu::eraseRemoveIf(tokens, [](const Tkn& mTkn){ return mTkn.toDel; }); | |
| for(auto& t : tokens) if(defines.count(t.str) > 0) t.str = defines[t.str]; | |
| //for(auto& s : tokens) ssvu::lo()<<s.str.c_str()<<std::endl; | |
| struct Instr | |
| { | |
| std::string idnf{"NULL"}; | |
| std::vector<std::string> args; | |
| }; | |
| std::vector<Instr> instructions; | |
| Instr currentInstr; | |
| std::size_t tknIdx{0u}; | |
| while(tknIdx < tokens.size()) | |
| { | |
| currentInstr.idnf = tokens[tknIdx].str; | |
| ++tknIdx; | |
| if(tokens[tknIdx].str == "(") | |
| { | |
| if(tokens[tknIdx + 1].str == ")" && tokens[tknIdx + 2].str == ";") | |
| { | |
| instructions.push_back(currentInstr); currentInstr = Instr{}; | |
| tknIdx = tknIdx + 3; continue; | |
| } | |
| ++tknIdx; | |
| while(tokens[tknIdx].str != ";") | |
| { | |
| currentInstr.args.push_back(ssvu::getReplaced(tokens[tknIdx].str, ".f", "")); | |
| tknIdx += 2; | |
| } | |
| ++tknIdx; | |
| instructions.push_back(currentInstr); currentInstr = Instr{}; | |
| } | |
| } | |
| //for(auto& s : instructions) ssvu::lo() << s.idnf << " " << s.args << "\n"; | |
| std::map<std::string, std::string> labelIdxs; | |
| bool found{true}; | |
| while(found) | |
| { | |
| found = false; | |
| for(auto i(0u); i < instructions.size(); ++i) | |
| { | |
| if(instructions[i].idnf == "$label") | |
| { | |
| found = true; | |
| labelIdxs[instructions[i].args[0]] = ssvu::toStr(i); | |
| instructions.erase(std::begin(instructions) + i); | |
| break; | |
| } | |
| } | |
| } | |
| for(auto& kk : labelIdxs) for(auto& i : instructions) for(auto& arg : i.args) if(arg == kk.first) arg = kk.second; | |
| //for(auto& s : instructions) ssvu::lo() << s.idnf << " " << s.args << "\n"; | |
| ssvvm::Program result; | |
| int idx{0}; | |
| for(auto& s : instructions) | |
| { | |
| ssvu::lo() << idx++ << ":\t" << s.idnf << " " << s.args << "\n"; | |
| if(s.idnf == "halt") { if(s.args.size() == 0) result += {ssvvm::OpCode::Halt}; else throw; } | |
| else if(s.idnf == "loadIntCVToR") { if(s.args.size() == 2) result += {ssvvm::OpCode::LoadIntCVToR, std::atoi(s.args[0].c_str()), std::atoi(s.args[1].c_str())}; else throw; } | |
| else if(s.idnf == "loadFloatCVToR") { if(s.args.size() == 2) result += {ssvvm::OpCode::LoadFloatCVToR, std::atoi(s.args[0].c_str()), (float)std::atof(s.args[1].c_str())}; else throw; } | |
| else if(s.idnf == "moveRVToR") { if(s.args.size() == 2) result += {ssvvm::OpCode::MoveRVToR, std::atoi(s.args[0].c_str()), std::atoi(s.args[1].c_str())}; else throw; } | |
| else if(s.idnf == "pushRVToS") { if(s.args.size() == 1) result += {ssvvm::OpCode::PushRVToS, std::atoi(s.args[0].c_str())}; else throw; } | |
| else if(s.idnf == "popSVToR") { if(s.args.size() == 1) result += {ssvvm::OpCode::PopSVToR, std::atoi(s.args[0].c_str())}; else throw; } | |
| else if(s.idnf == "moveSBOVToR") { if(s.args.size() == 2) result += {ssvvm::OpCode::MoveSBOVToR, std::atoi(s.args[0].c_str()), std::atoi(s.args[1].c_str())}; else throw; } | |
| else if(s.idnf == "pushIntCVToS") { if(s.args.size() == 1) result += {ssvvm::OpCode::PushIntCVToS, std::atoi(s.args[0].c_str())}; else throw; } | |
| else if(s.idnf == "pushFloatCVToS") { if(s.args.size() == 1) result += {ssvvm::OpCode::PushFloatCVToS, (float)std::atof(s.args[0].c_str())}; else throw; } | |
| else if(s.idnf == "pushSVToS") { if(s.args.size() == 0) result += {ssvvm::OpCode::PushSVToS}; else throw; } | |
| else if(s.idnf == "popSV") { if(s.args.size() == 0) result += {ssvvm::OpCode::PopSV}; else throw; } | |
| else if(s.idnf == "callPI") { if(s.args.size() == 1) result += {ssvvm::OpCode::CallPI, std::atoi(s.args[0].c_str())}; else throw; } | |
| else if(s.idnf == "returnPI") { if(s.args.size() == 0) result += {ssvvm::OpCode::ReturnPI}; else throw; } | |
| else if(s.idnf == "goToPI") { if(s.args.size() == 1) result += {ssvvm::OpCode::GoToPI, std::atoi(s.args[0].c_str())}; else throw; } | |
| else if(s.idnf == "goToPIIfIntRV") { if(s.args.size() == 2) result += {ssvvm::OpCode::GoToPIIfIntRV, std::atoi(s.args[0].c_str()), std::atoi(s.args[1].c_str())}; else throw; } | |
| else if(s.idnf == "goToPIIfCompareRVGreater") { if(s.args.size() == 2) result += {ssvvm::OpCode::GoToPIIfCompareRVGreater, std::atoi(s.args[0].c_str()), std::atoi(s.args[1].c_str())}; else throw; } | |
| else if(s.idnf == "goToPIIfCompareRVSmaller") { if(s.args.size() == 2) result += {ssvvm::OpCode::GoToPIIfCompareRVSmaller, std::atoi(s.args[0].c_str()), std::atoi(s.args[1].c_str())}; else throw; } | |
| else if(s.idnf == "goToPIIfCompareRVEqual") { if(s.args.size() == 2) result += {ssvvm::OpCode::GoToPIIfCompareRVEqual, std::atoi(s.args[0].c_str()), std::atoi(s.args[1].c_str())}; else throw; } | |
| else if(s.idnf == "incrementIntRV") { if(s.args.size() == 1) result += {ssvvm::OpCode::IncrementIntRV, std::atoi(s.args[0].c_str())}; else throw; } | |
| else if(s.idnf == "decrementIntRV") { if(s.args.size() == 1) result += {ssvvm::OpCode::DecrementIntRV, std::atoi(s.args[0].c_str())}; else throw; } | |
| else if(s.idnf == "addInt2SVs") { if(s.args.size() == 0) result += {ssvvm::OpCode::AddInt2SVs}; else throw; } | |
| else if(s.idnf == "addFloat2SVs") { if(s.args.size() == 0) result += {ssvvm::OpCode::AddFloat2SVs}; else throw; } | |
| else if(s.idnf == "subtractInt2SVs") { if(s.args.size() == 0) result += {ssvvm::OpCode::SubtractInt2SVs}; else throw; } | |
| else if(s.idnf == "subtractFloat2SVs") { if(s.args.size() == 0) result += {ssvvm::OpCode::SubtractFloat2SVs}; else throw; } | |
| else if(s.idnf == "multiplyInt2SVs") { if(s.args.size() == 0) result += {ssvvm::OpCode::MultiplyInt2SVs}; else throw; } | |
| else if(s.idnf == "multiplyFloat2SVs") { if(s.args.size() == 0) result += {ssvvm::OpCode::MultiplyFloat2SVs}; else throw; } | |
| else if(s.idnf == "divideInt2SVs") { if(s.args.size() == 0) result += {ssvvm::OpCode::DivideInt2SVs}; else throw; } | |
| else if(s.idnf == "divideFloat2SVs") { if(s.args.size() == 0) result += {ssvvm::OpCode::DivideFloat2SVs}; else throw; } | |
| else if(s.idnf == "compareIntRVIntRVToR") { if(s.args.size() == 3) result += {ssvvm::OpCode::CompareIntRVIntRVToR, std::atoi(s.args[0].c_str()), std::atoi(s.args[1].c_str()), std::atoi(s.args[2].c_str())}; else throw; } | |
| else if(s.idnf == "compareIntRVIntSVToR") { if(s.args.size() == 2) result += {ssvvm::OpCode::CompareIntRVIntSVToR, std::atoi(s.args[0].c_str()), std::atoi(s.args[1].c_str())}; else throw; } | |
| else if(s.idnf == "compareIntSVIntSVToR") { if(s.args.size() == 1) result += {ssvvm::OpCode::CompareIntSVIntSVToR, std::atoi(s.args[0].c_str())}; else throw; } | |
| else if(s.idnf == "compareIntRVIntCVToR") { if(s.args.size() == 3) result += {ssvvm::OpCode::CompareIntRVIntCVToR, std::atoi(s.args[0].c_str()), std::atoi(s.args[1].c_str()), std::atoi(s.args[2].c_str())}; else throw; } | |
| else if(s.idnf == "compareIntSVIntCVToR") { if(s.args.size() == 2) result += {ssvvm::OpCode::CompareIntSVIntCVToR, std::atoi(s.args[0].c_str()), std::atoi(s.args[1].c_str())}; else throw; } | |
| else throw; | |
| } | |
| return result; | |
| } | |
| int cfunc(int x) { return x * 2; } | |
| int main() | |
| { | |
| SSVU_TEST_RUN_ALL(); | |
| ssvvm::Program program{makeProgram(source)}; | |
| ssvvm::VirtualMachine vm; | |
| ssvvm::VirtualMachine::BoundFunction bf = vm.bindCFunction(&cfunc); | |
| ssvvm::Params callParams{21}; | |
| ssvvm::Value returnValue = bf.function->call(callParams); | |
| ssvu::lo() << returnValue << std::endl; | |
| return 0; | |
| vm.setProgram(program); | |
| vm.run(); | |
| //ssvu::lo() << vm.registry.getValue(0).get<float>() << "\n"; | |
| //ssvu::lo() << vm.registry.getValue(1).get<float>() << "\n"; | |
| return 0; | |
| } | |
| #endif | |
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment