#include #include #include #include #include #include #include void um(std::istream & scroll, std::istream & i, std::ostream & o) { std::unitbuf(o); using Chr = std::uint8_t; using Plt = std::uint32_t; auto reg = std::array(); auto arr = std::vector>(1); auto fng = Plt(0); auto hlt = false; auto alloc = [&](Plt c) { arr.emplace_back(c); return(Plt)arr.size()-1; }; auto aband = [&](Plt c) { arr[c] = decltype(arr)::value_type(); }; #define PACK(IND) ((Plt)(Chr)ch[IND] << 8*(3-IND)) for (char ch[4]; scroll.read(ch, 4);) arr[0].push_back(PACK(0) | PACK(1) | PACK(2) | PACK(3)); #undef PACK while (!hlt) { #define UNPACK(POS, SIZ) ((plt >> POS) & ((Plt(1) << SIZ) - 1)) auto plt = arr[0][fng++]; auto num = UNPACK(28, 4); auto val = UNPACK( 0, 25); auto & a = reg[UNPACK( 6, 3)]; auto & b = reg[UNPACK( 3, 3)]; auto & c = reg[UNPACK( 0, 3)]; auto & d = reg[UNPACK(25, 3)]; #undef UNPACK switch (num) { case 0: a = c ? b : a; break; // CMOVE case 1: a = arr[b][c]; break; // LOAD case 2: arr[a][b] = c; break; // STOR case 3: a = b + c; break; // ADD case 4: a = b * c; break; // MUL case 5: a = b / c; break; // DIV case 6: a = ~(b & c); break; // NAND case 7: hlt = true; break; // HALT case 8: b = alloc(c); break; // ALLOC case 9: aband(c); break; // ABAND case 10: o.put(c); break; // PUT case 11: c = i.get(); break; // GET case 12: arr[0] = arr[b]; fng = c; break; // EXEC case 13: d = val; break; // VALUE } } } int main(int argc, char * argv[]) { if (argc != 2) return std::fputs("Usage: um \n", stderr), EXIT_FAILURE; auto scroll = std::ifstream(argv[1], std::ios::binary); if (scroll.fail()) return std::perror("Failed to read scroll"), EXIT_FAILURE; if (scroll.peek(), scroll.eof()) return std::fputs("Empty scroll\n", stderr), EXIT_FAILURE; um(scroll, std::cin, std::cout); }