diff options
| author | Nic Gaffney <gaffney_nic@protonmail.com> | 2024-07-28 01:33:19 -0500 | 
|---|---|---|
| committer | Nic Gaffney <gaffney_nic@protonmail.com> | 2024-07-28 01:33:19 -0500 | 
| commit | e5d311f91ecda870c8e50d3f9c860b99e244a908 (patch) | |
| tree | fbd3d8e2a0989522550c11cab56e89d6a211c0b1 | |
| parent | 46e8f2f827bf176a5e480ac9ff96806ced594bde (diff) | |
| download | calico-e5d311f91ecda870c8e50d3f9c860b99e244a908.tar.gz | |
Added const, var, and assigning variables.
| -rw-r--r-- | examples/test1.gft | 5 | ||||
| -rw-r--r-- | src/codegen.zig | 103 | ||||
| -rw-r--r-- | src/main.zig | 3 | ||||
| -rw-r--r-- | src/parser.zig | 33 | ||||
| -rw-r--r-- | src/tokenize.zig | 56 | 
5 files changed, 179 insertions, 21 deletions
| diff --git a/examples/test1.gft b/examples/test1.gft index ae83590..bfaed74 100644 --- a/examples/test1.gft +++ b/examples/test1.gft @@ -1 +1,4 @@ -exit 7; +const x = 1; +var y = 4; +y = 3; +exit y; diff --git a/src/codegen.zig b/src/codegen.zig index a200e23..98501c2 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -18,35 +18,106 @@ pub const Generator = struct {          self.code.deinit();      } -    fn genExit(self: *Generator, expr: parse.NodeExpr) ![]const u8 { -        return try std.fmt.allocPrint(self.allocator, -            \\  mov rax, 60 -            \\  mov rdi, {d} -            \\  syscall +    fn genExit(self: *Generator, expr: parse.NodeExpr) !void { +        const newCode = +            switch (expr) { +            .intLit => try std.fmt.allocPrint(self.allocator, +                \\  mov rax, 60 +                \\  mov rdi, {d} +                \\  syscall +                \\ +            , .{ +                expr.intLit.intlit.intLit, +            }), +            .ident => try std.fmt.allocPrint(self.allocator, +                \\  mov rax, 60 +                \\  mov rdi, [{s}] +                \\  syscall +                \\ +            , .{ +                expr.ident.ident.ident, +            }), +        }; +        try self.code.appendSlice(newCode); +        self.allocator.free(newCode); +    } + +    fn genValue(self: *Generator, value: parse.NodeValue) !void { +        const str = try std.fmt.allocPrint(self.allocator, +            \\section .data +            \\  {s}: dw {d}              \\ -        , .{switch (expr) { -            .intLit => expr.intLit.intlit.intLit, +        , .{ value.ident.ident, switch (value.value) { +            .intLit => value.value.intLit.intlit.intLit,              else => return error.NotImplemented, -        }}); +        } }); +        defer self.allocator.free(str); +        try self.code.insertSlice(0, str);      } -    fn genValue(self: *Generator) ![]const u8 { -        _ = self; -        return error.NotImplemented; +    fn genAssign(self: *Generator, assign: parse.NodeAssign) !void { +        const newCode = +            switch (assign.value) { +            .intLit => try std.fmt.allocPrint(self.allocator, +                \\  mov rax, {d} +                \\  mov [{s}], rax +                \\ +            , .{ +                assign.value.intLit.intlit.intLit, +                assign.ident.ident, +            }), +            .ident => try std.fmt.allocPrint(self.allocator, +                \\  mov rax, [{s}] +                \\  mov [{s}], rax +                \\ +            , .{ +                assign.value.ident.ident.ident, +                assign.ident.ident, +            }), +        }; +        try self.code.appendSlice(newCode); +        self.allocator.free(newCode);      }      pub fn generate(self: *Generator) ![]const u8 {          try self.code.appendSlice( -            \\global _start: +            \\section .text +            \\  global _start +            \\_start:              \\          );          for (self.root) |stmt| { -            const code = switch (stmt) { +            switch (stmt) {                  .exit => try self.genExit(stmt.exit.expr), -                .value => try self.genValue(), -            }; -            try self.code.appendSlice(code); +                .value => try self.genValue(stmt.value), +                .assign => try self.genAssign(stmt.assign), +            }          }          return self.code.items;      }  }; + +test "Codegen exit" { +    const tok = @import("tokenize.zig"); +    const expect = std.testing.expect; +    const src = "exit 120;"; +    var tokenizer = tok.Tokenizer.init(std.testing.allocator, src); +    defer tokenizer.deinit(); +    const toks = try tokenizer.tokenize(); +    var parser = parse.Parser.init(std.testing.allocator, toks); +    defer parser.deinit(); +    const parseTree = try parser.parse(); +    var gen = Generator.init(std.testing.allocator, parseTree); +    defer gen.deinit(); +    const actual = try gen.generate(); +    const expected = +        \\section .text +        \\  global _start +        \\_start: +        \\  mov rax, 60 +        \\  mov rdi, 120 +        \\  syscall +        \\ +    ; +    try expect(std.mem.eql(u8, actual, expected)); +} diff --git a/src/main.zig b/src/main.zig index cdf5a38..14bcfad 100644 --- a/src/main.zig +++ b/src/main.zig @@ -52,9 +52,8 @@ pub fn main() !void {      // Codegen      var generator = gen.Generator.init(allocator, tree); +    defer generator.deinit();      const code = try generator.generate(); -    std.debug.print("{s}", .{code}); -    defer allocator.free(code);      try outWriter.writeAll(code);      // Run nasm and ld to build the executable diff --git a/src/parser.zig b/src/parser.zig index 18b2348..df0f068 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -20,6 +20,12 @@ pub const NodeExpr = union(enum) {  pub const NodeStmt = union(enum) {      exit: NodeExit,      value: NodeValue, +    assign: NodeAssign, +}; + +pub const NodeAssign = struct { +    ident: Token, +    value: NodeExpr,  };  pub const NodeValue = struct { @@ -78,10 +84,37 @@ pub const Parser = struct {              .exit => NodeStmt{ .exit = try self.parseExit() },              .constant => NodeStmt{ .value = try self.parseValue(true) },              .variable => NodeStmt{ .value = try self.parseValue(false) }, +            .ident => NodeStmt{ .assign = try self.parseAssign() },              else => ParsingError.InvalidStatement,          };      } +    fn parseAssign(self: *Parser) !NodeAssign { +        const ident = try self.tokens.consume(.ident); +        var isMutable = false; +        var exists = false; +        for (self.nodes.items) |item| { +            switch (item) { +                .value => |v| { +                    if (std.mem.eql(u8, v.ident.ident, ident.?.ident)) { +                        isMutable = !v.isConst; +                        exists = true; +                    } +                }, +                else => {}, +            } +        } +        if (!exists) return error.UnknownIdentifier; +        if (!isMutable) return error.ImmutableValue; +        _ = try self.tokens.consume(.equal); +        const expr = try self.parseExpr(); +        _ = try self.tokens.consume(.semiCol); +        return NodeAssign{ +            .ident = ident.?, +            .value = expr, +        }; +    } +      fn parseExit(self: *Parser) !NodeExit {          _ = try self.tokens.consume(.exit);          const expr = try self.parseExpr(); diff --git a/src/tokenize.zig b/src/tokenize.zig index c78a59b..ad263c2 100644 --- a/src/tokenize.zig +++ b/src/tokenize.zig @@ -159,9 +159,9 @@ pub const Tokenizer = struct {      }  }; -test "Tokenize" { +test "Tokenize Expression" {      const expect = std.testing.expect; -    const testSource: []const u8 = "exit 120 + 150 - 260 * 12 / 5;"; +    const testSource: []const u8 = "exit 120 + 150 - 260 * 12 / 5 + variable;";      var tokenizer = Tokenizer.init(std.testing.allocator, testSource);      defer tokenizer.deinit();      const tokens = try tokenizer.tokenize(); @@ -176,6 +176,8 @@ test "Tokenize" {          .{ .intLit = 12 },          .slash,          .{ .intLit = 5 }, +        .plus, +        .{ .ident = "variable" },          .semiCol,      };      for (tokens, expected) |act, exp| { @@ -187,6 +189,56 @@ test "Tokenize" {              .minus => |v| try expect(v == exp.minus),              .star => |v| try expect(v == exp.star),              .slash => |v| try expect(v == exp.slash), +            .ident => |v| try expect(std.mem.eql(u8, v, exp.ident)), +            else => try expect(1 == 0), +        } +    } +} + +test "Tokenize variable" { +    const expect = std.testing.expect; +    const testSource: []const u8 = "var five = 5;"; +    var tokenizer = Tokenizer.init(std.testing.allocator, testSource); +    defer tokenizer.deinit(); +    const tokens = try tokenizer.tokenize(); +    const expected = &[_]Token{ +        .variable, +        .{ .ident = "five" }, +        .equal, +        .{ .intLit = 5 }, +        .semiCol, +    }; +    for (tokens, expected) |act, exp| { +        switch (act) { +            .variable => |v| try expect(v == exp.variable), +            .ident => |v| try expect(std.mem.eql(u8, exp.ident, v)), +            .equal => |v| try expect(v == exp.equal), +            .intLit => |v| try expect(v == exp.intLit), +            .semiCol => |v| try expect(v == exp.semiCol), +            else => try expect(1 == 0), +        } +    } +} +test "Tokenize constant" { +    const expect = std.testing.expect; +    const testSource: []const u8 = "const five = 5;"; +    var tokenizer = Tokenizer.init(std.testing.allocator, testSource); +    defer tokenizer.deinit(); +    const tokens = try tokenizer.tokenize(); +    const expected = &[_]Token{ +        .constant, +        .{ .ident = "five" }, +        .equal, +        .{ .intLit = 5 }, +        .semiCol, +    }; +    for (tokens, expected) |act, exp| { +        switch (act) { +            .constant => |v| try expect(v == exp.constant), +            .ident => |v| try expect(std.mem.eql(u8, exp.ident, v)), +            .equal => |v| try expect(v == exp.equal), +            .intLit => |v| try expect(v == exp.intLit), +            .semiCol => |v| try expect(v == exp.semiCol),              else => try expect(1 == 0),          }      } | 
