Skip to content

Instantly share code, notes, and snippets.

@mervick
Forked from maxtruxa/BrainFuck.cpp
Last active November 28, 2017 01:53
Show Gist options
  • Select an option

  • Save mervick/3a831985e5879d1ca68cfee4eac2ebe9 to your computer and use it in GitHub Desktop.

Select an option

Save mervick/3a831985e5879d1ca68cfee4eac2ebe9 to your computer and use it in GitHub Desktop.
C++ BrainFuck Interpreter
#include <iostream>
#include <fstream>
#include <vector>
size_t const DATA_SIZE_START = 0x0000400; // 1 KiB
size_t const DATA_SIZE_MAX = 0x1000000; // 16 MiB
enum token_t : char {
NextField = '>',
PreviousField = '<',
IncrementField = '+',
DecrementField = '-',
Output = '.',
Input = ',',
LoopBegin = '[',
LoopEnd = ']'
};
void DisplayError(char const* message)
{
std::cout << message << std::endl;
}
int main(int argc, char const* argv[])
{
if (argc != 2) {
DisplayError("No input file supplied.");
return 1;
}
std::string inputFileName = argv[1];
std::vector<char> contents;
// Extra scope so that ifs will be destructed after being read.
{
std::ifstream ifs;
std::istreambuf_iterator<char> begin;
if (inputFileName.compare("-") == 0) {
begin = std::cin;
}
else {
ifs.open(inputFileName);
if (!ifs) {
DisplayError("Unable to open input file.");
return 2;
}
begin = ifs;
}
contents = std::vector<char>(begin, std::istreambuf_iterator<char>());
}
std::vector<char> data(DATA_SIZE_START);
auto dp = data.begin();
for (auto ip = contents.cbegin(); ip != contents.cend(); ++ip) {
switch (*ip) {
case NextField:
if (dp == data.end()) {
if (data.size() == DATA_SIZE_MAX) {
DisplayError("STACK_OVERFLOW");
return 3;
}
data.resize(std::min(data.size() * 2, DATA_SIZE_MAX));
dp = data.begin();
}
++dp;
break;
case PreviousField:
if (dp == data.begin()) {
DisplayError("ACCESS_VIOLATION");
return 4;
}
--dp;
break;
case IncrementField:
++(*dp);
break;
case DecrementField:
--(*dp);
break;
case Output:
putchar(*dp);
break;
case Input:
*dp = getchar();
break;
case LoopBegin:
if (*dp == 0) {
size_t level = 1;
for (++ip; ip != contents.cend() && level > 0; ++ip) {
switch (*ip) {
case LoopBegin: ++level; break;
case LoopEnd: --level; break;
}
}
if (level > 0) {
DisplayError("INVALID_LOOP");
return 5;
}
}
break;
case LoopEnd:
if (*dp != 0) {
size_t level = 1;
for (--ip; ip != contents.cbegin() && level > 0; --ip) {
switch (*ip) {
case LoopBegin: --level; break;
case LoopEnd: ++level; break;
}
}
if (level > 0) {
DisplayError("INVALID_LOOP");
return 6;
}
}
break;
default:
// Unknown tokens are simply ignored.
break;
}
}
return *dp;
}
@mervick
Copy link
Copy Markdown
Author

mervick commented Nov 28, 2017

To compile this using gcc:

gcc brainfuck.cpp -lstdc++ -std=c++11 -o brainfuck

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment