Search code examples
cdebuggingbrainfuck

Why the brainfuck interpreter in C may not work when executing a program with loops?


I decided to write another one BF interpreter in order of personal development, and despite the fact that this is his second version written from scratch, one way or another it doesn't work correctly with cycles. Please tell me how this can be rewritten, or what is the logical problem. Below is the code and examples of programs in BF.

#include <stdio.h>

void brainfuck(char* str, int length)
{
    char arr[30000] = { 0 };
    int ptr = 0, i = 0;

    int **brackets = { 0 };
    int br_len = 0;

    while (i < length)
    {
        if (str[i] == '[')
        {
            brackets = (int **)realloc(brackets, (br_len + 1) * sizeof(int *));
            brackets[br_len] = (int *)malloc(2 * sizeof(int));
            brackets[br_len][0] = '[';
            brackets[br_len][1] = i;
            br_len++;
        }
        else if (str[i] == ']')
        {
            brackets = (int **)realloc(brackets, (br_len + 1) * sizeof(int *));
            brackets[br_len] = (int *)malloc(2 * sizeof(int));
            brackets[br_len][0] = ']';
            brackets[br_len][1] = i;
            br_len++;
        }

        i++;
    }

    int counter, pos, j; i = 0;

    while (i < length)
    {
        switch (str[i])
        {
            case '>': ptr++; break;
            case '<': ptr--; break;
            case '+': arr[ptr]++; break;
            case '-': arr[ptr]--; break;
            case '.': putchar(arr[ptr]); break;
            case ',': arr[ptr] = getchar(); break;
            case '[':
                if (arr[ptr] == 0)
                {
                    j = 0;
                    pos = 0;

                    do
                    {
                        pos = j;
                        j++;
                    }
                    while (brackets[j - 1][1] != i);

                    j = pos + 1;
                    counter = 1;

                    while (j < br_len)
                    {
                        if (brackets[j][0] == '[')
                            counter++;
                        else if (brackets[j][0] == ']')
                        {
                            counter--;
                            if (counter == 0)
                                break;
                        }

                        j++;
                    }

                    i = brackets[j][1];
                }

                break;
            case ']':
                if (arr[ptr] == 0)
                {
                    j = br_len - 1;
                    pos = br_len - 1;

                    do
                    {
                        pos = j;
                        j--;
                    } while (brackets[j + 1][1] != i);

                    j = pos - 1;
                    counter = -1;

                    while (j >= 0)
                    {
                        if (brackets[j][0] == '[')
                        {
                            counter++;
                            if (counter == 0)
                                break;
                        }
                        else if (brackets[j][0] == ']')
                            counter--;

                        j--;
                    }

                    i = brackets[j][1] - 1;
                }

                break;
            default: break;
        }

        i++;
    }

    free(brackets);
}

void main()
{
    FILE* fr;
    int length;
    char* str;

    fr = fopen("input.txt", "r");

    fseek(fr, 0, SEEK_END);
    length = ftell(fr);
    rewind(fr);

    str = (char*)malloc(length * sizeof(char));
    fread(str, 1, length, fr);

    brainfuck(str, length);

    free(str);
    fclose(fr);
}

"Hello World!" with one loop

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

"Hello World!" with nested loops

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

Solution

  • ']' should jump back if cell is nonzero

    Hugely convoluted approach; you want to put the matches in the brackets array so it's like

    case '[':
      if (arr[ptr] == 0)
        i = brackets[i];
      break;
    

    Why i = brackets[j][1] - 1; and not just i = brackets[j][1]; (extra speed cost)

    Having j and pos laboriously correlate is a red flag

    Forgot to free all those little 2-int arrays