const std = @import("std");
const Allocator = std.mem.Allocator;
const Scanner = @import("Scanner.zig");
+const Token = @import("Token.zig");
+const Parser = @import("Parser.zig");
+const ast_printer = @import("ast_printer.zig");
var hadError = false;
}
fn run(allocator: Allocator, source: []const u8) !void {
- var scanner = Scanner.init(source);
- const tokens = try scanner.scanTokens(allocator);
+ var scanner = Scanner.init(allocator, source);
+ const tokens = try scanner.scanTokens();
defer allocator.free(tokens);
+ var parser = try Parser.init(allocator, tokens);
+ defer parser.deinit();
+ const expression = try parser.parse();
- // For now, just print the tokens.
- for (tokens) |token| {
- std.debug.print("{f}\n", .{token});
- }
+ // Stop if there was a syntax error.
+ if (hadError) return;
+
+ const printed = try ast_printer.print(allocator, expression.?);
+ defer allocator.free(printed);
+ std.debug.print("{s}\n", .{printed});
}
-pub fn @"error"(line: u32, message: []const u8) !void {
+pub fn scanError(line: u32, message: []const u8) !void {
try report(line, "", message);
}
try stderr.flush();
hadError = true;
}
+
+pub fn parseError(allocator: Allocator, token: Token, message: []const u8) !void {
+ if (token.type == .eof) {
+ try report(token.line, " at end", message);
+ } else {
+ try report(token.line, try std.fmt.allocPrint(allocator, " at '{s}'", .{token.lexeme}), message);
+ }
+}