3
\$\begingroup\$

Syntax is ./bf-interpreter <program.bf>.

#include <stdio.h>
#include <stdlib.h>
#define MEM_CELL_SIZE 30000
#define MAX_INSTRUCTIONS 5000

unsigned int progressUntilNext(char* source, unsigned int i_pointer, size_t newLen)
{
    int open_brackets = 0;
    for(int i = i_pointer; i < newLen; i++)
    {
        switch (source[i])
        {
            case '[':
                open_brackets++;
                break;
            case ']':
                open_brackets--;
        }
        if (open_brackets == 0)
        {
            return i;
        }
    }
    return -1;
}
unsigned int goBackToPrevious(char* source, unsigned int i_pointer, size_t newLen)
{
    int open_brackets = 0;
    for(int i = i_pointer; i >= 0; i--)
    {
        switch (source[i])
        {
            case '[':
                open_brackets--;
                break;
            case ']':
                open_brackets++;
        }
        if (open_brackets == 0)
        {
            return i;
        }
    }
    return -1;
}
int main (int argc, char *argv[]) {
    unsigned char* memory;
    memory = calloc(MEM_CELL_SIZE, sizeof(char));
    unsigned int memory_pointer = 0;
    if (argc != 2)
    {
        printf("Syntax: ./bf-interpreter <filename>\n");
        return 1;
    }
    char* filename = argv[1];
    char* source = NULL;
    size_t newLen = 0;
    FILE* fp = fopen(filename, "r");
    if (fp != NULL)
    {
    /* Go to the end of the file. */
        if (fseek(fp, 0L, SEEK_END) == 0)
        {
            /* Get the size of the file. */
            long bufsize = ftell(fp);
            if ((bufsize == -1) || (bufsize > MAX_INSTRUCTIONS))
            {
                printf("Too much instructions\n");
                return 1;
            }
            /* Allocate our buffer to that size. */
            source = malloc(sizeof(char) * (bufsize + 1));
            /* Go back to the start of the file. */
            if (fseek(fp, 0L, SEEK_SET) != 0)
            {
                printf("Seek error\n");
                return 1;
            }
            /* Read the entire file into memory. */
            newLen = fread(source, sizeof(char), bufsize, fp);
            if (newLen == 0)
            {
                fputs("Error reading file", stderr);
                return 1;
            }
            else {
                source[++newLen] = '\0';
                // End of instructions
            }
        }
        else
        {
            printf("error\n");
            return 1;
        }
    fclose(fp);
    }
    for(int i_pointer = 0; i_pointer <= newLen; i_pointer++)
    {
        switch (source[i_pointer])
        {
            case '>':
                if (memory_pointer == MEM_CELL_SIZE)
                {
                    printf("Memory pointer error\n");
                    return 2;
                }
                memory_pointer++;
                break;
            case '<':
                if (memory_pointer == 0)
                {
                    printf("Memory pointer error\n");
                    return 2;
                }
                memory_pointer--;
                break;
            case '+':
                memory[memory_pointer]++;
                break;
            case '-':
                memory[memory_pointer]--;
                break;
            case '.':
                putchar(memory[memory_pointer]);
                break;
            case ',':
                memory[memory_pointer] = getchar();
                break;
            case '[':
                if (memory[memory_pointer] == 0)
                {
                    i_pointer = progressUntilNext(source, i_pointer, newLen);
                }
                break;
            case ']':
                if (memory[memory_pointer] != 0)
                {
                    i_pointer = goBackToPrevious(source, i_pointer, newLen);
                }
                break;
            case '\n':
                // This is a NOP
                break;
            case '\0':
                return 0;
                break;
            default:
                printf("Not recogized: %c\n", source[i_pointer]);
                break;
        }
    }
    free(source);
}
\$\endgroup\$
2
\$\begingroup\$

You have missed some error checks after memory allocations. Also you output errors to both stdin and stdout. That's not nice. I guess the only valid use of stdout is for Brainfuck . command output. Everything else are errors, they may go to stderr.

In C error handling is rather tedious and it is common practice to implement die function to terminate program with some message.

Example die:

void die(const char *msg) {
    fputs(msg, stderr);
    if (msg[0] && msg[strlen(msg)-1] == ':') {
        fputc(' ', stderr);
        perror(NULL);
    } else {
        fputc('\n', stderr);
    }
    exit(EXIT_FAILURE);
}

Notice how it uses perror when msg ends with :.

fread function is a bit tricky. It returns the number of items read. If an error occurs, or the end of the file is reached, the return value is a short item count. One trick is to call it like this: fread(source, bufsize, 1, fp). This way fread will return 1 only if all file was read. Anything else is unexpected end of file or error.

Example main:

int main(int argc, char *argv[]) {

    if (argc != 2) die("Syntax: ./bf-interpreter <filename>");

    FILE* fp = fopen(argv[1], "r");
    if (fp == NULL) die("fopen:");


    /* Getting file size. */

    if (fseek(fp, 0, SEEK_END) != 0) die("fseek:");
    size_t newLen = ftell(fp);
    if (newLen == -1) die("ftell:");
    if (newLen > MAX_INSTRUCTIONS) die("Too much instructions");
    if (fseek(fp, 0, SEEK_SET) != 0) die("fseek:");


    /* Reading the entire file into memory. */

    char *source = malloc(newLen + 1);
    if (source == NULL) die("malloc:");

    if (fread(source, newLen, 1, fp) != 1) {
        die("Error reading file");
    }

    source[++newLen] = '\0';

    fclose(fp);


    /* Brainfuck interpreter code starts here
       ...
    */
}

Some other notes:

  • putchar and getchar can return EOF
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.