5
\$\begingroup\$

Generic Headers

#include <vector>
#include <string>
#include <iostream>
#include <fstream>
typedef std::string const BFProgram;

BF Interpreter

class BFInterpretor
{
 static const std::size_t MemorySize = 10000;
 std::vector<char> memory;
 std::vector<std::size_t> openLoops;
 BFProgram& program;
 std::istream& input;
 std::ostream& output;
 std::size_t dataPointer;
 std::size_t progPointer;
 std::size_t scanToEndOfLoop()
 {
 std::size_t nestedLoops = 1;
 std::size_t scanPos = progPointer;
 for(;nestedLoops != 0;++scanPos)
 {
 switch(program[scanPos])
 {
 case '[': ++nestedLoops; break;
 case ']': --nestedLoops; break;
 default: break;
 }
 }
 return scanPos;
 }
 public:
 BFInterpretor(BFProgram& program, std::istream& input = std::cin, std::ostream& output = std::cout)
 : memory(MemorySize)
 , program(program)
 , input(input)
 , output(output)
 , dataPointer(0)
 , progPointer(0)
 {}
 static bool bfComment(char c)
 {
 switch(c)
 {
 case '>': case '<': case '.': case ',': case '+': case '-': case '[': case ']':
 return false;
 default:
 break;
 }
 return true;
 }
 void run()
 {
 while(progPointer < program.size())
 {
 ++progPointer;
 switch(program[progPointer - 1])
 {
 case '>': dataPointer = (dataPointer + 1) % MemorySize;break;
 case '<': dataPointer = (dataPointer - 1) % MemorySize;break;
 case '+': ++(memory[dataPointer]); break;
 case '-': --(memory[dataPointer]); break;
 case '.': output.put(memory[dataPointer]); break;
 case ',': memory[dataPointer] = input.get(); break;
 case '[': if (memory[dataPointer]) {
 openLoops.push_back(progPointer);
 }
 else {
 progPointer = scanToEndOfLoop();
 }
 break;
 case ']': if (memory[dataPointer]) {
 progPointer = openLoops.back();
 }
 else {
 openLoops.pop_back();
 }
 break;
 default: break; /* Ignore all comments */
 }
 }
 }
};

Program Loader

BFProgram loadProgram(std::istream& program)
{
 std::string programText;
 std::string line;
 while(std::getline(program, line))
 {
 line.erase(std::remove_if(std::begin(line), std::end(line), [](char c){return BFInterpretor::bfComment(c);}), std::end(line));
 programText.append(line);
 }
 return programText;
}
BFProgram loadProgram(std::string const& file)
{
 if (file == "-") {
 return loadProgram(std::cin);
 }
 std::ifstream program(file);
 return loadProgram(program);
}

Main

int main(int argc, char* argv[])
{
 std::vector<std::string> args(argv+1 , argv+argc);
 if (args.empty()) {
 args.push_back("-");
 }
 for(std::string const& file: args) {
 std::string program = loadProgram(file);
 BFInterpretor interpretor(program);
 interpretor.run();
 }
}
asked Mar 18, 2015 at 19:42
\$\endgroup\$
1
  • \$\begingroup\$ Too little to add for a full answer: 1. Are you sure storing a reference to the program instead of a copy ofit is a good idea? Hope noone ever passes an xvalue there. 2. Consider wrapping your lines a little earlier, horizontal scrolling is deadly. \$\endgroup\$ Commented Mar 19, 2015 at 0:07

2 Answers 2

2
\$\begingroup\$
  • Make MemorySize a parameter of the interpreter, or even better make the memory array dynamically adjust its size to the contents.
  • Missing the <algorithm> header for using std::remove_if.
  • Redundant use of lambda [](char c){return BFInterpretor::bfComment(c);}: simple BFInterpretor::bfComment as a predicate would do.
  • I would also declare BFInterpretor's constructor explicit to avoid unnecessary type conversion.
  • For my taste, a bit fishy use of magic "-" literal to treat the special case of std::cin, I would rather store istream-provider functions there.
answered Mar 18, 2015 at 22:45
\$\endgroup\$
1
  • \$\begingroup\$ You get the tick for spotting the bad usage of lambda (which I think was a terrible mistake on my side). Also liked the concept of MemorySize as a parameter \$\endgroup\$ Commented Mar 22, 2015 at 0:59
4
\$\begingroup\$
  • An malformed program (with misbalanced brackets) may cause an UB (e.g. popping back from an empty vector; or running out of program space in scanToEndOfLoops).

  • I recommend implementing step method:

    void run() {
     while (progPointer < program.size()) {
     step();
     }
    }
    

    with an intention to reuse it in a debugger.

answered Mar 18, 2015 at 20:20
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.