-
-
Save mervick/3a831985e5879d1ca68cfee4eac2ebe9 to your computer and use it in GitHub Desktop.
C++ BrainFuck Interpreter
This file contains hidden or 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> | |
| 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; | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
To compile this using
gcc: