const std = @import("std"); pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}).init; defer _ = gpa.deinit(); const alloc = gpa.allocator(); // Using this for cross-platform suitability const argv = try std.process.argsAlloc(alloc); defer std.process.argsFree(alloc, argv); try stkEval(alloc, argv[1..]); } const eql = std.mem.eql; const parseFloat = std.fmt.parseFloat; const StkEvalError = error{ StackUnderflow, UnrecognizedOperation, }; fn Stack(comptime T: type) type { return struct { const Self = @This(); storage: std.ArrayList(T), alloc: std.mem.Allocator, pub fn init(alloc: std.mem.Allocator) !Self { const list = try std.ArrayList(T).initCapacity(alloc, 8); return Self{ .storage = list, .alloc = alloc, }; } pub fn items(self: Self) []T { return self.storage.items; } pub fn deinit(self: *Self) void { self.storage.deinit(self.alloc); } pub fn pop(self: *Self) StkEvalError!T { return self.storage.pop() orelse StkEvalError.StackUnderflow; } pub fn push(self: *Self, item: T) !void { try self.storage.append(self.alloc, item); } }; } pub fn stkEval(alloc: std.mem.Allocator, tokens: [][:0]u8) !void { var dataStack = try Stack(f64).init(alloc); defer dataStack.deinit(); for (tokens) |token| { if (parseFloat(f64, token) catch null) |num| { try dataStack.push(num); } else if (eql(u8, token, "+")) { const a = try dataStack.pop(); const b = try dataStack.pop(); try dataStack.push(a+b); } else if (eql(u8, token, "-")) { const a = try dataStack.pop(); const b = try dataStack.pop(); try dataStack.push(b-a); } else if (eql(u8, token, "x")) { const a = try dataStack.pop(); const b = try dataStack.pop(); try dataStack.push(a*b); } else if (eql(u8, token, "div")) { const a = try dataStack.pop(); const b = try dataStack.pop(); try dataStack.push(b/a); } else { std.debug.print("UNHANDLED {s}\n", .{token}); return StkEvalError.UnrecognizedOperation; } } for (dataStack.items()) |item| { std.debug.print("{} ", .{item}); } std.debug.print("\n", .{}); }