229 lines
4.5 KiB
C++
229 lines
4.5 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,
|
|
JumpTo,
|
|
Print,
|
|
|
|
// Registry
|
|
StoreValueIn,
|
|
PutValueIn,
|
|
SetValueIn, // Three Argumens!!
|
|
|
|
// Type
|
|
W,
|
|
X,
|
|
Y,
|
|
Z,
|
|
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;
|
|
int selectedRegistry = 0;
|
|
std::array<int, maxCells> 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 SetValueIn:
|
|
if (selectedRegistry == 0) {
|
|
selectedRegistry = command;
|
|
return;
|
|
}
|
|
whichRegistry(selectedRegistry) = command;
|
|
selectedRegistry = 0;
|
|
break;
|
|
|
|
case Print:
|
|
handlePrint(command);
|
|
break;
|
|
|
|
default:
|
|
std::terminate();
|
|
return;
|
|
}
|
|
|
|
// This is only called after multi-argument functions are done
|
|
if (State != NoCommand && selectedRegistry == 0) {
|
|
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;
|
|
|
|
// Multi Argument Commands
|
|
case Print:
|
|
case JumpTo:
|
|
|
|
case StoreValueIn:
|
|
case PutValueIn:
|
|
case SetValueIn:
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
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<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
|