Skip to content

Instantly share code, notes, and snippets.

@alexpana
Last active December 19, 2020 10:26
Show Gist options
  • Save alexpana/e47c462e5a48c0edf3ddc8908d391605 to your computer and use it in GitHub Desktop.
Save alexpana/e47c462e5a48c0edf3ddc8908d391605 to your computer and use it in GitHub Desktop.
const std = @import("std");
// const input = @embedFile("18.test.input");
const Operator = enum {
l_paren,
r_paren,
add,
sub,
mul,
div,
pub fn isOperator(c: u8) bool {
return switch (c) {
'(', ')', '+', '-', '*', '/' => true,
else => false,
};
}
pub fn fromChar(c: u8) Operator {
return switch (c) {
'(' => Operator.l_paren,
')' => Operator.r_paren,
'+' => Operator.add,
'-' => Operator.sub,
'*' => Operator.mul,
'/' => Operator.div,
else => @panic("Unknown character"),
};
}
pub fn evaluate(self: Operator, a: i64, b: i64) i64 {
return switch (self) {
Operator.add => a + b,
Operator.sub => a - b,
Operator.mul => a * b,
Operator.div => @divFloor(a, b),
else => @panic("Cannot evaluate parenthesis operators"),
};
}
};
test "Operator evaluation" {
std.testing.expect(Operator.fromChar('*').evaluate(2, 3) == 6);
std.testing.expect(Operator.fromChar('/').evaluate(8, 4) == 2);
std.testing.expect(Operator.fromChar('+').evaluate(5, 5) == 10);
}
pub const TokenIterator = struct {
buffer: []const u8,
index: ?usize,
/// Returns a slice of the next token, or null if splitting is complete.
pub fn next(self: *TokenIterator) ?[]const u8 {
// Return null (end of iteration) if our index is null
const start = self.index orelse return null;
var index = start;
var result: []const u8 = undefined;
if (Operator.isOperator(self.buffer[index])) {
index += 1;
} else {
while (index < self.buffer.len and '0' <= self.buffer[index] and self.buffer[index] <= '9') {
index += 1;
}
}
result = self.buffer[start..index];
// skip whitespace
while (index < self.buffer.len and self.buffer[index] == ' ') {
index += 1;
}
// std.debug.print("{}\n", .{index});
if (index == self.buffer.len) {
self.index = null;
} else {
self.index = index;
}
return result;
}
};
pub fn tokenize(buffer: []const u8) TokenIterator {
return TokenIterator{
.buffer = buffer,
.index = 0,
};
}
pub fn Stack(comptime T: type, comptime size: u32) type {
return struct {
items: [size]?T,
tip: u32,
const Self = @This();
pub fn init() Self {
return Self{
.items = [1]?T{null} ** size,
.tip = 0,
};
}
pub fn front(self: *Self) ?T {
return if (self.tip > 0) self.items[self.tip - 1].? else null;
}
pub fn pop(self: *Self) ?T {
var result = self.front();
if (self.tip > 0) {
self.tip -= 1;
}
return result;
}
pub fn isEmpty(self: *Self) bool {
return self.tip == 0;
}
pub fn push(self: *Self, item: T) void {
self.items[self.tip] = item;
self.tip += 1;
}
};
}
test "Stack" {
const expect = std.testing.expect;
var s = Stack(i64, 32).init();
expect(s.isEmpty() == true);
expect(s.front() == null);
s.push(64);
expect(s.isEmpty() == false);
expect(s.front().? == 64);
s.pop();
expect(s.isEmpty() == true);
expect(s.front() == null);
s.pop();
s.pop();
}
pub fn main() !void {
var expression = "1 + 2 * (54+324)";
var terms = Stack(i64, 32).init();
var ops = Stack(Operator, 32).init();
var it = tokenize(expression);
while (it.next()) |token| {
if (Operator.isOperator(token[0])) {
while (!ops.isEmpty() and ops.front() != Operator.l_paren) {
var a = terms.pop().?;
var b = terms.pop().?;
var op = ops.pop().?;
terms.push(op.evaluate(a, b));
}
ops.push(Operator.fromChar(token[0]));
} else {
terms.push(try std.fmt.parseInt(i64, token, 10));
}
std.debug.print("{}\n", .{token});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment