4

I am trying to write a brainfuck interpreter but I am missing some context or something. The function that is supposed to be called to handle the conversion of "+><>" etc is supposed to be:

std::vector<int> Interpreter::interpret(const std::string &src_,
    const std::vector<int> & input_)

A test of the program is as follows:

    int main()
{
std::vector<int> res;
// output: 1
res = interpret("+.");
for (auto i : res)
std::cout << i << " ";
2
// output: 2
res = interpret(",.", {2});
for (auto i : res)
std::cout << i << " ";
return 0;
}

http://www.muppetlabs.com/~breadbox/bf/

I really don't get what this is doing. I have seen other videos but it just doesn't make sense. Can someone explain the objective?

What is the point of the 30000 byte array if the function is given an array to translate?

Edit: I am supposed to write C++ code that will translate the characters the characters for the commands of brainfuck and they are supposed to do the corresponding commands on some array of 30000 bytes and some how that means something.

Edit: Provided instructions

Abstract Write a simple interpreter for Brainfk. 1 Introduction

A Brainfk program has an implicit byte pointer, called the pointer, which is free to move around within an array of 30000 bytes, initially all set to zero. The pointer itself is initialized to point to the beginning of this array. The Brainfuck programming language consists of eight commands, each of which is represented as a single character.

> Increment the pointer.
< Decrement the pointer.
+ Increment the byte at the pointer.
- Decrement the byte at the pointer.
. A dot, output the byte at the pointer.
, A comma, input a byte and store it in the byte at the pointer.
[ Jump forward past the matching ] IF the byte at the pointer is zero.
] Jump backward to the matching [ UNLESS the byte at the pointer is zero.

For example, one version of the "Hello, World!" program in Brainfk is

++++++++++[>+++++++>++++++++++>+++>+<<<<-]
>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.
+++.------.--------.>+.>.

2 Requirement

2.1 Test Program
I will use program to test and grade your code in batch. So please double check your function signature. Failure to run properly may impact your project grade. The entry function will all have the name interpret. And you may implement as many other helper functions as you want. The following sections elaborate on the specifications.

2.1.1 C++ I would use C++11 (g++ -std=c++11 ...) to test your program. So feel free to employ some of the recent goodies added to C++, e.g., lambda function, array initialization, etc. For convenience, please separate your declaration and implementation code in bf.h and bf.cpp. The function signature is std::vector<int> interpret(const std::string &src, const std::vector<int> &input = {});

My test program would look like

int main()  
{  
std::vector<int> res;  
// output: 1  
res = interpret("+.");  
for (auto i : res)  
    std::cout << i << " ";  

// output: 2  
res = interpret(",.", {2});  
for (auto i : res)  
    std::cout << i << " ";  
return 0;  
}  

Edit: What I have so far:

BFK.h

#pragma once
#include <vector>
#include <iostream>

using namespace std;


char arr[30000];
char* p = arr;

void incPtr();

void decPtr();

void incByte();

void decByte();

void printByte();

void setByte();

void jumpF();

void jumpB();

std::vector<int> interpret(const std::string &src,
    const std::vector<int> & input = {});

BFK.cpp

#include "BFK.h"

void incPtr() {
    p++;
}

void decPtr() {
    p--;
}

void incByte() {
    (*p)++;
}

void decByte() {
    (*p)--;
}

void printByte() {
    std::cout << *p;
}

void setByte() {
    std::cin >> *p;
}

void jumpF() {
    if (*p == 0) {

    }
}

void jumpB() {

}


std::vector<int> interpret(const std::string &src_,
    const std::vector<int> & input_){
    int i = 0;
    int max = src_.size();
    while (i < max) {
        switch (src_[i]) {
        case '>':
            incPtr();
            break;
        case '<':
            decPtr();
            break;
        case '+':
            incByte();
            break;
        case '-':
            decByte();
            break;
        case '.':
            printByte();
            break;
        case ',':
            setByte();
            break;
        case '[':
            jumpF();
            break;
        case ']':
            jumpB();
            break;
        }
    }

    return input_;
}

You are supposed to be able to call interpret without instantiating anything so I didn't know of another way to put this together. I have yet to implement the jump functions.

Zoe
  • 27,060
  • 21
  • 118
  • 148
user3577756
  • 643
  • 1
  • 9
  • 13
  • 1
    It's not really clear which parts you have written, and what you're confused about. I don't know why you have chosen to return a new vector after running `interpret`. Surely that vector represents memory (and should be `char` values, not `int`) and any changes to it would modify the original. You need to show us the actual output and the expected output. And maybe your `interpret` function. – paddy Nov 30 '15 at 05:16
  • @paddy The output as how I understand it is supposed to be in normal english characters. So in goes ++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++. and out comes "Hello world" – user3577756 Nov 30 '15 at 05:32
  • 1
    Show us the body of your `interpret()`. Did you write anything so far? – CinCout Nov 30 '15 at 05:37
  • 1
    @paddy: I think that the `vector` argument is the available inputs, so when the `,` needs to read a value, it comes from that vector. Analogously, the return `vector` is the output from the `.` operation. Hence the test program looping on the returned vector to print values. – Jonathan Leffler Nov 30 '15 at 05:38
  • @HappyCoder I have a little written but I am sure it is incorrect. I am not sure what the purpose of the 30000 array is or what to use it for. I am missing context on how all of this works together. Reading about doesn't seem to be helping either. – user3577756 Nov 30 '15 at 05:44
  • 1
    The 30,000 byte array is the BF program's memory; the `src` string is the BF program code which will act on the memory; the `input` vector is the supply of input values; and the returned vector is the set of output values. I'm not clear from the specification what should happen if you increment the current position past the last byte in the memory, or decrement it before the first byte, or try to read a value when there is no value to read. Such details are probably spelled out somewhere. – Jonathan Leffler Nov 30 '15 at 05:46
  • To begin with, you missed incrementing `i` in your `while` loop! – CinCout Nov 30 '15 at 05:50
  • @HappyCoder Thanks for the feedback. I will see what progress I can make with this but still not sure on how to build this. Do I need a class or just declare functions independently? – user3577756 Nov 30 '15 at 06:00
  • That depends on the way you want to implement it. Methods would suffice IMO. – CinCout Nov 30 '15 at 06:01
  • Have you read the Wikipedia article on BF? If not, you should probably do so. I did a Google search and found multiple useful references — but Wikipedia was pretty good. Amongst other things, it discusses some of the variations on what BF interpreters do with operations that increment or decrement the pointer out of bounds, and what happens on an attempt to read when there is nothing to read. – Jonathan Leffler Nov 30 '15 at 06:33
  • @JonathanLeffler I looked through it but I didn't understand it. I will try to go through it again tomorrow. Thanks for the feedback again. – user3577756 Nov 30 '15 at 06:35
  • Just some other thoughts in addition to the "not incrementing `i`", which is pretty important. You expose `p` and `arr` in the header, but they are locals. This shouldn't cause a problem, but they should really be in your source file. Even better, make this whole thing a class. You also never initialise the array, and you are not using the `input` and `output` vectors (instead you are using stdin and stdout -- was that intentional?) – paddy Nov 30 '15 at 21:02

1 Answers1

2

What is the point of the 30000 byte array if the function is given an array to translate?

Imagine that you get two numbers - 2 and 5 - and want your Brainfuck program to print their sum.

How do you do, when all you can do is manipulate the value in the current cell and "select" which cell is the current? Surely, you will need some temporary memory at some point.

In order to have two values in two separate cells, to prepare for the addition, this is what you could do:

,>,

If the user enters 2 and 3 (decimal, not ascii) then the first two bytes of the Brainfuck program memory, or tape, will look like this:

[2, 3, 0, 0, ...]
//  ^ This is where our tape pointer is now. We incremented it with `>`

Good enough, what about the addition now? A solution is to use a Brainfuck loop.

Let's add two natural integers without doing anything but incrementing and decrementing values:

int a = 2, b = 3

while (a != 0)
{
    b += 1
    a -= 1
}

Basically, we're decrementing the first value until it reaches zero, and as this is decreasing, we are incrementing the second value. Over time, this would show:

a = 2, b = 3
a = 1, b = 4
a = 0, b = 5
a == 0, break

So with that, we indeed get 2 + 3 = 5. This is simple enough to implement in brainfuck.

,  Get value for first cell (a)
>, Get value for second cell (b)
<  Move back to a
[  Loop until a == 0
    >+ Decrement b
    <- Increment a
    We are still at a at this point, so everything is alright
]  Loop again if a != 0
>. Print the final result (sum of a plus b)

... All this to demonstrate how you can use Brainfuck's tape memory to do actual things.

I believe that a lot of Brainfuck programs manipulate the tape as a stack. Funnily enough, you actually don't really need to know about techniques Brainfuck program employs to store temporarily values in an usable manner.

Let's see how the Brainfuck interpreter would roughly work with the above program, instruction by instruction.

* after a value in the stack means it's where the stack pointers aims now.

I'll group some of them as to not make this too long.

  1. , - tape[index] = input(), stack is now [2*, 0, 0, ...]
  2. > - index += 1, stack is now [2, 0*, 0, ...]
  3. , - tape[index] = input(), stack is now [2, 3*, 0, ...]
  4. < - index -= 1, stack is now [2*, 3, 0, ...]
  5. [ - if (tape[index] == 0) { skipToLoopEnd(); }, doesn't jump (2 == 0 is false), stack is left the same
  6. >+ - stack is now [2, 4*, 0, ...]
  7. <- - stack is now [1*, 4, 0, ...]
  8. ] - if (tape[index] != 0) { skipToLoopBegin(); }, jumps (1 != 0 is true), stack is the left the same
  9. >+ - stack is now [1, 5*, 0, ...]
  10. <- - stack is now [0*, 5, 0, ...]
  11. ] - if (tape[index] != 0) { skipToLoopBegin(); }, doesn't jump (0 != 0 is false), stack is left the same
  12. > - index += 1, stack is now [0, 5*, 0, ...]
  13. . - print(tape[index]), prints 5!

Needless to say, I didn't realize this question was from 2015! (Yay!) At least somebody may find this useful in the future... :^)

asu
  • 1,875
  • 17
  • 27