opt1.zig (3747B) - raw


      1 // opt1: use jump table
      2 
      3 const std = @import("std");
      4 const common = @import("common.zig");
      5 const Allocator = std.mem.Allocator;
      6 const ArrayList = std.ArrayList;
      7 const Program = common.Program;
      8 const JumpTable = ArrayList(usize);
      9 
     10 // comptime known build option, -Dtrace and -Ddebug-opts
     11 const build_options = @import("build_options");
     12 const TRACE = build_options.TRACE;
     13 
     14 pub fn main() anyerror!void {
     15     if (TRACE) {
     16         std.debug.print("Building with TRACE enabled\n", .{});
     17     }
     18 
     19     try common.runInterpreter(common.parseProgram, interpret);
     20 }
     21 
     22 test "og: interpret hello world" {
     23     try common.testHelloWorld(common.parseProgram, interpret);
     24 }
     25 
     26 fn interpret(program: Program, memory: []u8, rdr: anytype, wtr: anytype, alloc: Allocator) !void {
     27     var instruction_count = if (TRACE) std.AutoHashMap(u8, usize).init(alloc);
     28     if (TRACE) {
     29         defer instruction_count.deinit();
     30     }
     31 
     32     const jumptable = try computeJumptable(program, alloc);
     33     defer jumptable.deinit();
     34 
     35     const instructions = program.instructions;
     36     var pc: usize = 0;
     37     var dataptr: usize = 0;
     38 
     39     while (pc < instructions.len) {
     40         const instruction = instructions[pc];
     41 
     42         if (TRACE) {
     43             const entry = try instruction_count.getOrPut(instruction);
     44             if (entry.found_existing) {
     45                 entry.value_ptr.* += 1;
     46             } else {
     47                 entry.value_ptr.* = 1;
     48             }
     49         }
     50 
     51         switch (instruction) {
     52             '>' => dataptr += 1,
     53             '<' => dataptr -= 1,
     54             '+' => memory[dataptr] += 1,
     55             '-' => memory[dataptr] -= 1,
     56             ',' => memory[dataptr] = try rdr.readByte(),
     57             '.' => try wtr.writeByte(memory[dataptr]),
     58             // jumps to next matching ']' if curr_data == 0
     59             '[' => if (memory[dataptr] == 0) {
     60                 pc = jumptable.items[pc];
     61             },
     62             // jumps to previous matching ']' if curr data != 0
     63             ']' => if (memory[dataptr] != 0) {
     64                 pc = jumptable.items[pc];
     65             },
     66             else => {
     67                 return error.unreachableChar;
     68             },
     69         }
     70 
     71         pc += 1;
     72     }
     73 
     74     if (TRACE) {
     75         var kv = instruction_count.iterator();
     76         std.debug.print("\n# Instruction Count\n", .{});
     77         while (kv.next()) |entry| {
     78             std.debug.print("{c}: {d}\n", .{ entry.key_ptr.*, entry.value_ptr.* });
     79         }
     80     }
     81 }
     82 
     83 // jump from idx to jmp[idx]. Any non-jump is mapped jmp[idx] = 0
     84 fn computeJumptable(program: Program, alloc: Allocator) !JumpTable {
     85     var jumptable = try JumpTable.initCapacity(alloc, program.instructions.len);
     86     jumptable.appendNTimesAssumeCapacity(0, program.instructions.len);
     87 
     88     const instructions = program.instructions;
     89     var pc: usize = 0;
     90 
     91     // for each bracket, seek the matching bracket
     92     // and then write both into jumptable
     93     while (pc < instructions.len) {
     94         const instruction = instructions[pc];
     95 
     96         if (instruction == '[') {
     97             var bracket_nesting: usize = 1;
     98             var seek: usize = pc;
     99 
    100             while (bracket_nesting != 0 and seek < instructions.len - 1) {
    101                 seek += 1;
    102 
    103                 const seek_instruction = instructions[seek];
    104                 if (seek_instruction == ']') {
    105                     bracket_nesting -= 1;
    106                 } else if (seek_instruction == '[') {
    107                     bracket_nesting += 1;
    108                 }
    109             }
    110 
    111             if (bracket_nesting == 0) {
    112                 jumptable.items[pc] = seek;
    113                 jumptable.items[seek] = pc;
    114             } else {
    115                 std.debug.print("unmatched ']' at pc={}", .{pc});
    116             }
    117         }
    118         pc += 1;
    119     }
    120 
    121     return jumptable;
    122 }