Compare commits

...

3 commits

Author SHA1 Message Date
caandt e6ef9e16d7 fmt 2025-06-09 23:33:50 -05:00
caandt da4484d4f5 clean stack 2025-06-09 23:33:42 -05:00
caandt 39199f4a0d assign and seq 2025-06-09 23:30:02 -05:00
2 changed files with 78 additions and 13 deletions

View file

@ -7,6 +7,8 @@ const op_kind = token.op_kind;
pub const Expr = union(enum) {
binop: struct { lhs: *const Expr, rhs: *const Expr, op: Token },
unop: struct { expr: *const Expr, op: Token },
assign: struct { lhs: *const Expr, rhs: *const Expr },
seq: struct { a: *const Expr, b: *const Expr },
atom: Token,
pub fn eval(self: *const Expr, src: []const u8) i64 {
return switch (self.*) {
@ -69,6 +71,17 @@ fn infix_binop(parser: *Parser, precedence: u32, lhs: *const Expr, tok: Token) E
const rhs = try parser.parse_expr(precedence);
return try parser.make_expr(.{ .binop = .{ .lhs = lhs, .rhs = rhs, .op = tok } });
}
fn infix_seq(parser: *Parser, precedence: u32, lhs: *const Expr, _: Token) Error!*const Expr {
const rhs = try parser.parse_expr(precedence);
return try parser.make_expr(.{ .seq = .{ .a = lhs, .b = rhs } });
}
fn infix_assign(parser: *Parser, precedence: u32, lhs: *const Expr, tok: Token) Error!*const Expr {
var rhs = try parser.parse_expr(precedence);
if (tok.kind != op_kind("=")) {
rhs = try parser.make_expr(.{ .binop = .{ .lhs = lhs, .rhs = rhs, .op = tok } });
}
return try parser.make_expr(.{ .assign = .{ .lhs = lhs, .rhs = rhs } });
}
pub const Parser = struct {
tokenizer: token.Tokenizer,
@ -106,21 +119,28 @@ pub const Parser = struct {
op_p.value_ptr.parse_infix = infix_binop;
op_p.value_ptr.infix_precedence = precedence;
}
fn register_assign(self: *Parser, op: []const u8) Error!void {
const op_p = try self.ops.getOrPutValue(op_kind(op), .{});
op_p.value_ptr.parse_infix = infix_assign;
op_p.value_ptr.infix_precedence = 2;
}
pub fn init(allocator: std.mem.Allocator) Error!Parser {
const ops = std.AutoHashMap(TokenKind, Operator).init(allocator);
var p = Parser{ .tokenizer = undefined, .allocator = allocator, .ops = ops };
try p.ops.put(TokenKind.name, .{ .parse_prefix = prefix_atom });
try p.ops.put(TokenKind.number, .{ .parse_prefix = prefix_atom });
try p.ops.put(TokenKind.semicolon, .{ .parse_infix = infix_seq, .infix_precedence = 1 });
try p.ops.put(op_kind("("), .{ .parse_prefix = prefix_paren });
try p.ops.put(op_kind(")"), .{});
try p.register_unop("+", 4);
try p.register_unop("-", 4);
try p.register_assign("=");
try p.register_unop("+", 5);
try p.register_unop("-", 5);
try p.register_binop("+", 2);
try p.register_binop("-", 2);
try p.register_binop("*", 3);
try p.register_binop("/", 3);
try p.register_binop("+", 3);
try p.register_binop("-", 3);
try p.register_binop("*", 4);
try p.register_binop("/", 4);
return p;
}
pub fn free(self: *Parser) void {

View file

@ -45,9 +45,9 @@ pub const sz_inst = union(enum) {
if (@TypeOf(n) == void) {
try writer.print("[{s}]", .{@tagName(value)});
} else {
try writer.print("[{s} {}]", .{@tagName(value), n});
try writer.print("[{s} {}]", .{ @tagName(value), n });
}
}
},
}
}
};
@ -60,6 +60,7 @@ const sz_code_tmp = struct {
consts: std.ArrayList(sz_obj),
vars: std.ArrayList(sz_obj),
bc: std.ArrayList(sz_inst),
name: std.StringHashMap(usize),
fn finalize(self: *sz_code_tmp) !sz_code {
return sz_code{
.consts = try self.consts.toOwnedSlice(),
@ -71,20 +72,64 @@ const sz_code_tmp = struct {
switch (expr.*) {
.atom => |a| {
switch (a.kind) {
.number => try self.consts.append(.{ .obj = @bitCast(std.fmt.parseInt(isize, src[a.start..a.end], 0) catch 0) }),
else => unreachable,
.number => {
try self.consts.append(.{ .obj = @bitCast(std.fmt.parseInt(isize, src[a.start..a.end], 0) catch 0) });
try self.bc.append(.{ .push_const = @truncate(self.consts.items.len - 1) });
},
.name => {
const name = src[a.start..a.end];
const i = try self.name.getOrPutValue(name, self.vars.items.len);
if (self.vars.items.len == i.value_ptr.*) {
try self.vars.append(.{ .tag = .err });
}
try self.bc.append(.{ .push_var = @truncate(i.value_ptr.*) });
},
else => return error.SyntaxError,
}
try self.bc.append(.{ .push_const = @truncate(self.consts.items.len - 1) });
},
.binop => |b| {
try self.append(src, b.lhs);
try self.append(src, b.rhs);
try self.bc.append(.{ .binop = @intFromEnum(b.op.kind) });
},
.seq => |s| {
try self.append(src, s.a);
try self.clean_stack(s.a);
try self.append(src, s.b);
try self.clean_stack(s.b);
},
.unop => |u| {
try self.append(src, u.expr);
try self.bc.append(.{ .unop = @intFromEnum(u.op.kind) });
},
.assign => |a| {
try self.append(src, a.rhs);
try self.append_assign(src, a.lhs);
},
}
}
fn clean_stack(self: *sz_code_tmp, expr: *const Expr) !void {
switch (expr.*) {
.atom, .binop, .unop => try self.bc.append(.{ .pop = {} }),
else => {},
}
}
fn append_assign(self: *sz_code_tmp, src: []const u8, expr: *const Expr) !void {
switch (expr.*) {
.atom => |a| {
switch (a.kind) {
.name => {
const name = src[a.start..a.end];
const i = try self.name.getOrPutValue(name, self.vars.items.len);
if (self.vars.items.len == i.value_ptr.*) {
try self.vars.append(.{ .tag = .err });
}
try self.bc.append(.{ .pop_var = @truncate(i.value_ptr.*) });
},
else => return error.SyntaxError,
}
},
else => return error.SyntaxError,
}
}
};
@ -92,8 +137,8 @@ const sz_code_tmp = struct {
pub fn compile(allocator: std.mem.Allocator, src: []const u8) !sz_code {
var p = try parse.Parser.init(allocator);
const expr = try p.parse(src);
var code = sz_code_tmp{ .consts = std.ArrayList(sz_obj).init(allocator), .vars = std.ArrayList(sz_obj).init(allocator), .bc = std.ArrayList(sz_inst).init(allocator) };
var code = sz_code_tmp{ .consts = std.ArrayList(sz_obj).init(allocator), .vars = std.ArrayList(sz_obj).init(allocator), .bc = std.ArrayList(sz_inst).init(allocator), .name = std.StringHashMap(usize).init(allocator) };
try code.append(src, expr);
try code.bc.append(.{ .pop = {} });
try code.clean_stack(expr);
return code.finalize();
}