diff --git a/src/frontend/parse.zig b/src/frontend/parse.zig index 1524b42..a789996 100644 --- a/src/frontend/parse.zig +++ b/src/frontend/parse.zig @@ -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 { diff --git a/src/interp/compile.zig b/src/interp/compile.zig index 1cc25a7..3e99f98 100644 --- a/src/interp/compile.zig +++ b/src/interp/compile.zig @@ -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,56 @@ 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.append(src, 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 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,7 +129,7 @@ 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 = {} }); return code.finalize();