A => Makefile +4 -0
@@ 0,0 1,4 @@
+.PHONY: test
+
+test: rpn.zig stack.zig
+ zig test rpn.zig
A => rpn.py +57 -0
@@ 0,0 1,57 @@
+#!/usr/bin/env python3
+
+import sys
+
+
+def str2float(str):
+ try:
+ return float(str)
+ except ValueError:
+ return None
+
+
+ops = {
+ "+": lambda a, b: a + b,
+ "-": lambda a, b: a - b,
+ "*": lambda a, b: a * b,
+ "/": lambda a, b: a / b,
+}
+
+
+def rpn(cmd, vals):
+ val = str2float(cmd)
+ if val is not None:
+ vals.append(val)
+ return None
+ op = ops[cmd]
+ b = vals.pop()
+ a = vals.pop()
+ vals.append(op(a, b))
+ return vals[-1]
+
+
+def repl():
+ vals = []
+ while True:
+ try:
+ line = input()
+ except EOFError:
+ return
+ val = rpn(line, vals)
+ print(line, vals, file=sys.stderr)
+ if val is not None:
+ print(val)
+
+
+def cli():
+ vals = []
+ for cmd in sys.argv[1:]: # Note that your shell might need to escape '*'
+ rpn(cmd, vals)
+ print(vals.pop())
+
+
+if __name__ == "__main__":
+ if len(sys.argv) > 1:
+ cli()
+ else:
+ repl()
A => rpn.zig +61 -0
@@ 0,0 1,61 @@
+const std = @import("std");
+const Stack = @import("stack.zig").Stack;
+
+fn str2f64(s: []const u8) ?f64 {
+ return std.fmt.parseFloat(f64, s) catch return null;
+}
+
+fn add(a: f64, b: f64) f64 {
+ return a + b;
+}
+
+fn sub(a: f64, b: f64) f64 {
+ return a - b;
+}
+
+fn mul(a: f64, b: f64) f64 {
+ return a * b;
+}
+
+fn div(a: f64, b: f64) f64 {
+ return a / b;
+}
+
+fn rpn(cmd: []const u8, vals: *Stack) !?f64 {
+ if (str2f64(cmd)) |val| {
+ try vals.push(val);
+ return null;
+ }
+
+ const b = vals.pop().?;
+ const a = vals.pop().?;
+
+ var result = switch (cmd[0]) {
+ '+' => add(a, b),
+ '-' => sub(a, b),
+ '*' => mul(a, b),
+ '/' => div(a, b),
+ else => return error.BadOp,
+ };
+
+ try vals.push(result);
+ return vals.peek();
+}
+
+const testing = std.testing;
+const alloc = std.testing.allocator;
+
+test "Reverse some polish notations." {
+ var stack: Stack = Stack.init(alloc);
+ defer stack.deinit();
+
+ try testing.expectEqual(@as(?f64, null), try rpn("3.5", &stack));
+ try testing.expectEqual(@as(?f64, null), try rpn("5.5", &stack));
+ try testing.expectEqual(@as(?f64, 9.0), try rpn("+", &stack));
+ try testing.expectEqual(@as(?f64, null), try rpn("83", &stack));
+ try testing.expectEqual(@as(?f64, null), try rpn("3", &stack));
+ _ = try rpn("/", &stack);
+ try testing.expectEqual(@as(?f64, 249.0), try rpn("*", &stack));
+ try testing.expectEqual(@as(?f64, null), try rpn("49", &stack));
+ try testing.expectEqual(@as(?f64, 200.0), try rpn("-", &stack));
+}
A => stack.zig +63 -0
@@ 0,0 1,63 @@
+const std = @import("std");
+const Allocator = std.mem.Allocator;
+
+pub const Stack = struct {
+ const Self = @This();
+
+ pub const Node = struct {
+ next: ?*Node = null,
+ data: f64,
+ };
+
+ head: ?*Node = null,
+ allocator: Allocator,
+
+ pub fn push(self: *Self, val: f64) !void {
+ const next: ?*Node = self.head;
+ var new: *Node = try self.allocator.create(Node);
+ new.next = next;
+ new.data = val;
+ self.head = new;
+ }
+
+ pub fn pop(self: *Self) ?f64 {
+ var popped: *Node = self.head orelse return null;
+ defer self.allocator.destroy(popped);
+ self.head = popped.next;
+ return popped.data;
+ }
+
+ pub fn peek(self: *Self) ?f64 {
+ var next: *Node = self.head orelse return null;
+ return next.data;
+ }
+
+ pub fn init(allocator: Allocator) Self {
+ return Self{
+ .head = null,
+ .allocator = allocator,
+ };
+ }
+
+ pub fn deinit(self: *Self) void {
+ while (self.pop()) |_| {}
+ }
+};
+
+const testing = std.testing;
+const alloc = std.testing.allocator;
+
+test "Create, push, pop" {
+ var stack: Stack = Stack.init(alloc);
+ try std.testing.expectEqual(@as(?f64, null), stack.peek());
+ try std.testing.expectEqual(@as(?f64, null), stack.pop());
+ try stack.push(2.5);
+ try std.testing.expectEqual(@as(?f64, 2.5), stack.peek());
+ try stack.push(3.5);
+ try std.testing.expectEqual(@as(?f64, 3.5), stack.peek());
+ try std.testing.expectEqual(@as(?f64, 3.5), stack.pop());
+ try std.testing.expectEqual(@as(?f64, 2.5), stack.peek());
+ try std.testing.expectEqual(@as(?f64, 2.5), stack.pop());
+ try std.testing.expectEqual(@as(?f64, null), stack.peek());
+ try std.testing.expectEqual(@as(?f64, null), stack.pop());
+}