Skip to content

Instantly share code, notes, and snippets.

@shouth
Last active December 30, 2021 18:46
Show Gist options
  • Save shouth/ffdd120958f572fa3d9b03092275a400 to your computer and use it in GitHub Desktop.
Save shouth/ffdd120958f572fa3d9b03092275a400 to your computer and use it in GitHub Desktop.
#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