Last active
November 28, 2017 00:56
-
-
Save maxtruxa/f0725a3a232661336c19 to your computer and use it in GitHub Desktop.
C++ BrainFuck Interpreter
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 <iostream> | |
#include <fstream> | |
#include <vector> | |
#include <Windows.h> // MessageBox | |
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) | |
{ | |
MessageBoxA(NULL, message, "Error", MB_OK | MB_ICONERROR); | |
} | |
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 1; | |
} | |
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 1; | |
} | |
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 1; | |
} | |
--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 1; | |
} | |
} | |
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 1; | |
} | |
} | |
break; | |
default: | |
// Unknown tokens are simply ignored. | |
break; | |
} | |
} | |
return *dp; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment