Paste number 23177: UM implementation

Paste number 23177: UM implementation
Pasted by: Per Vognsen
When:11 years, 2 months ago
Share:Tweet this! | http://paste.lisp.org/+HVT
Channel:None
Paste contents:
Raw Source | XML | Display As
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

typedef unsigned int word_t;

struct array_t
{
    size_t size;
    word_t elements[1];
};

array_t* program = NULL;
word_t registers[8] = {0};

array_t* alloc_array(size_t size)
{
    array_t* array = (array_t*) malloc(sizeof(size_t) + size * sizeof(word_t));
    array->size = size;
    memset(&array->elements[0], 0, size * sizeof(word_t));
    return array;
}

array_t* array_from_word(word_t word)
{
    return (word == 0) ? program : (array_t*) word;
}

void run_program()
{
    size_t pc = 0;
    while (pc < program->size) {
        const word_t word = program->elements[pc++];
        const int op = (word >> 28) & 0xF;
        if (op == 13) { // orthography
            const int i = (word >> 25) & 0x7;
            const word_t value = word & ((1 << 25) - 1);
            registers[i] = value;
        } else {
            const int a = (word >> 6) & 0x7;
            const int b = (word >> 3) & 0x7;
            const int c = word & 0x7;
            switch (op) {
            case 0: // conditional move
                if (registers[c] != 0) {
                    registers[a] = registers[b];
                }
                break;
            case 1: // array index
            {
                const array_t* array = array_from_word(registers[b]);
                const word_t offset = registers[c];
                assert(offset < array->size);
                registers[a] = array->elements[offset];
                break;
            }
            case 2: // array amendment
            {
                array_t* array = array_from_word(registers[a]);
                const word_t offset = registers[b];
                assert(offset < array->size);
                array->elements[offset] = registers[c];
                break;
            }
            case 3: // addition
                registers[a] = registers[b] + registers[c];
                break;
            case 4: // multiplication
                registers[a] = registers[b] * registers[c];
                break;
            case 5: // division
                registers[a] = registers[b] / registers[c];
                break;
            case 6: // not-and
                registers[a] = ~(registers[b] & registers[c]);
                break;
            case 7: // halt
                return;
            case 8: // allocation
                registers[b] = word_t(alloc_array(registers[c]));
                break;
            case 9: // abandonment
            {
                array_t* array = array_from_word(registers[c]);
                assert(array != program);
                free(array);
                break;
            }
            case 10: // output
                fputc(registers[c], stdout);
                break;
            case 11: // input
            {
                const char ch = fgetc(stdin);
                registers[c] = word_t((ch != EOF) ? ch : ~0);
                break;
            }
            case 12: // load program
            {
                pc = registers[c];
                const array_t* array = array_from_word(registers[b]);
                if (array != program) {
                    free(program);
                    program = alloc_array(array->size);
                    memcpy(&program->elements[0], &array->elements[0], array->size * sizeof(word_t));
                }
                break;
            }
            default:
                fprintf(stderr, "invalid opcode");
                exit(EXIT_FAILURE);
            }
        }
    }
}

array_t* load_array_from_file(const char* filename)
{
    if (FILE* fp = fopen(filename, "rb")) {
        fseek(fp, 0, SEEK_END);
        const size_t size = ftell(fp) / 4;
        fseek(fp, 0, SEEK_SET);
        array_t* array = alloc_array(size);
        for (size_t i = 0; i < size; i++) {
            unsigned char bytes[4];
            if (fread(bytes, 1, 4, fp) != 4) {
                perror("load_array_from_file");
                exit(EXIT_FAILURE);
            }
            array->elements[i] = word_t((bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]);
        }
        fclose(fp);
        return array;
    } else {
        perror("load_array_from_file");
        exit(EXIT_FAILURE);
        return NULL;
    }
}

int main(int argc, char** argv)
{
    if (argc < 2) {
        fprintf(stderr, "Usage: %s <program-file>\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    program = load_array_from_file(argv[1]);
    run_program();
    return 0;
}

This paste has no annotations.

Colorize as:
Show Line Numbers

Lisppaste pastes can be made by anyone at any time. Imagine a fearsomely comprehensive disclaimer of liability. Now fear, comprehensively.