From d4ec81f8453ecc5ded0d2c2843c952ab27d19642 Mon Sep 17 00:00:00 2001 From: Baitinq Date: Tue, 1 Apr 2025 23:46:55 +0200 Subject: Feature: Start adding support for assigning to pointers with arithmetic --- examples/18.src | 10 ++++----- grammar.ebnf | 2 +- src/codegen.zig | 64 ++++++++++++++++++++++++++++++++------------------------- src/parser.zig | 25 ++++++++++++++-------- 4 files changed, 58 insertions(+), 43 deletions(-) diff --git a/examples/18.src b/examples/18.src index 90234c4..6d75e30 100644 --- a/examples/18.src +++ b/examples/18.src @@ -4,13 +4,13 @@ extern free = (*i64) => void; let main = () => i64 { let x = malloc(128); - /* - *(x+0) = 10; - *(x+8) = 20; - */ + (*(x+0)) = 10; + (*(x+1)) = 20; + (*(x+2)) = 40; printf("%p\n", x); - printf("%d\n", *x); + printf("%d\n", *(x+0)); printf("%d\n", *(x+1)); + printf("%d\n", *(x+2)); free(x); return 0; }; diff --git a/grammar.ebnf b/grammar.ebnf index 85d824d..f421d28 100644 --- a/grammar.ebnf +++ b/grammar.ebnf @@ -2,7 +2,7 @@ Program ::= Statement+ Statement ::= (AssignmentStatement | ExternDeclaration | FunctionCallStatement | IfStatement | WhileStatement | ReturnStatement) SEMICOLON -AssignmentStatement ::= ("let")? ("*")? IDENTIFIER EQUALS Expression +AssignmentStatement ::= ("let")? ("*")? Expression EQUALS Expression ExternDeclaration ::= "extern" IDENTIFIER EQUALS Type diff --git a/src/codegen.zig b/src/codegen.zig index 553de77..d6b3e98 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -123,40 +123,48 @@ pub const CodeGen = struct { fn generate_assignment_statement(self: *CodeGen, statement: *parser.Node) CodeGenError!void { errdefer std.debug.print("Error generating assignment statement\n", .{}); std.debug.assert(statement.* == parser.Node.ASSIGNMENT_STATEMENT); - const assignment_statement = statement.ASSIGNMENT_STATEMENT; - if (assignment_statement.is_declaration and self.environment.scope_stack.items.len > 1) { - std.debug.assert(assignment_statement.is_dereference == false); - // TODO: vv Int64Type is a problem - const alloca = llvm.LLVMBuildAlloca(self.builder, llvm.LLVMInt64Type(), try std.fmt.allocPrintZ(self.arena, "{s}", .{assignment_statement.name})); //TODO: Correct type - try self.environment.add_variable(assignment_statement.name, try self.create_variable(.{ - .value = alloca, - .type = llvm.LLVMVoidType(), // This gets set to the correct type during the expression type resolution. ALTERNATIVE: Pass the alloca - .stack_level = null, - .node = statement, - })); - } + if (assignment_statement.lhs.* == .PRIMARY_EXPRESSION) { + const identifier = assignment_statement.lhs.PRIMARY_EXPRESSION.IDENTIFIER; - var undereferenced_variable: ?*Variable = null; - if (assignment_statement.is_dereference) { - const ptr = self.environment.get_variable(assignment_statement.name) orelse unreachable; - undereferenced_variable = ptr; - const x = llvm.LLVMBuildLoad2(self.builder, ptr.type, ptr.value, "") orelse return CodeGenError.CompilationError; - try self.environment.add_variable(assignment_statement.name, try self.create_variable(.{ - .value = x, - .type = ptr.type, - .stack_level = null, - .node = statement, - })); - } + if (assignment_statement.is_declaration and self.environment.scope_stack.items.len > 1) { + std.debug.assert(assignment_statement.is_dereference == false); + // TODO: vv Int64Type is a problem + const alloca = llvm.LLVMBuildAlloca(self.builder, llvm.LLVMInt64Type(), try std.fmt.allocPrintZ(self.arena, "{s}", .{identifier.name})); //TODO: Correct type + try self.environment.add_variable(identifier.name, try self.create_variable(.{ + .value = alloca, + .type = llvm.LLVMVoidType(), // This gets set to the correct type during the expression type resolution. ALTERNATIVE: Pass the alloca + .stack_level = null, + .node = statement, + })); + } - const variable = try self.generate_expression_value(assignment_statement.expression, assignment_statement.name); + var undereferenced_variable: ?*Variable = null; + if (assignment_statement.is_dereference) { + const ptr = self.environment.get_variable(identifier.name) orelse unreachable; + undereferenced_variable = ptr; + const x = llvm.LLVMBuildLoad2(self.builder, ptr.type, ptr.value, "") orelse return CodeGenError.CompilationError; + try self.environment.add_variable(identifier.name, try self.create_variable(.{ + .value = x, + .type = ptr.type, + .stack_level = null, + .node = statement, + })); + } - if (!assignment_statement.is_dereference) { - try self.environment.add_variable(assignment_statement.name, variable); + const variable = try self.generate_expression_value(assignment_statement.rhs, identifier.name); + + if (!assignment_statement.is_dereference) { + try self.environment.add_variable(identifier.name, variable); + } else { + try self.environment.add_variable(identifier.name, undereferenced_variable.?); + } } else { - try self.environment.add_variable(assignment_statement.name, undereferenced_variable.?); + const xd = assignment_statement.lhs.UNARY_EXPRESSION.expression; + const a = try self.generate_expression_value(xd, null); + const variable = try self.generate_expression_value(assignment_statement.rhs, null); + _ = llvm.LLVMBuildStore(self.builder, variable.value, a.value); } } diff --git a/src/parser.zig b/src/parser.zig index a40c811..4f607be 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -16,8 +16,8 @@ pub const Node = union(enum) { ASSIGNMENT_STATEMENT: struct { is_declaration: bool, is_dereference: bool, - name: []const u8, - expression: *Node, + lhs: *Node, + rhs: *Node, }, FUNCTION_CALL_STATEMENT: struct { expression: *Node, @@ -154,7 +154,7 @@ pub const Parser = struct { }); } - // AssignmentStatement ::= ("let")? ("*")? IDENTIFIER EQUALS Expression + // AssignmentStatement ::= ("let")? ("*")? Expression EQUALS Expression fn parse_assignment_statement(self: *Parser) ParserError!*Node { errdefer if (!self.try_context) std.debug.print("Error parsing assignment statement {any}\n", .{self.peek_token()}); @@ -168,18 +168,18 @@ pub const Parser = struct { is_dereference = true; } - const identifier = try self.parse_token(tokenizer.TokenType.IDENTIFIER); + const lhs = try self.parse_expression(); _ = try self.parse_token(tokenizer.TokenType.EQUALS); - const expression = try self.parse_expression(); + const rhs = try self.parse_expression(); return self.create_node(.{ .ASSIGNMENT_STATEMENT = .{ .is_declaration = is_declaration, .is_dereference = is_dereference, - .name = try self.arena.dupe(u8, identifier.type.IDENTIFIER), - .expression = @constCast(expression), + .lhs = lhs, + .rhs = rhs, }, }); } @@ -200,8 +200,15 @@ pub const Parser = struct { .ASSIGNMENT_STATEMENT = .{ .is_declaration = true, .is_dereference = false, - .name = try self.arena.dupe(u8, identifier.type.IDENTIFIER), - .expression = @constCast(typ), + .lhs = try self.create_node(.{ + .PRIMARY_EXPRESSION = .{ + .IDENTIFIER = .{ + .name = try self.arena.dupe(u8, identifier.type.IDENTIFIER), + .type = null, + }, + }, + }), + .rhs = @constCast(typ), }, }); } -- cgit 1.4.1