console8.zig (2934B)
1const std = @import("std"); 2const aoc = @import("aoc.zig"); 3 4pub const OpError = error{ InstructionPointerOOB, InvalidFormat, InstructionUnknown }; 5pub const OpFuncSig = fn (ctx: *Console, arg: i64) OpError!void; 6pub const Instruction = struct { opcode: []const u8, opfunc: *const OpFuncSig, argval: i64 }; 7 8pub const Console = struct { 9 accumulator: i64 = 0, 10 instructptr: u64 = 0, 11 12 jumpAddr: i65 = 0, 13 14 code: []const u8, 15 instlist: [][]const u8, 16 allocator: std.mem.Allocator, 17 const Self = @This(); 18 19 pub fn init(code: []const u8, allocator: std.mem.Allocator) !Self { 20 var instvec = std.ArrayList([]const u8).init(allocator); 21 errdefer instvec.deinit(); 22 23 var instit = std.mem.tokenize(u8, code, "\n"); 24 while (instit.next()) |inst| { 25 try instvec.append(inst); 26 } 27 return Console{ 28 .code = code, 29 .instlist = instvec.toOwnedSlice(), 30 .allocator = allocator, 31 }; 32 } 33 34 pub fn deinit(self: *Self) void { 35 self.allocator.free(self.instlist); 36 } 37 38 pub fn reset(self: *Self) void { 39 self.accumulator = 0; 40 self.instructptr = 0; 41 } 42 43 const instructionMap = std.ComptimeStringMap(*const OpFuncSig, .{ 44 .{ "jmp", jumpInstruction }, 45 .{ "acc", accInstruction }, 46 .{ "nop", nopInstruction }, 47 }); 48 49 pub fn jumpInstruction(self: *Self, arg: i64) OpError!void { 50 self.jumpAddr = @intCast(i65, self.instructptr) + @intCast(i65, arg); 51 if (self.jumpAddr < 0 or self.jumpAddr >= self.instlist.len) 52 return error.InstructionPointerOOB; 53 self.instructptr = @intCast(u64, self.jumpAddr); 54 } 55 56 pub fn accInstruction(self: *Self, arg: i64) OpError!void { 57 self.accumulator += arg; 58 self.instructptr += 1; 59 } 60 61 pub fn nopInstruction(self: *Self, arg: i64) OpError!void { 62 _ = arg; 63 self.instructptr += 1; 64 } 65 66 pub fn parseNext(self: *Self) !?Instruction { 67 if (self.instructptr >= self.instlist.len) 68 return null; 69 70 const inststr = self.instlist[self.instructptr]; 71 const sep = std.mem.indexOfScalar(u8, inststr, ' '); 72 if (sep == null) return OpError.InvalidFormat; 73 74 const opcode = inststr[0..sep.?]; 75 if (instructionMap.get(opcode)) |opfunc| { 76 const arg = inststr[sep.? + 1 ..]; 77 const val = std.fmt.parseInt(i64, arg, 10) catch { 78 aoc.debugfmt("Failed to parse arg value: {s}\n", .{arg}); 79 return OpError.InvalidFormat; 80 }; 81 return Instruction{ .opcode = opcode, .opfunc = opfunc, .argval = val }; 82 } else { 83 aoc.debugfmt("Unknown instruction: {s}\n", .{inststr}); 84 return OpError.InstructionUnknown; 85 } 86 } 87 88 pub fn exec(self: *Self, inst: *Instruction) !void { 89 try inst.opfunc(self, inst.argval); 90 } 91};