From c8439a069354cb526e02a76f52e978738ad8871c Mon Sep 17 00:00:00 2001 From: Baitinq Date: Thu, 15 May 2025 18:42:37 +0200 Subject: Feature: Add support for null pointers --- grammar.ebnf | 2 +- src/codegen.zig | 13 +++++++++++++ src/parser.zig | 6 +++++- src/tokenizer.zig | 2 ++ 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/grammar.ebnf b/grammar.ebnf index ec61e90..70c0641 100644 --- a/grammar.ebnf +++ b/grammar.ebnf @@ -28,7 +28,7 @@ MultiplicativeExpression ::= UnaryExpression (("*" | "/" | "%") UnaryExpression) UnaryExpression ::= ("!" | "-" | "*") UnaryExpression | PrimaryExpression -PrimaryExpression ::= NUMBER | BOOLEAN | CHAR | STRING | IDENTIFIER | FunctionCallStatement | FunctionDefinition | LPAREN Expression RPAREN +PrimaryExpression ::= NULL | NUMBER | BOOLEAN | CHAR | STRING | IDENTIFIER | FunctionCallStatement | FunctionDefinition | LPAREN Expression RPAREN FunctionDefinition ::= LPAREN FunctionParameters? RPAREN ARROW IDENTIFIER LBRACE Statement* ReturnStatement SEMICOLON RBRACE diff --git a/src/codegen.zig b/src/codegen.zig index 5733d5f..05cb877 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -426,6 +426,19 @@ pub const CodeGen = struct { return try self.generate_function_call_statement(@ptrCast(fn_call)); }, .PRIMARY_EXPRESSION => |primary_expression| switch (primary_expression) { + .NULL => { + return try self.generate_literal(llvm.LLVMConstNull(llvm.LLVMPointerType(llvm.LLVMInt8Type(), 0)), name, expression, try self.create_node(.{ + .TYPE = .{ + .POINTER_TYPE = .{ + .type = try self.create_node(.{ + .TYPE = .{ .SIMPLE_TYPE = .{ + .name = "i8", + } }, + }), + }, + }, + })); + }, .NUMBER => |n| { return try self.generate_literal(llvm.LLVMConstInt(llvm.LLVMInt64Type(), @intCast(n.value), 0), name, expression, try self.create_node(.{ .TYPE = .{ diff --git a/src/parser.zig b/src/parser.zig index 7e1b695..ce1e4cb 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -61,6 +61,7 @@ pub const Node = union(enum) { BOOLEAN: struct { value: bool, }, + NULL: void, CHAR: struct { value: u8, }, @@ -525,7 +526,7 @@ pub const Parser = struct { } }); } - // PrimaryExpression ::= NUMBER | BOOLEAN | CHAR | STRING | IDENTIFIER | FunctionCallStatement | FunctionDefinition | LPAREN Expression RPAREN + // PrimaryExpression ::= NULL | NUMBER | BOOLEAN | CHAR | STRING | IDENTIFIER | FunctionCallStatement | FunctionDefinition | LPAREN Expression RPAREN fn parse_primary_expression(self: *Parser) ParserError!*Node { errdefer if (!self.try_context) std.debug.print("Error parsing primary expression {any}\n", .{self.peek_token()}); @@ -542,6 +543,9 @@ pub const Parser = struct { const token = self.consume_token() orelse return ParserError.ParsingError; return switch (token.type) { + .NULL => try self.create_node(.{ + .PRIMARY_EXPRESSION = .{ .NULL = void{} }, + }), .NUMBER => |number_token| try self.create_node(.{ .PRIMARY_EXPRESSION = .{ .NUMBER = .{ diff --git a/src/tokenizer.zig b/src/tokenizer.zig index 7ccb871..3b0ae4e 100644 --- a/src/tokenizer.zig +++ b/src/tokenizer.zig @@ -21,6 +21,7 @@ pub const TokenType = union(enum) { // Literals NUMBER: i64, BOOLEAN: bool, + NULL: void, CHAR: u8, STRING: []u8, @@ -94,6 +95,7 @@ pub const Tokenizer = struct { if (self.accept_string("break")) return self.create_token(.{ .BREAK = void{} }); if (self.accept_string("true")) return self.create_token(.{ .BOOLEAN = true }); if (self.accept_string("false")) return self.create_token(.{ .BOOLEAN = false }); + if (self.accept_string("null")) return self.create_token(.{ .NULL = void{} }); if (self.accept_string("=>")) return self.create_token(.{ .ARROW = void{} }); if (self.accept_string(";")) return self.create_token(.{ .SEMICOLON = void{} }); -- cgit 1.4.1