1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
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);
}
};
|