<?xml version="1.0"?>
<paste-with-annotations>
  <paste>
    <number>
      <integer>23177</integer>
    </number>
    <user>
      <string>Per Vognsen</string>
    </user>
    <title>
      <string>UM implementation</string>
    </title>
    <contents>
      <string>#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;assert.h&gt;

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-&gt;size = size;
    memset(&amp;array-&gt;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 &lt; program-&gt;size) {
        const word_t word = program-&gt;elements[pc++];
        const int op = (word &gt;&gt; 28) &amp; 0xF;
        if (op == 13) { // orthography
            const int i = (word &gt;&gt; 25) &amp; 0x7;
            const word_t value = word &amp; ((1 &lt;&lt; 25) - 1);
            registers[i] = value;
        } else {
            const int a = (word &gt;&gt; 6) &amp; 0x7;
            const int b = (word &gt;&gt; 3) &amp; 0x7;
            const int c = word &amp; 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 &lt; array-&gt;size);
                registers[a] = array-&gt;elements[offset];
                break;
            }
            case 2: // array amendment
            {
                array_t* array = array_from_word(registers[a]);
                const word_t offset = registers[b];
                assert(offset &lt; array-&gt;size);
                array-&gt;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] &amp; 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-&gt;size);
                    memcpy(&amp;program-&gt;elements[0], &amp;array-&gt;elements[0], array-&gt;size * sizeof(word_t));
                }
                break;
            }
            default:
                fprintf(stderr, &quot;invalid opcode&quot;);
                exit(EXIT_FAILURE);
            }
        }
    }
}

array_t* load_array_from_file(const char* filename)
{
    if (FILE* fp = fopen(filename, &quot;rb&quot;)) {
        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 &lt; size; i++) {
            unsigned char bytes[4];
            if (fread(bytes, 1, 4, fp) != 4) {
                perror(&quot;load_array_from_file&quot;);
                exit(EXIT_FAILURE);
            }
            array-&gt;elements[i] = word_t((bytes[0] &lt;&lt; 24) | (bytes[1] &lt;&lt; 16) | (bytes[2] &lt;&lt; 8) | bytes[3]);
        }
        fclose(fp);
        return array;
    } else {
        perror(&quot;load_array_from_file&quot;);
        exit(EXIT_FAILURE);
        return NULL;
    }
}

int main(int argc, char** argv)
{
    if (argc &lt; 2) {
        fprintf(stderr, &quot;Usage: %s &lt;program-file&gt;\n&quot;, argv[0]);
        exit(EXIT_FAILURE);
    }
    program = load_array_from_file(argv[1]);
    run_program();
    return 0;
}
</string>
    </contents>
    <universal-time>
      <integer>3362871730</integer>
    </universal-time>
    <channel>
      <string>None</string>
    </channel>
    <colorization-mode>
      <string>C++</string>
    </colorization-mode>
    <maybe-spam>
      <null/>
    </maybe-spam>
    <is-unicode>
      <null/>
    </is-unicode>
  </paste>
</paste-with-annotations>