This tutorial will guide you through creating a simple command-line calculator using Zig programming language. We'll cover installation, project setup, implementation, and testing.
Table of Contents
Installing Zig
- Visit ziglang.org/download
- Download the appropriate version for your operating system (0.11.0 or later)
- Extract the archive to a location of your choice
-
Add Zig to your system's PATH:
- Windows: Edit system environment variables and add the path to Zig
- Linux/MacOS: Add to ~/.bashrc or ~/.zshrc:
export PATH=$PATH:/path/to/zig
Verify installation:
zig version
Project Setup
- Create a new project directory:
mkdir calculator
cd calculator
- Initialize the project structure:
mkdir src
touch src/calculator.zig
touch src/calculator_test.zig
- Create a build.zig file:
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const exe = b.addExecutable(.{
.name = "calculator",
.root_source_file = b.path("src/calculator.zig"),
.target = target,
.optimize = optimize,
});
b.installArtifact(exe);
const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(b.getInstallStep());
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
const exe_unit_tests = b.addTest(.{
.root_source_file = b.path("src/calculator_test.zig"),
.target = target,
.optimize = optimize,
});
const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);
const test_step = b.step("test", "Run unit tests");
test_step.dependOn(&run_exe_unit_tests.step);
}
Understanding the Code
1. Calculator Implementation (src/calculator.zig)
The calculator consists of two main parts:
a) The calculate function:
pub fn calculate(num1: f64, num2: f64, op: u8) !f64 {
return switch (op) {
'+' => num1 + num2,
'-' => num1 - num2,
'*' => num1 * num2,
'/' => if (num2 == 0) {
return error.DivisionByZero;
} else num1 / num2,
'%' => @mod(num1, num2),
else => error.InvalidOperation,
};
}
This function:
- Takes two numbers and an operation as input
- Uses a switch statement to perform the calculation
- Handles errors like division by zero
- Returns the result as a f64 (double-precision float)
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
const stdin = std.io.getStdIn().reader();
while (true) {
try stdout.writeAll("\nCalculator (enter 'q' to quit)\n");
try stdout.writeAll("Enter first number: ");
var first_input_buffer: [16]u8 = undefined;
const first_input = try stdin.readUntilDelimiter(&first_input_buffer, '\n');
if (first_input.len == 1 and first_input[0] == 'q') break;
const num1 = try std.fmt.parseFloat(f64, first_input);
try stdout.writeAll("Enter operation (+, -, *, /): ");
var op_buffer: [16]u8 = undefined;
const op = try stdin.readUntilDelimiter(&op_buffer, '\n');
if (op.len == 0) {
try stdout.writeAll("Error: No operation entered!\n");
continue;
}
try stdout.writeAll("Enter second number: ");
var second_input_buffer: [16]u8 = undefined;
const num2 = try std.fmt.parseFloat(f64, try stdin.readUntilDelimiter(&second_input_buffer, '\n'));
const result = calculate(num1, num2, op[0]) catch |err| {
switch (err) {
error.DivisionByZero => try stdout.writeAll("Error: Division by zero!\n"),
error.InvalidOperation => try stdout.print("Error: Invalid operation '{s}'!\n", .{op}),
else => return err,
}
continue;
};
try stdout.print("Result: {d}\n", .{result});
}
}
b) The main function:
- Creates an interactive command-line interface
- Reads user input for numbers and operations
- Handles errors and displays results
- Provides a quit option ('q')
2. Testing (src/calculator_test.zig)
Tests are written using Zig's built-in testing framework:
test "basic addition" {
const result = try calculator.calculate(5, 3, '+');
try testing.expectEqual(@as(f64, 8), result);
}
Key testing concepts:
- Each test is a function marked with the
test
keyword - Use
try
for error handling - Use
testing.expectEqual()
for assertions
Building and Running
- Build the project:
zig build
- Run the calculator:
zig build run
- Using the calculator:
Calculator (enter 'q' to quit)
Enter first number: 10
Enter operation (+, -, *, /): +
Enter second number: 5
Result: 15
Testing
Run the test suite:
zig build test
The tests will verify:
- Basic arithmetic operations
- Error handling for division by zero
- Invalid operation handling
- Edge cases
Common Issues
- Compilation Errors
- Ensure Zig version 0.11.0 or later
- Check file paths in build.zig
- Verify syntax, especially in error handling
- Runtime Errors
- Division by zero is handled with error.DivisionByZero
- Invalid operations return error.InvalidOperation
- Input parsing errors are caught and handled
-
Build Issues
- Make sure build.zig is in the root directory
- Verify project structure matches the tutorial
- Check that all source files are present
Next Steps
To enhance the calculator, consider:
- Adding more operations (power, square root)
- Implementing memory functions
- Supporting complex numbers
- Adding a graphical user interface
- Implementing scientific calculator features
Resources
Conclusion
You've now built a functional command-line calculator in Zig! This project demonstrates:
- Basic Zig syntax and features
- Error handling
- Testing
- Command-line I/O
- Project organization
Keep exploring Zig's features and build upon this foundation to create more complex applications!
Find me on X and Discord @augusthottie
Top comments (1)
In future when If I will be doing stuff with Zig, I will make sure to follow through properly. Weldone!