Need to clear my brain.
BF interpretor in C++.
bf.h
#include <vector>
class BF
{
std::vector<char> memory;
std::size_t dp;
template<typename I>
I findMatchingClose(I start);
public:
BF(std::size_t defaultMemorySize = 4096);
void reset() {dp = 0;}
template<typename I>
// Not sure how to specify that `I` is limited to allow random access.
// Suppose I could re-write to allow slips back and forward.
void run(I begin, I end);
};
bf.cpp
#include "bf.h"
#include <iostream>
BF::BF(std::size_t defaultMemorySize)
: memory(defaultMemorySize, 0)
, dp(0)
{}
template<typename I>
I BF::findMatchingClose(I loop)
{
std::size_t openCount = 1;
for (++loop; openCount != 0; ++loop) {
if (*loop == '[') {
++openCount;
}
else if (*loop == ']') {
--openCount;
}
}
return loop;
}
template<typename I>
void BF::run(I begin, I end)
{
/*
> Increment the data pointer by one (to point to the next cell to the right).
< Decrement the data pointer by one (to point to the next cell to the left).
+ Increment the byte at the data pointer by one.
- Decrement the byte at the data pointer by one.
. Output the byte at the data pointer.
, Accept one byte of input, storing its value in the byte at the data pointer.
[ If the byte at the data pointer is zero, then instead of moving the instruction pointer forward to the next command, jump it forward to the command after the matching ] command.
] If the byte at the data pointer is nonzero, then instead of moving the instruction pointer forward to the next command, jump it back to the command after the matching [ command.
*/
std::vector<I> stack;
for (I loop = begin; loop != end; ++loop) {
switch (*loop) {
case '>': dp = (dp + 1) % memory.size(); break;
case '<': dp = std::max(memory.size() -1, dp - 1); break;
case '+': ++memory[dp];break;
case '-': --memory[dp];break;
case '.': std::cout << memory[dp];break;
case ',': std::cin >> memory[dp];break;
case '[': if (memory[dp]) {
// Enter the loop.
// So remember where to jump back to.
stack.emplace_back(loop);
}
else {
// Ignore the loop.
// So find the end (the ++loop) will take
// us to the next instruction.
loop = findMatchingClose(loop);
}
case ']': if (memory[dp]) {
// Next loop iteration.
// Set loop to start of the inner most loop.
// Note ++loop will take us to the first instruction.
loop = stack.back();
}
else {
// Exit the inner most loop.
stack.pop_back();
}
break;
default:
continue;
}
}
}
main.cpp
#include "bf.h"
#include <iostream>
#include <fstream>
#include <iterator>
int main(int argc, char* argv[])
{
std::cout << (-11 % 10) << "\n";
if (argc <= 1) {
std::cerr << "No input file\n";
return -1;
}
BF bf;
for (int loop = 1; loop < argc; ++loop) {
std::ifstream file(argv[loop]);
std::string program(std::istream_iterator<char>{file}, std::istream_iterator<char>{});
bf.reset();
bf.run(std::begin(program), std::end(program));
}
}