aboutsummaryrefslogtreecommitdiffstats
path: root/src/common/console8.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/console8.zig')
-rw-r--r--src/common/console8.zig91
1 files changed, 91 insertions, 0 deletions
diff --git a/src/common/console8.zig b/src/common/console8.zig
new file mode 100644
index 0000000..c778955
--- /dev/null
+++ b/src/common/console8.zig
@@ -0,0 +1,91 @@
+const std = @import("std");
+const aoc = @import("aoc.zig");
+
+pub const OpError = error{ InstructionPointerOOB, InvalidFormat, InstructionUnknown };
+pub const OpFuncSig = fn (ctx: *Console, arg: i64) OpError!void;
+pub const Instruction = struct { opcode: []const u8, opfunc: *const OpFuncSig, argval: i64 };
+
+pub const Console = struct {
+ accumulator: i64 = 0,
+ instructptr: u64 = 0,
+
+ jumpAddr: i65 = 0,
+
+ code: []const u8,
+ instlist: [][]const u8,
+ allocator: std.mem.Allocator,
+ const Self = @This();
+
+ pub fn init(code: []const u8, allocator: std.mem.Allocator) !Self {
+ var instvec = std.ArrayList([]const u8).init(allocator);
+ errdefer instvec.deinit();
+
+ var instit = std.mem.tokenize(u8, code, "\n");
+ while (instit.next()) |inst| {
+ try instvec.append(inst);
+ }
+ return Console{
+ .code = code,
+ .instlist = instvec.toOwnedSlice(),
+ .allocator = allocator,
+ };
+ }
+
+ pub fn deinit(self: *Self) void {
+ self.allocator.free(self.instlist);
+ }
+
+ pub fn reset(self: *Self) void {
+ self.accumulator = 0;
+ self.instructptr = 0;
+ }
+
+ const instructionMap = std.ComptimeStringMap(*const OpFuncSig, .{
+ .{ "jmp", jumpInstruction },
+ .{ "acc", accInstruction },
+ .{ "nop", nopInstruction },
+ });
+
+ pub fn jumpInstruction(self: *Self, arg: i64) OpError!void {
+ self.jumpAddr = @intCast(i65, self.instructptr) + @intCast(i65, arg);
+ if (self.jumpAddr < 0 or self.jumpAddr >= self.instlist.len)
+ return error.InstructionPointerOOB;
+ self.instructptr = @intCast(u64, self.jumpAddr);
+ }
+
+ pub fn accInstruction(self: *Self, arg: i64) OpError!void {
+ self.accumulator += arg;
+ self.instructptr += 1;
+ }
+
+ pub fn nopInstruction(self: *Self, arg: i64) OpError!void {
+ _ = arg;
+ self.instructptr += 1;
+ }
+
+ pub fn parseNext(self: *Self) !?Instruction {
+ if (self.instructptr >= self.instlist.len)
+ return null;
+
+ const inststr = self.instlist[self.instructptr];
+ const sep = std.mem.indexOfScalar(u8, inststr, ' ');
+ if (sep == null) return OpError.InvalidFormat;
+
+ const opcode = inststr[0..sep.?];
+ if (instructionMap.get(opcode)) |opfunc| {
+ const arg = inststr[sep.? + 1 ..];
+ const val = std.fmt.parseInt(i64, arg, 10) catch {
+ aoc.debugfmt("Failed to parse arg value: {s}\n", .{arg});
+ return OpError.InvalidFormat;
+ };
+ return Instruction{ .opcode = opcode, .opfunc = opfunc, .argval = val };
+ } else {
+ aoc.debugfmt("Unknown instruction: {s}\n", .{inststr});
+ return OpError.InstructionUnknown;
+ }
+ }
+
+ pub fn exec(self: *Self, inst: *Instruction) !void {
+ try inst.opfunc(self, inst.argval);
+ }
+};