assign and seq
This commit is contained in:
parent
47606bd082
commit
39199f4a0d
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
Loading…
Reference in a new issue