Files
variadic-machine/machine.hpp

178 lines
3.6 KiB
C++

/*
* SPDX-FileCopyrightText: Dora "cat" <cat@thenight.club>
* 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 <array>
#include <bitset>
#include <cstdarg>
#include <cstddef>
#include <exception>
#include <iomanip>
#include <iostream>
namespace VariadicMachine {
using Command = int;
enum : int {
// Single Argument
NoCommand,
MoveLeft,
MoveRight,
Increment,
Decrement,
// Two Arguments
IncrementBy,
DecrementBy,
MultiplyBy,
DivideBy,
ModulusBy,
SetTo,
Print,
// Type
AsDigit,
AsUnsignedDigit,
AsCharacter,
AsBinary,
AsHex,
};
template <std::size_t maxCells = 2048> class VMachine {
public:
template <typename... Commands> constexpr void Do(Commands &&...commands) {
(Execute(commands), ...);
}
private:
Command State = NoCommand;
std::array<int, maxCells> memory;
int W = 0, X = 0, Y = 0, Z = 0;
std::size_t currentPosition = 0;
void Execute(int command) {
switch (State) {
case NoCommand:
processCommand(command);
return;
// Arithmatic
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 Print:
handlePrint(command);
State = NoCommand;
return;
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 SetTo:
case IncrementBy:
case DecrementBy:
case MultiplyBy:
case DivideBy:
case ModulusBy:
State = static_cast<Command>(command);
return;
default:
std::cout << "Here\n";
std::terminate();
return;
}
}
void handlePrint(int Type) {
switch (Type) {
case AsDigit:
std::cout << memory[currentPosition];
return;
case AsUnsignedDigit:
std::cout << static_cast<unsigned int>(memory[currentPosition]);
return;
case AsCharacter:
std::wcout << static_cast<wchar_t>(memory[currentPosition]);
return;
case AsBinary:
std::cout << std::bitset<sizeof(int) * 8>(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