Last active
December 19, 2020 10:26
-
-
Save alexpana/e47c462e5a48c0edf3ddc8908d391605 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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