diff options
| author | Baitinq <[email protected]> | 2025-05-28 00:11:06 +0200 |
|---|---|---|
| committer | Baitinq <[email protected]> | 2025-05-28 00:11:06 +0200 |
| commit | 48958afe4e187ce496d3445ee622ec3bc7bc8453 (patch) | |
| tree | bf6c0ead8240a27e150e9e81dd9207cee4dbe211 | |
| parent | Feature: Finish adding struct support :^) (diff) | |
| download | pry-lang-48958afe4e187ce496d3445ee622ec3bc7bc8453.tar.gz pry-lang-48958afe4e187ce496d3445ee622ec3bc7bc8453.tar.bz2 pry-lang-48958afe4e187ce496d3445ee622ec3bc7bc8453.zip | |
Feature: Add sizeof builtin function
| -rw-r--r-- | examples/19.src | 2 | ||||
| -rw-r--r-- | grammar.ebnf | 6 | ||||
| -rw-r--r-- | src/codegen.zig | 23 | ||||
| -rw-r--r-- | src/parser.zig | 35 |
4 files changed, 60 insertions, 6 deletions
diff --git a/examples/19.src b/examples/19.src index 5a3543f..2ae1973 100644 --- a/examples/19.src +++ b/examples/19.src @@ -3,7 +3,7 @@ extern malloc = (i64) => *void; extern free = (*void) => void; let main = () => i64 { - let buf = cast(*i8, malloc(13)); + let buf = cast(*i8, malloc(sizeof(i8) * 13)); (*(buf+cast(*i8, 0))) = 'h'; (*(buf+cast(*i8, 1))) = 'e'; (*(buf+cast(*i8, 2))) = 'l'; diff --git a/grammar.ebnf b/grammar.ebnf index 78101f1..cecc65e 100644 --- a/grammar.ebnf +++ b/grammar.ebnf @@ -1,6 +1,6 @@ Program ::= Statement+ -Statement ::= (AssignmentStatement | ImportDeclaration | ExternDeclaration | CastStatement| FunctionCallStatement | IfStatement | WhileStatement | ReturnStatement | "break" | "continue") SEMICOLON +Statement ::= (AssignmentStatement | ImportDeclaration | ExternDeclaration | CastStatement | SizeOfStatement | FunctionCallStatement | IfStatement | WhileStatement | ReturnStatement | "break" | "continue") SEMICOLON AssignmentStatement ::= ("let")? ("*")? Expression EQUALS Expression @@ -21,6 +21,8 @@ FunctionArguments ::= Expression ("," Expression)* Expression ::= EqualityExpression | AdditiveExpression CastStatement ::= "cast" LPAREN TYPE "," Expression RPAREN + +SizeOfStatement ::= "sizeof" LPAREN TYPE RPAREN EqualityExpression ::= AdditiveExpression ("==" | "!=" | "<=" | ">=" | "<" | ">") AdditiveExpression @@ -30,7 +32,7 @@ MultiplicativeExpression ::= UnaryExpression (("*" | "/" | "%") UnaryExpression) UnaryExpression ::= ("!" | "-" | "*") UnaryExpression | PostfixExpression -PostfixExpression ::= PrimaryExpression (FieldAccess | FunctionCallStatement | CastStatement)* +PostfixExpression ::= PrimaryExpression (FieldAccess | FunctionCallStatement | CastStatement | SizeOfStatement)* PrimaryExpression ::= NULL | NUMBER | BOOLEAN | CHAR | STRING | IDENTIFIER | FunctionDefinition | StructDefinition | StructInstantiation | FieldAccess | LPAREN Expression RPAREN diff --git a/src/codegen.zig b/src/codegen.zig index b72e9c4..d246853 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -17,6 +17,7 @@ pub const CodeGenError = error{ pub const CodeGen = struct { llvm_module: llvm.LLVMModuleRef, + llvm_target_data: llvm.LLVMTargetDataRef, llvm_context: llvm.LLVMContextRef, builder: llvm.LLVMBuilderRef, environment: *Environment, @@ -43,6 +44,7 @@ pub const CodeGen = struct { const self = try arena.create(CodeGen); self.* = .{ .llvm_module = module, + .llvm_target_data = llvm.LLVMGetModuleDataLayout(module), .llvm_context = context, .builder = builder, .environment = try Environment.init(arena), @@ -753,6 +755,27 @@ pub const CodeGen = struct { .node_type = exp.typ, }); }, + .SIZEOF_STATEMENT => |exp| { + const typ = try self.get_llvm_type(exp.typ); + const size_in_bits = llvm.LLVMSizeOfTypeInBits(self.llvm_target_data, typ); + const size_in_bytes = size_in_bits / 8; + + const size_val = llvm.LLVMConstInt(llvm.LLVMInt64Type(), size_in_bytes, 0); + + return try self.create_variable(.{ + .value = size_val, + .type = null, + .node_type = try self.create_node(.{ + .TYPE = .{ + .SIMPLE_TYPE = .{ + .name = "i64", + }, + }, + }), + .stack_level = null, + .node = expression, + }); + }, .FIELD_ACCESS => |exp| { const ptr = self.environment.get_variable(exp.expression.PRIMARY_EXPRESSION.IDENTIFIER.name).?; diff --git a/src/parser.zig b/src/parser.zig index 95b4bf2..5db8fa8 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -111,6 +111,9 @@ pub const Node = union(enum) { typ: *Node, expression: *Node, }, + SIZEOF_STATEMENT: struct { + typ: *Node, + }, BREAK_STATEMENT: void, CONTINUE_STATEMENT: void, }; @@ -168,12 +171,13 @@ pub const Parser = struct { } }); } - // Statement ::= (AssignmentStatement | ImportDeclaration | ExternDeclaration | CastStatement | FunctionCallStatement | IfStatement | WhileStatement | ReturnStatement | "break" | "continue") SEMICOLON + // Statement ::= (AssignmentStatement | ImportDeclaration | ExternDeclaration | CastStatement | SizeOfStatement | FunctionCallStatement | IfStatement | WhileStatement | ReturnStatement | "break" | "continue") SEMICOLON fn parse_statement(self: *Parser) ParserError!*Node { errdefer if (!self.try_context) std.debug.print("Error parsing statement {any}\n", .{self.peek_token()}); const statement = - self.accept_parse(parse_cast_statement) orelse + self.accept_parse(parse_cast_statement) orelse //TODO: Can we not deal with cast / sizeof in parser? + self.accept_parse(parse_sizeof_statement) orelse self.accept_parse(parse_function_call_statement) orelse self.accept_parse(parse_if_statement) orelse self.accept_parse(parse_while_statement) orelse @@ -567,12 +571,14 @@ pub const Parser = struct { } }); } - // PostfixExpression ::= PrimaryExpression (FunctionCallStatement | FieldAccess )* + // PostfixExpression ::= PrimaryExpression (CastStatement | SizeOfStatement | FunctionCallStatement | FieldAccess )* fn parse_postfix_expression(self: *Parser) ParserError!*Node { errdefer if (!self.try_context) std.debug.print("Error parsing postfix expression {any}\n", .{self.peek_token()}); if (self.accept_parse(parse_cast_statement)) |stmt| { return stmt; + } else if (self.accept_parse(parse_sizeof_statement)) |stmt| { + return stmt; } else if (self.accept_parse(parse_function_call_statement)) |stmt| { return stmt; } else if (self.accept_parse(parse_field_access)) |stmt| { @@ -814,6 +820,29 @@ pub const Parser = struct { }); } + // SizeOfStatement ::= "sizeof" LPAREN TYPE RPAREN + fn parse_sizeof_statement(self: *Parser) ParserError!*Node { + errdefer if (!self.try_context) std.debug.print("Error parsing sizeof statement {any}\n", .{self.peek_token()}); + + const ident = try self.parse_token(tokenizer.TokenType.IDENTIFIER); + + if (!std.mem.eql(u8, "sizeof", ident.type.IDENTIFIER)) { + return ParserError.ParsingError; + } + + _ = try self.parse_token(tokenizer.TokenType.LPAREN); + + const typ = try self.parse_type(); + + _ = try self.parse_token(tokenizer.TokenType.RPAREN); + + return self.create_node(.{ + .SIZEOF_STATEMENT = .{ + .typ = typ, + }, + }); + } + // Type ::= IDENTIFIER | FunctionType fn parse_type(self: *Parser) ParserError!*Node { errdefer if (!self.try_context) std.debug.print("Error parsing type annotation {any}\n", .{self.peek_token()}); |