4Head/AuthorImplementation.c

From Esolang
Jump to navigation Jump to search
Back to 4Head
#include <assert.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

#define cell int16_t

#define MEM_X 100
#define MEM_Y 100


int is_digit(char x) {
    return '0' <= x && x <= '9';
}


void print_2d_array(cell *array, size_t width, size_t height, size_t x, size_t y) {
    for (size_t yi = 0; yi < height; ++yi) {
        for (size_t xi = 0; xi < width; ++xi) {
            size_t i = width*yi + xi;
            if (x == xi && y == yi) {
                printf(">%2d<", array[i]);
            }
            else {
                printf(" %2d ", array[i]);
            }
        }
        printf("\n");
    }
}


void interpret_program(const char *program, size_t program_length, int enable_debug) {
    const size_t width = MEM_X, height = MEM_Y;
    cell memory[MEM_Y][MEM_X] = {0};

    size_t x = 0, y = 0;
    size_t amount = 1;
    cell hold = 0;

    size_t i = 0;

    while (i < program_length) {
#if 0
        printf("i=%3lld,x=%2lld,y=%2lld\n", i, x, y);
#endif
        switch(program[i]) {
            case '+':
                // Increment
                hold += amount;
                amount = 1;
                i++;
                break;
            case '-':
                // Decrement
                hold -= amount;
                amount = 1;
                i++;
                break;
            case '<':
                // Move left
                if (amount >= x) {
                    x = 0;
                }
                else {
                    x -= amount;
                }
                amount = 1;
                i++;
                break;
            case '>':
                // Move right
                if (x + amount > width-1) {
                    x = width-1;
                }
                else {
                    x += amount;
                }
                amount = 1;
                i++;
                break;
            case '^':
                // Move up
                if (amount >= y) {
                    y = 0;
                }
                else {
                    y -= amount;
                }
                amount = 1;
                i++;
                break;
            case 'v':
                // Move down
                if (y + amount > height-1) {
                    y = height-1;
                }
                else {
                    y += amount;
                }
                amount = 1;
                i++;
                break;
            case '@':
                // Fetch
                hold = memory[y][x];
                amount = 1;
                i++;
                break;
            case '!':
                // Store
                memory[y][x] = hold;
                amount = 1;
                i++;
                break;
            case '%':
                // Swap
                {
                    cell t = memory[y][x];
                    memory[y][x] = hold;
                    hold = t;
                    amount = 1;
                    i++;
                }
                break;
            case '[':
                // Jump past matching bracket if current cell is 0
                if (hold == 0) {
                    int level = 1;
                    int original_i = i;
                    // inefficient while loop to find the matching bracket
                    while (level != 0 && i < program_length) {
                        i++;
                        if (program[i] == '[') {
                            level++;
                        }
                        else if (program[i] == ']') {
                            level--;
                        }
                    }
                    if (level != 0) {
                        printf("ERROR: unmatched opening bracket '[' at index %d", original_i);
                        exit(1);
                    }
                }
                i++;
                amount = 1;
                break;
            case ']':
                // Jump back to the matching bracket if current cell is not 0
                if (hold != 0) {
                    int level = 1;
                    int original_i = i;
                    // inefficient while loop to find the matching bracket
                    while (level != 0 && i < program_length) {
                        i--;
                        if (program[i] == ']') {
                            level++;
                        }
                        else if (program[i] == '[') {
                            level--;
                        }
                    }
                    if (level != 0) {
                        printf("ERROR: unmatched opening bracket ']' at index %d", original_i);
                        exit(1);
                    }
                }
                i++;
                amount = 1;
                break;
            case '?':
                // Get a character of input
                hold = getchar();
                i++;
                amount = 1;
                break;
            case '.':
                // Set a character of output
                putchar(hold);
                i++;
                amount = 1;
                break;
            case '#':
                // Debugger
                if (enable_debug) {
                    printf("\n");
                    print_2d_array((cell*) memory, width, height, x, y);
                    amount = 1;
                }
                i++;
                break;
            default:
                // Try to read a number and ignore any other characters
                if (is_digit(program[i])) {
                    // Start of a number, so set the amount to it
                    size_t n = 0;
                    while (is_digit(program[i])) {
                        n = (n*10) + (program[i] - '0');
                        i++;
                    }
                    if (n) {
                        amount = n;
                    }
                } else {
                    // Ignore non-number
                    i++;
                }
                break;
        }
    }
}