Skip to content

Instantly share code, notes, and snippets.

@micaiahparker
Last active October 30, 2019 19:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save micaiahparker/e7f1f5e1190b2a2d41251bbc83a9de84 to your computer and use it in GitHub Desktop.
Save micaiahparker/e7f1f5e1190b2a2d41251bbc83a9de84 to your computer and use it in GitHub Desktop.
BF interpreter in Zig
const std = @import("std");
const io = std.io;
const File = std.fs.File;
const debug = std.debug;
const process = std.process;
const mem = std.mem;
const assert = debug.assert;
const warn = debug.warn;
const allocator = debug.global_allocator;
const logging = true;
const Token = enum {
Add,
Sub,
Get,
Put,
Next,
Prev,
LeftBracket,
RightBracket,
Invalid,
};
pub fn main() anyerror!void {
var logger: File = File.openWrite("bfz.log") catch |err| {
warn("Failed to open 'log.bfz' {}\n", @errorName(err));
return err;
};
try log(logger, "Started program.\n");
var args = process.args();
const exe = args.next(allocator).? catch |err| {
warn("{}\n", @errorName(err));
return err;
};
const filename = args.next(allocator).? catch |err| {
warn("{}\n", err);
return err;
};
var in = File.openRead(filename) catch |err| {
warn("Failed to open input: {}\n", filename);
return err;
};
var ptr: u8 = 0;
var tape: []u8 = try allocator.alloc(u8, 1024 * 4);
for (tape) |*i| {
i.* = 0;
}
var program: []Token = try allocator.alloc(Token, 1024 * 4);
var p: u32 = 0;
var p_max: u32 = 0;
var stdin = try io.getStdIn();
var buf: [1024 * 4]u8 = undefined;
while (true) {
if (p_max == program.len) {
warn("Buffer exceeded.\n");
}
const bytes_read = in.read(buf[0..]) catch |err| {
warn("Unable to read from stdin {}\n", @errorName(err));
return err;
};
if (bytes_read == 0) {
break;
}
try log(logger, "Program:\n\n");
for (buf[0..bytes_read]) |c, i| {
const token: Token = get_token(c);
if (token != Token.Invalid) {
program[p_max] = token;
try log(logger, buf[i..i+1]);
p_max += 1;
}
}
try log(logger, "\n\n");
}
in.close();
while (p < p_max) {
switch (program[p]) {
Token.LeftBracket => {
if (tape[ptr] == 0) {
p = nextBracket(program[0..], p);
}
},
Token.RightBracket => {
if (tape[ptr] != 0) {
p = prevBracket(program[0..], p);
}
},
Token.Add => {
tape[ptr] +%= 1;
},
Token.Sub => {
tape[ptr] -%= 1;
},
Token.Get => {
tape[ptr] = try get();
},
Token.Put => {
try put(tape[ptr .. ptr + 1]);
},
Token.Next => {
ptr += 1;
},
Token.Prev => {
ptr -= 1;
},
else => unreachable,
}
var line_buf: [300]u8 = undefined;
const line = try std.fmt.bufPrint(line_buf[0..], "{} {} {} {}\n", p, @tagName(program[p]), ptr, tape[ptr]);
try log(logger, line);
p += 1;
}
allocator.free(tape);
try log(logger, "Free: tape\n");
allocator.free(program);
try log(logger, "Free: program\n");
logger.close();
}
fn nextBracket(program: []Token, i: u32) u32 {
var tmp: u32 = i;
var stack: u32 = 0;
while (true) {
if (program[tmp] == Token.LeftBracket) {
stack += 1;
}
if (program[tmp] == Token.RightBracket) {
stack -= 1;
}
if (stack == 0 and program[tmp] == Token.RightBracket) {
return tmp;
}
tmp += 1;
}
}
fn prevBracket(program: []Token, i: u32) u32 {
var tmp: u32 = i;
var stack: u32 = 0;
while (true) {
if (program[tmp] == Token.RightBracket) {
stack += 1;
}
if (program[tmp] == Token.LeftBracket) {
stack -= 1;
}
if (stack == 0 and program[tmp] == Token.LeftBracket) {
return tmp;
}
tmp -= 1;
}
}
fn get_token(c: u8) Token {
return switch (c) {
'+' => Token.Add,
'-' => Token.Sub,
',' => Token.Get,
'.' => Token.Put,
'>' => Token.Next,
'<' => Token.Prev,
'[' => Token.LeftBracket,
']' => Token.RightBracket,
else => Token.Invalid,
};
}
fn put(c: []u8) anyerror!void {
var stdout = io.getStdOut() catch |err| {
warn("Failed to get stdout. {}", @errorName(err));
return err;
};
stdout.write(c) catch |err| {
warn("Failed to write to stdout.");
return err;
};
}
fn get() anyerror!u8 {
var buf: [1]u8 = undefined;
var stdin = try io.getStdIn();
_ = try stdin.read(buf[0..1]);
return buf[0];
}
fn log(file: File, msg: []const u8) anyerror!void {
if (logging) {
try file.write(msg);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment