diff options
| author | Baitinq <[email protected]> | 2025-03-29 11:22:13 +0100 |
|---|---|---|
| committer | Baitinq <[email protected]> | 2025-03-29 11:27:15 +0100 |
| commit | d74c6a363cf457a2197f3f10c0d567a77573e79c (patch) | |
| tree | b82cad7904e8493c28cfa1612de2e0e081484e0c | |
| parent | Codegen: Support void type (diff) | |
| download | interpreter-d74c6a363cf457a2197f3f10c0d567a77573e79c.tar.gz interpreter-d74c6a363cf457a2197f3f10c0d567a77573e79c.tar.bz2 interpreter-d74c6a363cf457a2197f3f10c0d567a77573e79c.zip | |
Feature: Add basic support for pointer references and dereferences
| -rw-r--r-- | examples/17.src | 12 | ||||
| -rw-r--r-- | grammar.ebnf | 4 | ||||
| -rw-r--r-- | src/codegen.zig | 31 | ||||
| -rw-r--r-- | src/evaluator.zig | 15 | ||||
| -rw-r--r-- | src/parser.zig | 25 |
5 files changed, 70 insertions, 17 deletions
diff --git a/examples/17.src b/examples/17.src new file mode 100644 index 0000000..0e73fae --- /dev/null +++ b/examples/17.src @@ -0,0 +1,12 @@ +extern printf = (*i64, varargs) => void; +extern malloc = (i64) => *i64; +extern free = (*i64) => void; + +let main = () => i64 { + let x = malloc(8); + *x = 10; + printf("%p\n", x); + printf("%d\n", *x); + free(x); + return 0; +}; diff --git a/grammar.ebnf b/grammar.ebnf index 83da90a..85d824d 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")? ("*")? IDENTIFIER EQUALS Expression ExternDeclaration ::= "extern" IDENTIFIER EQUALS Type @@ -24,7 +24,7 @@ AdditiveExpression ::= MultiplicativeExpression (("+" | "-") MultiplicativeExpre MultiplicativeExpression ::= UnaryExpression (("*" | "/" | "%") UnaryExpression)* -UnaryExpression ::= ("!" | "-") UnaryExpression | PrimaryExpression +UnaryExpression ::= ("!" | "-" | "*") UnaryExpression | PrimaryExpression PrimaryExpression ::= NUMBER | BOOLEAN | STRING | IDENTIFIER | FunctionCallStatement | FunctionDefinition | LPAREN Expression RPAREN diff --git a/src/codegen.zig b/src/codegen.zig index da1c8ca..a6f4b08 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -127,6 +127,7 @@ pub const CodeGen = struct { 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(.{ @@ -137,8 +138,26 @@ pub const CodeGen = struct { })); } + 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, + })); + } + const variable = try self.generate_expression_value(assignment_statement.expression, assignment_statement.name); - try self.environment.add_variable(assignment_statement.name, variable); + + if (!assignment_statement.is_dereference) { + try self.environment.add_variable(assignment_statement.name, variable); + } else { + try self.environment.add_variable(assignment_statement.name, undereferenced_variable.?); + } } fn generate_function_call_statement(self: *CodeGen, statement: *parser.Node) CodeGenError!*Variable { @@ -430,16 +449,20 @@ pub const CodeGen = struct { var r: llvm.LLVMValueRef = undefined; var t: llvm.LLVMTypeRef = undefined; - switch (exp.negation) { - true => { + switch (exp.typ) { + .NOT => { std.debug.assert(k.type == llvm.LLVMInt1Type()); r = llvm.LLVMBuildICmp(self.builder, llvm.LLVMIntEQ, k.value, llvm.LLVMConstInt(llvm.LLVMInt1Type(), 0, 0), ""); t = llvm.LLVMInt1Type(); }, - false => { + .MINUS => { r = llvm.LLVMBuildNeg(self.builder, k.value, ""); t = llvm.LLVMInt64Type(); }, + .STAR => { + r = llvm.LLVMBuildLoad2(self.builder, k.type, k.value, ""); + t = llvm.LLVMInt64Type(); + }, } return self.generate_literal(r, t, name, expression); diff --git a/src/evaluator.zig b/src/evaluator.zig index f3c0a6c..5d97eed 100644 --- a/src/evaluator.zig +++ b/src/evaluator.zig @@ -186,12 +186,17 @@ pub const Evaluator = struct { }, .UNARY_EXPRESSION => |x| { const val = try self.get_expression_value(x.expression) orelse return EvaluatorError.EvaluationError; - if (!x.negation) { - std.debug.assert(val.* == .NUMBER); - return try self.create_variable(.{ .NUMBER = -val.NUMBER }); + switch (x.typ) { + .NOT => { + std.debug.assert(val.* == .BOOLEAN); + return try self.create_variable(.{ .BOOLEAN = !val.BOOLEAN }); + }, + .MINUS => { + std.debug.assert(val.* == .NUMBER); + return try self.create_variable(.{ .NUMBER = -val.NUMBER }); + }, + else => unreachable, } - std.debug.assert(val.* == .BOOLEAN); - return try self.create_variable(.{ .BOOLEAN = !val.BOOLEAN }); }, .EQUALITY_EXPRESSION => |x| { const lhs = try self.get_expression_value(x.lhs) orelse return EvaluatorError.EvaluationError; diff --git a/src/parser.zig b/src/parser.zig index a66817c..a40c811 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -15,6 +15,7 @@ pub const Node = union(enum) { }, ASSIGNMENT_STATEMENT: struct { is_declaration: bool, + is_dereference: bool, name: []const u8, expression: *Node, }, @@ -42,7 +43,11 @@ pub const Node = union(enum) { typ: MultiplicativeExpressionType, }, UNARY_EXPRESSION: struct { - negation: bool, + typ: enum { + NOT, + MINUS, + STAR, + }, expression: *Node, }, PRIMARY_EXPRESSION: union(enum) { @@ -149,15 +154,20 @@ pub const Parser = struct { }); } - // AssignmentStatement ::= "let"? IDENTIFIER EQUALS Expression + // AssignmentStatement ::= ("let")? ("*")? IDENTIFIER 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()}); - var is_declaration: bool = false; + var is_declaration = false; if (self.accept_token(.LET) != null) { is_declaration = true; } + var is_dereference = false; + if (self.accept_token(.MUL) != null) { + is_dereference = true; + } + const identifier = try self.parse_token(tokenizer.TokenType.IDENTIFIER); _ = try self.parse_token(tokenizer.TokenType.EQUALS); @@ -167,6 +177,7 @@ pub const Parser = struct { 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), }, @@ -188,6 +199,7 @@ pub const Parser = struct { return self.create_node(.{ .ASSIGNMENT_STATEMENT = .{ .is_declaration = true, + .is_dereference = false, .name = try self.arena.dupe(u8, identifier.type.IDENTIFIER), .expression = @constCast(typ), }, @@ -392,19 +404,20 @@ pub const Parser = struct { return lhs; } - // UnaryExpression ::= ("!" | "-") UnaryExpression | PrimaryExpression + // UnaryExpression ::= ("!" | "-" | "*") UnaryExpression | PrimaryExpression fn parse_unary_expression(self: *Parser) ParserError!*Node { errdefer if (!self.try_context) std.debug.print("Error parsing unary expression {any}\n", .{self.peek_token()}); const not = self.accept_token(tokenizer.TokenType.BANG) != null; const minus = self.accept_token(tokenizer.TokenType.MINUS) != null; + const star = self.accept_token(tokenizer.TokenType.MUL) != null; - if (!not and !minus) { + if (!not and !minus and !star) { return try self.parse_primary_expression(); } return self.create_node(.{ .UNARY_EXPRESSION = .{ - .negation = not, + .typ = if (not) .NOT else if (minus) .MINUS else .STAR, .expression = try self.parse_unary_expression(), } }); } |