From fe47528e65e4690a5600154978515cc29133e5da Mon Sep 17 00:00:00 2001 From: Baitinq Date: Sun, 23 Mar 2025 01:21:49 +0100 Subject: Parser: Fix ambiguity with symbol declaration --- examples/15.src | 4 ++-- grammar.ebnf | 6 ++++-- src/parser.zig | 38 +++++++++++++++++++++++++------------- src/tokenizer.zig | 2 ++ 4 files changed, 33 insertions(+), 17 deletions(-) diff --git a/examples/15.src b/examples/15.src index fd68961..5dc138c 100644 --- a/examples/15.src +++ b/examples/15.src @@ -1,6 +1,6 @@ -let putchar = (i64) => i64; +extern putchar = (i64) => i64; -let main = (_: void) => i64 { +let main = () => i64 { putchar(72); putchar(101); putchar(108); diff --git a/grammar.ebnf b/grammar.ebnf index 562f2f8..cbc3f0a 100644 --- a/grammar.ebnf +++ b/grammar.ebnf @@ -1,8 +1,10 @@ Program ::= Statement+ -Statement ::= (AssignmentStatement | FunctionCallStatement | IfStatement | WhileStatement | ReturnStatement) SEMICOLON +Statement ::= (AssignmentStatement | ExternDeclaration | FunctionCallStatement | IfStatement | WhileStatement | ReturnStatement) SEMICOLON -AssignmentStatement ::= "let" IDENTIFIER EQUALS (Type | Expression) +AssignmentStatement ::= "let"? IDENTIFIER EQUALS Expression + +ExternDeclaration ::= "extern" IDENTIFIER EQUALS Type FunctionCallStatement ::= (IDENTIFIER | FunctionDefinition) LPAREN FunctionArguments? RPAREN diff --git a/src/parser.zig b/src/parser.zig index d2067a1..64e670e 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -123,7 +123,7 @@ pub const Parser = struct { } }); } - // Statement ::= (AssignmentStatement | FunctionCallStatement | IfStatement | WhileStatement | ReturnStatement) SEMICOLON + // Statement ::= (AssignmentStatement | ExternDeclaration | FunctionCallStatement | IfStatement | WhileStatement | ReturnStatement) SEMICOLON fn parse_statement(self: *Parser) ParserError!*Node { errdefer if (!self.try_context) std.debug.print("Error parsing statement {any}\n", .{self.peek_token()}); @@ -131,7 +131,8 @@ pub const Parser = struct { self.accept_parse(parse_if_statement) orelse self.accept_parse(parse_while_statement) orelse self.accept_parse(parse_return_statement) orelse - try self.parse_assignment_statement(); + self.accept_parse(parse_assignment_statement) orelse + try self.parse_extern_declaration(); _ = try self.parse_token(tokenizer.TokenType.SEMICOLON); @@ -142,7 +143,7 @@ pub const Parser = struct { }); } - // AssignmentStatement ::= "let" IDENTIFIER EQUALS (Type | 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()}); @@ -155,16 +156,6 @@ pub const Parser = struct { _ = try self.parse_token(tokenizer.TokenType.EQUALS); - if (self.accept_parse(parse_type)) |typ| { - return self.create_node(.{ - .ASSIGNMENT_STATEMENT = .{ - .is_declaration = is_declaration, - .name = try self.arena.dupe(u8, identifier.type.IDENTIFIER), - .expression = @constCast(typ), - }, - }); - } - const expression = try self.parse_expression(); return self.create_node(.{ @@ -176,6 +167,27 @@ pub const Parser = struct { }); } + // ExternDeclaration ::= "extern" IDENTIFIER EQUALS Type + fn parse_extern_declaration(self: *Parser) ParserError!*Node { + errdefer if (!self.try_context) std.debug.print("Error parsing extern declaration {any}\n", .{self.peek_token()}); + + _ = try self.parse_token(.EXTERN); + + const identifier = try self.parse_token(tokenizer.TokenType.IDENTIFIER); + + _ = try self.parse_token(tokenizer.TokenType.EQUALS); + + const typ = try self.parse_type(); + + return self.create_node(.{ + .ASSIGNMENT_STATEMENT = .{ + .is_declaration = true, + .name = try self.arena.dupe(u8, identifier.type.IDENTIFIER), + .expression = @constCast(typ), + }, + }); + } + // FunctionCallStatement ::= (IDENTIFIER | FunctionDefinition) LPAREN FunctionArguments? RPAREN fn parse_function_call_statement(self: *Parser) ParserError!*Node { errdefer if (!self.try_context) std.debug.print("Error parsing function call statement {any}\n", .{self.peek_token()}); diff --git a/src/tokenizer.zig b/src/tokenizer.zig index f0dcd26..138ad69 100644 --- a/src/tokenizer.zig +++ b/src/tokenizer.zig @@ -7,6 +7,7 @@ const TokenizerError = error{ pub const TokenType = union(enum) { // Keywords LET: void, + EXTERN: void, IF: void, WHILE: void, RETURN: void, @@ -67,6 +68,7 @@ pub const Tokenizer = struct { if (self.offset >= self.buf.len) return null; if (self.accept_string("let")) return self.create_token(.{ .LET = void{} }); + if (self.accept_string("extern")) return self.create_token(.{ .EXTERN = void{} }); if (self.accept_string("if")) return self.create_token(.{ .IF = void{} }); if (self.accept_string("while")) return self.create_token(.{ .WHILE = void{} }); if (self.accept_string("return")) return self.create_token(.{ .RETURN = void{} }); -- cgit 1.4.1