1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
|
const std = @import("std");
const Allocator = std.mem.Allocator;
const root = @import("root");
const Token = root.Lexer.Token;
const Expr = root.Expr;
const Location = root.Lexer.Location;
pub const Reg = enum(u32) { _ };
pub const Instr = union(enum) {
constant: Constant,
bin_op: BinOp,
const Constant = struct {
dest: Reg,
value: Location,
};
const BinOp = struct {
dest: Reg,
lhs: Reg,
rhs: Reg,
op: Op,
const Op = enum {
add,
};
};
};
pub const Block = struct {
// arguments: []Reg,
instrs: []Instr,
};
pub fn compile(allocator: Allocator, expr: *const Expr) !Block {
const instrs: std.ArrayListUnmanaged(Instr) = try .initCapacity(allocator, 0);
var ctx: CompileContext = .{
.allocator = allocator,
.register_counter = 0,
.instrs = instrs,
};
_ = try ctx.compileExpr(expr);
return .{ .instrs = ctx.instrs.items };
}
const CompileContext = struct {
allocator: Allocator,
register_counter: u32,
instrs: std.ArrayListUnmanaged(Instr),
const Self = @This();
fn addInstr(self: *Self, instr: Instr) !void {
try self.instrs.append(self.allocator, instr);
}
fn compileExpr(self: *Self, expr: *const Expr) !Reg {
const dest = self.register();
switch (expr.type) {
.integer_literal => try addInstr(self, .{
.constant = .{ .dest = dest, .value = expr.loc },
}),
.bin_op => |binop| {
const lhs = try self.compileExpr(binop.lhs);
const rhs = try self.compileExpr(binop.rhs);
try addInstr(self, .{
.bin_op = .{
.dest = dest,
.lhs = lhs,
.rhs = rhs,
.op = switch (binop.op) {
.plus => .add,
},
},
});
},
.invalid => return error.CantCompileInvalidExpr,
}
return dest;
}
fn register(self: *Self) Reg {
const reg: Reg = @enumFromInt(self.register_counter);
self.register_counter += 1;
return reg;
}
};
|