Last active
December 29, 2016 07:05
-
-
Save dtoma/ce6a7dee19ba3206ab5dc0534273aac6 to your computer and use it in GitHub Desktop.
bf 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 <cstdio> | |
#include <functional> | |
#include <unordered_map> | |
#include <vector> | |
// Notes | |
// [some brainfuck fluff by daniel b cristofani](http://www.hevanet.com/cristofd/brainfuck/) | |
// [The Epistle to the Implementors](http://www.hevanet.com/cristofd/brainfuck/epistle.html) | |
// [The BrainFuck Compiler Collection](https://github.com/Sirflankalot/bfcc) | |
// TODO | |
// - [ ] Parser | |
// - [ ] Tests | |
// - [ ] Graphics | |
// - [ ] Fuzzing | |
// - [ ] Speed | |
namespace { | |
auto print_buffer(std::vector<int32_t> const& buffer, std::size_t data_ptr) { | |
printf("buffer: "); | |
for (auto const& e : buffer) { printf("%2i|", (int)e); } | |
printf("\n "); | |
printf("%*c\n", (int)(data_ptr * 3) + 2, '^'); | |
} | |
auto print_tape(std::string const& tape, std::size_t instr_ptr) { | |
printf("tape: "); | |
for (auto const& e : tape) { printf("%c", e); } | |
printf("\n "); | |
printf("%*c\n", (int)instr_ptr, '^'); | |
} | |
} | |
int main(int ac, char** av) { | |
if (ac < 3) { | |
fprintf(stderr, "usage:\n\t%s buffer_size<int> program<string>\n", av[0]); | |
return 1; | |
} | |
printf("BF interpreter running\n"); | |
std::string tape { av[2] }; | |
std::size_t instr_ptr = 0; | |
std::vector<int32_t> buffer(std::atoi(av[1])); | |
std::size_t data_ptr = 0; | |
std::unordered_map<char, std::function<void (void)>> commands = { | |
{ '>', [&data_ptr]() { data_ptr += 1; } }, | |
{ '<', [&data_ptr]() { data_ptr -= 1; } }, | |
{ '+', [&data_ptr, &buffer]() { buffer[data_ptr] += 1; } }, | |
{ '-', [&data_ptr, &buffer]() { buffer[data_ptr] -= 1; } }, | |
{ '.', [&data_ptr, &buffer]() { printf("%c", buffer[data_ptr]); } }, | |
{ ',', [&data_ptr, &buffer]() { buffer[data_ptr] = std::fgetc(stdin); } }, | |
{ '[', [&data_ptr, &buffer, &instr_ptr, tape]() { | |
if (buffer[data_ptr] != 0) { return; } | |
instr_ptr -= 1; | |
while (tape[instr_ptr] != ']') { instr_ptr += 1; } | |
} }, | |
{ ']', [&data_ptr, &buffer, &instr_ptr, tape]() { | |
if (buffer[data_ptr] == 0) { return; } | |
instr_ptr -= 1; | |
std::size_t closed_braces = 0; | |
while (tape[instr_ptr] != '[') { | |
instr_ptr -= 1; | |
// skip nested loops on the way back to the original '[' | |
if (tape[instr_ptr] == ']') { closed_braces += 1; } | |
if (tape[instr_ptr] == '[' && closed_braces != 0) { | |
closed_braces -= 1; instr_ptr -= 1; | |
} | |
} | |
} } | |
}; | |
auto end = tape.size(); | |
while (instr_ptr < end) { | |
auto instruction = tape[instr_ptr]; | |
instr_ptr += 1; | |
if (auto search = commands.find(instruction); search != std::end(commands)) { | |
search->second(); | |
} | |
// Uncomment to print the tape and buffer's status and step on enter | |
// print_buffer(buffer, data_ptr); | |
// print_tape(tape, instr_ptr); | |
// std::getc(stdin); | |
} | |
printf("\n"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Example run with debug uncommented: