funnyvm/src/main.zig

88 lines
2.2 KiB
Zig

const std = @import("std");
const Instruction = enum(u32) {
PSH,
ADD,
POP,
SET,
HLT,
};
const default_program = [_]u32{
@enumToInt(Instruction.PSH), 5,
@enumToInt(Instruction.PSH), 6,
@enumToInt(Instruction.ADD), @enumToInt(Instruction.POP),
@enumToInt(Instruction.HLT),
};
const Stack = std.ArrayList(u32);
const VM = struct {
program: []const u32,
stack: Stack,
instruction_pointer: usize = 0,
stack_pointer: usize = 0,
running: bool = false,
const Self = @This();
pub fn init(allocator: *std.mem.Allocator, program: []const u32) !Self {
return Self{
.program = program,
.stack = try Stack.initCapacity(allocator, 256),
.instruction_pointer = 0,
};
}
pub fn deinit(self: Self) void {
self.stack.deinit();
}
pub fn fetch(self: Self) u32 {
return self.program[self.instruction_pointer];
}
pub fn runOne(self: *Self, instruction_as_number: u32) !void {
const instruction: Instruction = try std.meta.intToEnum(Instruction, instruction_as_number);
std.log.info("running {}", .{instruction});
switch (instruction) {
.PSH => {
self.instruction_pointer += 1;
const value = self.fetch();
self.stack.appendAssumeCapacity(value);
},
.POP => {
const value = self.stack.pop();
std.log.info("stack: popped {}", .{value});
},
.ADD => {
const value_a = self.stack.pop();
const value_b = self.stack.pop();
self.stack.appendAssumeCapacity(value_b + value_a);
},
.HLT => self.running = false,
else => unreachable,
}
}
};
pub fn main() anyerror!void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer {
_ = gpa.deinit();
}
const allocator = &gpa.allocator;
var vm = try VM.init(allocator, &default_program);
defer vm.deinit();
vm.running = true;
while (vm.running) {
try vm.runOne(vm.fetch());
vm.instruction_pointer += 1;
}
}