#include #include #include #include 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 \n", argv[0]); exit(EXIT_FAILURE); } program = load_array_from_file(argv[1]); run_program(); return 0; }