2024-06-24 13:23:11 -04:00
|
|
|
//brainf
|
|
|
|
const std = @import("std");
|
|
|
|
const io = std.io;
|
|
|
|
const fs = std.fs;
|
2024-06-24 21:25:17 -04:00
|
|
|
const mem = std.mem;
|
2024-06-24 13:23:11 -04:00
|
|
|
const process = std.process;
|
2024-06-24 21:25:17 -04:00
|
|
|
const testing = std.testing;
|
|
|
|
const ArrayList = std.ArrayList;
|
|
|
|
|
|
|
|
const Level1 = union(enum) {
|
|
|
|
// think about it... i hope
|
|
|
|
inc: i16,
|
|
|
|
shift: i16,
|
|
|
|
// u8 because why would we be reading to/writing from the same cell 256 times in a row
|
|
|
|
// well, might as well use the extra space (union is bigger than its biggest member)
|
|
|
|
in: u16,
|
|
|
|
out: u16,
|
|
|
|
loop_start,
|
|
|
|
loop_end,
|
|
|
|
|
|
|
|
const Self = @This();
|
|
|
|
fn pointless(self: Self) bool {
|
|
|
|
return switch (self) {
|
|
|
|
.inc, .shift => |n| n == 0,
|
|
|
|
.in, .out => |n| n == 0,
|
|
|
|
else => false,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const Level2 = union(enum) {
|
|
|
|
inc: i16,
|
|
|
|
shift: i16,
|
|
|
|
in: u16,
|
|
|
|
out: u16,
|
|
|
|
// only difference
|
|
|
|
// u24s because i arbitrarily chose 2^24 as the limit
|
|
|
|
// maybe u32 would be more efficient idk this union should fit in a u32
|
|
|
|
// hm we can probably go way lower bc level1 is so much more compact than prog_unfiltered
|
|
|
|
// shouldn't be necessary
|
|
|
|
loop_start: u24,
|
|
|
|
loop_end: u24,
|
|
|
|
};
|
|
|
|
|
|
|
|
// we'll do the discarding of comment chars here
|
|
|
|
fn compileLevel1(allocator: mem.Allocator, src: []const u8) !ArrayList(Level1) {
|
|
|
|
var cur: ?Level1 = null;
|
|
|
|
var out = ArrayList(Level1).init(allocator);
|
|
|
|
|
|
|
|
for (src) |b| {
|
|
|
|
switch (b) {
|
|
|
|
'+', '-' => {
|
|
|
|
const n: i16 = if (b == '+') 1 else -1;
|
|
|
|
if (cur) |*ins| {
|
|
|
|
switch (ins.*) {
|
|
|
|
.inc => |*ns| ns.* += n,
|
|
|
|
else => {
|
|
|
|
if (!ins.pointless()) try out.append(ins.*);
|
|
|
|
cur = .{ .inc = n };
|
|
|
|
},
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
cur = .{ .inc = n };
|
|
|
|
}
|
|
|
|
},
|
|
|
|
'>', '<' => {
|
|
|
|
const n: i16 = if (b == '>') 1 else -1;
|
|
|
|
if (cur) |*ins| {
|
|
|
|
switch (ins.*) {
|
|
|
|
.shift => |*ns| ns.* += n,
|
|
|
|
else => {
|
|
|
|
if (!ins.pointless()) try out.append(ins.*);
|
|
|
|
cur = .{ .shift = n };
|
|
|
|
},
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
cur = .{ .shift = n };
|
|
|
|
}
|
|
|
|
},
|
|
|
|
'[', ']' => {
|
|
|
|
if (cur) |ins| {
|
|
|
|
if (!ins.pointless()) try out.append(ins);
|
|
|
|
cur = null;
|
|
|
|
}
|
|
|
|
try out.append(if (b == '[') .loop_start else .loop_end);
|
|
|
|
},
|
|
|
|
',' => {
|
|
|
|
if (cur) |*ins| {
|
|
|
|
switch (ins.*) {
|
|
|
|
.in => |*ns| ns.* += 1,
|
|
|
|
else => {
|
|
|
|
if (!ins.pointless()) try out.append(ins.*);
|
|
|
|
cur = .{ .in = 1 };
|
|
|
|
},
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
cur = .{ .in = 1 };
|
|
|
|
}
|
|
|
|
},
|
|
|
|
'.' => {
|
|
|
|
if (cur) |*ins| {
|
|
|
|
switch (ins.*) {
|
|
|
|
.out => |*ns| ns.* += 1,
|
|
|
|
else => {
|
|
|
|
if (!ins.pointless()) try out.append(ins.*);
|
|
|
|
cur = .{ .out = 1 };
|
|
|
|
},
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
cur = .{ .out = 1 };
|
|
|
|
}
|
|
|
|
},
|
|
|
|
else => {},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cur) |ins| {
|
|
|
|
if (!ins.pointless()) try out.append(ins);
|
|
|
|
}
|
|
|
|
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
test "level 1" {
|
|
|
|
const src = "+++-- [ >><<< +- ] ...,,,";
|
|
|
|
|
|
|
|
const level1 = try compileLevel1(testing.allocator, src);
|
|
|
|
defer level1.deinit();
|
|
|
|
|
|
|
|
std.debug.print("{any}\n", .{level1.items});
|
|
|
|
|
|
|
|
const should_be = [_]Level1{
|
|
|
|
.{ .inc = 1 },
|
|
|
|
.loop_start,
|
|
|
|
.{ .shift = -1 },
|
|
|
|
.loop_end,
|
|
|
|
.{ .out = 3 },
|
|
|
|
.{ .in = 3 },
|
|
|
|
};
|
|
|
|
try testing.expectEqual(should_be.len, level1.items.len);
|
|
|
|
|
|
|
|
for (
|
|
|
|
level1.items,
|
|
|
|
&should_be,
|
|
|
|
) |a, b| {
|
|
|
|
try testing.expectEqual(a, b);
|
|
|
|
}
|
|
|
|
}
|
2024-06-24 13:23:11 -04:00
|
|
|
|
|
|
|
pub fn main() !void {
|
|
|
|
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
|
|
|
var allocator = arena.allocator();
|
|
|
|
defer arena.deinit();
|
|
|
|
|
|
|
|
var out = io.getStdOut().writer();
|
|
|
|
var in = io.getStdIn().reader();
|
|
|
|
|
|
|
|
var args = process.args();
|
|
|
|
defer args.deinit();
|
|
|
|
_ = args.skip();
|
|
|
|
|
|
|
|
const prog_path = args.next() orelse {
|
|
|
|
try io.getStdErr().writer().writeAll("i need a program path :(\n");
|
|
|
|
process.exit(1);
|
|
|
|
};
|
|
|
|
|
|
|
|
var prog_file = try fs.cwd().openFile(prog_path, .{});
|
|
|
|
const prog_unfiltered = try prog_file.readToEndAlloc(allocator, 1 << 24);
|
|
|
|
var prog = try allocator.alloc(u8, prog_unfiltered.len);
|
|
|
|
var prog_len: u32 = 0;
|
|
|
|
for (prog_unfiltered) |c| {
|
|
|
|
if (c == '+' or c == '-' or c == '>' or c == '<' or c == '[' or c == ']' or c == '.' or c == ',') {
|
|
|
|
prog[prog_len] = c;
|
|
|
|
prog_len += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-24 21:25:17 -04:00
|
|
|
var memory = try allocator.alloc(u8, 1 << 16);
|
|
|
|
for (memory) |*m| {
|
2024-06-24 13:23:11 -04:00
|
|
|
m.* = 0;
|
|
|
|
}
|
|
|
|
var mp: u16 = 0;
|
|
|
|
var ip: u32 = 0;
|
|
|
|
|
|
|
|
while (ip < prog_len) {
|
|
|
|
switch (prog[ip]) {
|
2024-06-24 21:25:17 -04:00
|
|
|
'+' => memory[mp] +%= 1,
|
|
|
|
'-' => memory[mp] -%= 1,
|
2024-06-24 13:23:11 -04:00
|
|
|
'>' => mp +%= 1,
|
|
|
|
'<' => mp -%= 1,
|
|
|
|
'[' => {
|
2024-06-24 21:25:17 -04:00
|
|
|
if (memory[mp] == 0) {
|
2024-06-24 13:23:11 -04:00
|
|
|
var depth: i16 = 1;
|
|
|
|
ip += 1;
|
|
|
|
while (depth > 0) : (ip += 1) {
|
|
|
|
depth += switch (prog[ip]) {
|
|
|
|
']' => -1,
|
|
|
|
'[' => 1,
|
|
|
|
else => 0,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
ip -= 1;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
']' => {
|
2024-06-24 21:25:17 -04:00
|
|
|
if (memory[mp] != 0) {
|
2024-06-24 13:23:11 -04:00
|
|
|
var depth: i16 = 1;
|
|
|
|
ip -= 1;
|
|
|
|
while (depth > 0) : (ip -= 1) {
|
|
|
|
depth += switch (prog[ip]) {
|
|
|
|
'[' => -1,
|
|
|
|
']' => 1,
|
|
|
|
else => 0,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
ip += 1;
|
|
|
|
}
|
|
|
|
},
|
2024-06-24 21:25:17 -04:00
|
|
|
',' => memory[mp] = in.readByte() catch 0,
|
|
|
|
'.' => try out.writeByte(memory[mp]),
|
2024-06-24 13:23:11 -04:00
|
|
|
else => unreachable,
|
|
|
|
}
|
|
|
|
ip += 1;
|
|
|
|
}
|
|
|
|
}
|