/* * SPDX-FileCopyrightText: Dora "cat" * SPDX-License-Identifier: MPL-2.0 * * This Source Code Form is subject to the terms of the Mozilla Public License, * v. 2.0. If a copy of the MPL was not distributed with this file, You can * obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef GUARD_VARIADICMACHINE_MACHINE_H #define GUARD_VARIADICMACHINE_MACHINE_H #include #include #include #include #include #include #include namespace VariadicMachine { using Command = int; enum : int { // Single Argument NoCommand, MoveLeft, MoveRight, Increment, Decrement, // Two Arguments IncrementBy, DecrementBy, MultiplyBy, DivideBy, ModulusBy, SetTo, JumpTo, Print, StoreValueIn, PutValueIn, // Type W, X, Y, Z, AsDigit, AsUnsignedDigit, AsCharacter, AsBinary, AsHex, }; template class VMachine { public: template constexpr void Do(Commands &&...commands) { (Execute(commands), ...); } private: Command State = NoCommand; std::array memory; int RW = 0, RX = 0, RY = 0, RZ = 0; std::size_t currentPosition = 0; void Execute(int command) { switch (State) { case NoCommand: processCommand(command); return; // Arithmetic case SetTo: memory[currentPosition] = command; break; case IncrementBy: memory[currentPosition] += command; break; case DecrementBy: memory[currentPosition] -= command; break; case MultiplyBy: memory[currentPosition] *= command; break; case DivideBy: memory[currentPosition] /= command; break; case ModulusBy: memory[currentPosition] %= command; break; case JumpTo: currentPosition = command; break; case StoreValueIn: whichRegistry(command) = memory[currentPosition]; break; case PutValueIn: memory[currentPosition] = whichRegistry(command); break; case Print: handlePrint(command); break; default: std::terminate(); return; } // This is only called after multi-argument functions are done if (State != NoCommand) { State = NoCommand; return; } } void processCommand(int command) { switch (command) { case MoveLeft: // Underflow wrap if (--currentPosition > maxCells) { currentPosition = maxCells; } return; case MoveRight: // Overflow wrap if (++currentPosition > maxCells) { currentPosition = 0; } return; case Increment: ++memory[currentPosition]; return; case Decrement: --memory[currentPosition]; return; // Double Argument Commands case Print: case JumpTo: case SetTo: case StoreValueIn: case PutValueIn: case IncrementBy: case DecrementBy: case MultiplyBy: case DivideBy: case ModulusBy: State = static_cast(command); return; default: std::cout << "Here\n"; std::terminate(); return; } } int &whichRegistry(int Type) { switch (Type) { case W: return RW; case X: return RX; case Y: return RY; case Z: return RZ; default: std::terminate(); } } void handlePrint(int Type) { switch (Type) { case AsDigit: std::cout << memory[currentPosition]; return; case AsUnsignedDigit: std::cout << static_cast(memory[currentPosition]); return; case AsCharacter: std::wcout << static_cast(memory[currentPosition]); return; case AsBinary: std::cout << std::bitset(memory[currentPosition]); return; // Ugh hate this, I really should use C++23 case AsHex: std::cout << "0x" << std::setfill('0') << std::setw(sizeof(int)) << std::hex << memory[currentPosition]; // Stupid reset because cout is a dumb dumb thing std::cout << std::dec << std::setfill(' ') << std::setw(0); return; default: std::terminate(); return; } } }; } // namespace VariadicMachine #endif