Last active
December 30, 2021 18:46
-
-
Save shouth/ffdd120958f572fa3d9b03092275a400 to your computer and use it in GitHub Desktop.
This file contains 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
#include <array> | |
#include <cstddef> | |
#include <variant> | |
#include <utility> | |
#include <iostream> | |
namespace brainfuck { | |
enum class error_reason { | |
MISMATCHING_SQUARE_PARENTHESIS, | |
TRIED_TO_ACCESS_OUT_OF_INPUT_RANGE, | |
TRIED_TO_ACCESS_OUT_OF_CELLS_RANGE, | |
OUTPUT_CAPACITY_IS_TOO_SMALL, | |
}; | |
template<size_t Capacity> | |
using buffer = std::pair<std::array<uint8_t, Capacity>, size_t>; | |
template<typename T = void> | |
static constexpr bool false_v = false; | |
template< | |
const char * const &InputPtr, | |
const char * const &ProgramPtr, | |
size_t MemorySize = 32768, | |
size_t OutputCapacity = 32768> | |
struct interpreter { | |
static constexpr inline auto result = []() -> std::variant<buffer<OutputCapacity>, error_reason> { | |
size_t cnt = 0; | |
for (size_t i = 0; ProgramPtr[i]; i++) { | |
switch (ProgramPtr[i]) { | |
case '[': | |
cnt++; | |
break; | |
case ']': | |
cnt--; | |
break; | |
} | |
} | |
if (cnt != 0) { | |
return error_reason::MISMATCHING_SQUARE_PARENTHESIS; | |
} | |
std::array<uint8_t, MemorySize> cells = { }; | |
std::array<uint8_t, OutputCapacity> output = { }; | |
auto data = cells.begin(); | |
auto out = output.begin(); | |
auto in = InputPtr; | |
auto command = ProgramPtr; | |
while (*command) { | |
switch (*command) { | |
case '>': | |
data++; | |
if (data == cells.end()) { | |
return error_reason::TRIED_TO_ACCESS_OUT_OF_CELLS_RANGE; | |
} | |
break; | |
case '<': | |
if (data == cells.begin()) { | |
return error_reason::TRIED_TO_ACCESS_OUT_OF_CELLS_RANGE; | |
} | |
data--; | |
break; | |
case '+': | |
(*data)++; | |
break; | |
case '-': | |
(*data)--; | |
break; | |
case '.': | |
if (out == output.end()) { | |
return error_reason::OUTPUT_CAPACITY_IS_TOO_SMALL; | |
} | |
*out++ = *data; | |
break; | |
case ',': | |
if (in > InputPtr && in[-1] == '\0') { | |
return error_reason::TRIED_TO_ACCESS_OUT_OF_INPUT_RANGE; | |
} | |
*data = *in++; | |
break; | |
case '[': | |
if (*data == 0) { | |
cnt = 0; | |
while (cnt > 0 || *command != ']') { | |
if (*command == ']') cnt--; | |
command++; | |
if (*command == '[') cnt++; | |
} | |
} | |
break; | |
case ']': | |
if (*data != 0) { | |
cnt = 0; | |
while (cnt > 0 || *command != '[') { | |
if (*command == '[') cnt--; | |
command--; | |
if (*command == ']') cnt++; | |
} | |
} | |
break; | |
} | |
command++; | |
} | |
return buffer<OutputCapacity> { output, out - output.begin() }; | |
}(); | |
static constexpr inline auto output = [] { | |
if constexpr (result.index() == 0) { | |
constexpr auto buf = std::get<0>(result); | |
std::array<uint8_t, buf.second> ret = { }; | |
for (size_t i = 0; i < buf.second; i++) { | |
ret[i] = buf.first[i]; | |
} | |
return ret; | |
} else { | |
constexpr auto error = std::get<1>(result); | |
if constexpr (error == error_reason::MISMATCHING_SQUARE_PARENTHESIS) { | |
static_assert(false_v<>, "mismatching square parenthesis"); | |
} else if constexpr (error == error_reason::TRIED_TO_ACCESS_OUT_OF_INPUT_RANGE) { | |
static_assert(false_v<>, "tried to access out of input range"); | |
} else if constexpr (error == error_reason::TRIED_TO_ACCESS_OUT_OF_CELLS_RANGE) { | |
static_assert(false_v<>, "tried to access out of memory range"); | |
} else if constexpr (error == error_reason::OUTPUT_CAPACITY_IS_TOO_SMALL) { | |
static_assert(false_v<>, "output capacity is too small"); | |
} else { | |
static_assert(false_v<>, "unhandled error!"); | |
} | |
} | |
}(); | |
}; | |
} | |
constexpr const char *input = ""; | |
constexpr const char *program = R"( | |
++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+. | |
)"; | |
int main() | |
{ | |
constexpr auto output = brainfuck::interpreter<input, program>::output; | |
for (auto &e : output) std::cout << (char) e; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment