Created
February 6, 2022 09:54
-
-
Save inxanedev/711871b805aed0c16d639452f8d6e1bf to your computer and use it in GitHub Desktop.
Brainfuck intepreter in C++
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 <vector> | |
#include <iostream> | |
#include <string> | |
#include <fstream> | |
#include <unordered_map> | |
class Interpreter { | |
public: | |
using SourceType = std::vector<char>; | |
template <typename T> | |
class Memory { | |
public: | |
Memory() { | |
memory.push_back(0); | |
} | |
size_t left() { | |
if (index != 0) index--; | |
return index; | |
} | |
size_t right() { | |
if (index + 1 >= memory.size()) { | |
memory.push_back(0); | |
} | |
return ++index; | |
} | |
T increment() { | |
return ++memory[index]; | |
} | |
T decrement() { | |
return --memory[index]; | |
} | |
T get() { | |
return memory[index]; | |
} | |
T set(T value) { | |
return (memory[index] = value); | |
} | |
private: | |
std::vector<T> memory; | |
size_t index = 0; | |
}; | |
public: | |
static SourceType read_source(const std::string& filename) { | |
SourceType source; | |
std::ifstream file(filename); | |
char c; | |
while (file.get(c)) { | |
source.push_back(c); | |
} | |
return source; | |
} | |
public: | |
Interpreter() = delete; | |
Interpreter(const std::string& filename) | |
: source(Interpreter::read_source(filename)) {} | |
Interpreter(SourceType&& source) | |
: source(std::move(source)) {} | |
Interpreter(const SourceType& source) | |
: source(source) {} | |
public: | |
void execute() { | |
Memory<uint32_t> memory; | |
std::unordered_map<size_t, size_t> loops; | |
size_t index = 0; | |
while (index < source.size()) { | |
char c = source[index]; | |
if (c == '>') memory.right(); | |
else if (c == '<') memory.left(); | |
else if (c == '+') memory.increment(); | |
else if (c == '-') memory.decrement(); | |
else if (c == ',') { | |
char input; | |
std::cin >> input; | |
memory.set(static_cast<uint32_t>(input)); | |
} | |
else if (c == '.') | |
std::cout << static_cast<char>(memory.get()); | |
else if (c == '[') { | |
if (memory.get() == 0) | |
index = get_matching_brace(index); | |
else | |
loops[get_matching_brace(index)] = index; | |
} | |
else if (c == ']') { | |
if (memory.get() != 0) | |
index = loops[index]; | |
} | |
index++; | |
} | |
} | |
size_t get_matching_brace(size_t first) { | |
size_t count = first; | |
uint32_t nest_counter = 0; | |
while (count < source.size()) { | |
char c = source[++count]; | |
if (c == '[') nest_counter++; | |
else if (c == ']') { | |
if (nest_counter == 0) { | |
return count; | |
} | |
else nest_counter--; | |
} | |
} | |
std::cerr << "cant find matching brace\n"; | |
std::exit(-1); | |
} | |
private: | |
const SourceType source; | |
}; | |
int main(int argc, char* argv[]) { | |
if (argc < 2) { | |
std::cout << "Usage: " << argv[0] << " filename.bf\n"; | |
return -1; | |
} | |
Interpreter interpreter(argv[1]); | |
interpreter.execute(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment