const std = @import("std"); const scanners = @import("scanners.zig"); const parsers = @import("parsers.zig"); const printer = @import("ast_printer.zig"); const codegen = @import("codegen.zig"); const analysis = @import("analysis.zig"); pub const Result = enum { Ok, TokenizeError, ParseError, CompileError, }; pub fn run(allocator: *std.mem.Allocator, slice: []const u8) !Result { var scan = scanners.Scanner.init(allocator, slice); // do a full scan pass, then reset, then do it again (with parser) while (true) { var tok_opt = scan.nextToken() catch |err| { std.debug.warn( "error at '{}': {}\n", scan.currentLexeme(), err, ); return Result.TokenizeError; }; if (tok_opt) |tok| { if (tok.typ == .EOF) break; // TODO remove std.debug.warn("{x}\n", tok); } } scan.reset(); var parser = parsers.Parser.init(allocator, &scan); var root_opt = try parser.parse(); if (root_opt == null) { return Result.ParseError; } var root = root_opt.?; std.debug.warn("parse tree\n"); printer.printNode(root, 0); var solver = try analysis.TypeSolver.init(allocator); var ctx = try solver.pass(root); std.debug.warn("symbol table\n"); printer.printContext(ctx); var cgen = codegen.Codegen.init(allocator, &ctx); try cgen.gen(root); var child = try std.ChildProcess.init( [_][]const u8{ "gcc", "src/entry.c", "outpath.o", "-o", "a.out" }, allocator, ); try child.spawn(); _ = try child.wait(); return Result.Ok; } pub fn main() anyerror!void { const allocator = std.heap.direct_allocator; var args_it = std.process.args(); _ = args_it.skip(); const filepath = try (args_it.next(allocator) orelse @panic("expected file path")); var file = try std.fs.File.openRead(filepath); defer file.close(); const total_bytes = try file.getEndPos(); var slice = try allocator.alloc(u8, total_bytes); defer allocator.free(slice); _ = try file.read(slice); const result = try run(allocator, slice); switch (result) { .Ok => std.os.exit(0), .TokenizeError, .ParseError, .CompileError, => { std.debug.warn("error: {}\n", result); std.os.exit(1); }, } }