diff options
author | Baitinq <manuelpalenzuelamerino@gmail.com> | 2025-01-12 17:43:50 +0100 |
---|---|---|
committer | Baitinq <manuelpalenzuelamerino@gmail.com> | 2025-01-12 17:47:51 +0100 |
commit | b3344abfba762b22af1ac80cdf2801ff6eaf3696 (patch) | |
tree | 355cf53c0efcd5853b0e4c0755670b42453dec23 | |
parent | Evaluator: Fix bug when variables are initialized with the same identifier as... (diff) | |
download | interpreter-b3344abfba762b22af1ac80cdf2801ff6eaf3696.tar.gz interpreter-b3344abfba762b22af1ac80cdf2801ff6eaf3696.tar.bz2 interpreter-b3344abfba762b22af1ac80cdf2801ff6eaf3696.zip |
Add support for sum operator
-rw-r--r-- | examples/3.src | 6 | ||||
-rw-r--r-- | grammar.ebnf | 2 | ||||
-rw-r--r-- | src/evaluator.zig | 6 | ||||
-rw-r--r-- | src/parser.zig | 71 | ||||
-rw-r--r-- | src/tokenizer.zig | 67 | ||||
-rw-r--r-- | todo/0.src | 5 |
6 files changed, 99 insertions, 58 deletions
diff --git a/examples/3.src b/examples/3.src index 736ab61..042edea 100644 --- a/examples/3.src +++ b/examples/3.src @@ -1,5 +1,3 @@ -let ten = 10; +let sixteen = 10 + 2 + 4; -let twelve = ten + 2; - -print(twelve); +print(sixteen); diff --git a/grammar.ebnf b/grammar.ebnf index 1423e74..1ac139e 100644 --- a/grammar.ebnf +++ b/grammar.ebnf @@ -6,4 +6,4 @@ VariableStatement ::= ("let" IDENTIFIER | IDENTIFIER) EQUALS Expression PrintStatement :== PRINT LPAREN Expression RPAREN -Expression :== NUMBER | IDENTIFIER +Expression :== NUMBER | IDENTIFIER | Expression + Expression diff --git a/src/evaluator.zig b/src/evaluator.zig index f8bb052..ef83463 100644 --- a/src/evaluator.zig +++ b/src/evaluator.zig @@ -93,6 +93,12 @@ pub const Evaluator = struct { return try self.get_expression_value(expression orelse return EvaluatorError.EvaluationError); }, + .BINARY => |operation| { + //TODO: For now, this just represents sum + const lhs = try self.get_expression_value(operation.lhs); + const rhs = try self.get_expression_value(operation.rhs); + return lhs + rhs; + }, }; } }; diff --git a/src/parser.zig b/src/parser.zig index 9e27d65..e8fcd81 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -14,24 +14,35 @@ const NodeType = enum { EXPRESSION, }; -pub const Node = union(NodeType) { PROGRAM: struct { - statements: []*Node, -}, STATEMENT: struct { - statement: *Node, -}, VARIABLE_STATEMENT: struct { - is_declaration: bool, - name: []const u8, - expression: *Node, -}, PRINT_STATEMENT: struct { - expression: *Node, -}, EXPRESSION: union(enum) { - NUMBER: struct { - value: i64, +pub const Node = union(NodeType) { + PROGRAM: struct { + statements: []*Node, }, - IDENTIFIER: struct { + STATEMENT: struct { + statement: *Node, + }, + VARIABLE_STATEMENT: struct { + is_declaration: bool, name: []const u8, + expression: *Node, + }, + PRINT_STATEMENT: struct { + expression: *Node, + }, + EXPRESSION: union(enum) { + NUMBER: struct { + value: i64, + }, + IDENTIFIER: struct { + name: []const u8, + }, + BINARY: struct { + //TODO: For now, this just represents sum + lhs: *Node, + rhs: *Node, + }, }, -} }; +}; pub const Parser = struct { tokens: []tokenizer.Token, @@ -88,12 +99,10 @@ pub const Parser = struct { // VariableStatement ::= ("let" IDENTIFIER | IDENTIFIER) EQUALS Expression fn parse_variable_statement(self: *Parser) ParserError!*Node { errdefer std.debug.print("Error parsing variable statement\n", .{}); - const token = self.peek_token() orelse return ParserError.ParsingError; var is_declaration: bool = false; - if (token == .LET) { + if (self.match_token(.LET)) { is_declaration = true; - _ = self.consume_token() orelse return ParserError.ParsingError; } const identifier = try self.accept_token(tokenizer.TokenType.IDENTIFIER); @@ -129,12 +138,12 @@ pub const Parser = struct { }); } - // Expression :== NUMBER | IDENTIFIER + // Expression :== NUMBER | IDENTIFIER | Expression + Expression fn parse_expression(self: *Parser) ParserError!*Node { errdefer std.debug.print("Error parsing expression\n", .{}); const token = self.consume_token() orelse return ParserError.ParsingError; - return switch (token) { + const lhs = try switch (token) { .NUMBER => |number_token| self.create_node(.{ .EXPRESSION = .{ .NUMBER = .{ @@ -149,8 +158,19 @@ pub const Parser = struct { }, }, }), - else => return ParserError.ParsingError, + else => unreachable, }; + + while (self.match_token(tokenizer.TokenType.PLUS)) { + const rhs = try self.parse_expression(); + + return self.create_node(.{ .EXPRESSION = .{ .BINARY = .{ + .lhs = lhs, + .rhs = rhs, + } } }); + } + + return lhs; } fn accept_token(self: *Parser, expected_token: tokenizer.TokenType) ParserError!tokenizer.Token { @@ -162,6 +182,15 @@ pub const Parser = struct { return self.consume_token() orelse unreachable; } + fn match_token(self: *Parser, token: tokenizer.TokenType) bool { + const curr_token = self.peek_token() orelse return false; + if (curr_token == token) { + _ = self.consume_token(); + return true; + } + return false; + } + fn consume_token(self: *Parser) ?tokenizer.Token { if (self.offset >= self.tokens.len) return null; diff --git a/src/tokenizer.zig b/src/tokenizer.zig index 4353ebb..20f80cc 100644 --- a/src/tokenizer.zig +++ b/src/tokenizer.zig @@ -4,6 +4,39 @@ const TokenizerError = error{ TokenizingError, }; +pub const TokenType = enum { + // Keywords + LET, + PRINT, + + // Identifiers + IDENTIFIER, + + // Literals + NUMBER, + + // Operators + EQUALS, + PLUS, + + // Punctuation + SEMICOLON, + LPAREN, + RPAREN, +}; + +pub const Token = union(TokenType) { + LET: void, + PRINT: void, + IDENTIFIER: []u8, + NUMBER: i64, + EQUALS: void, + PLUS: void, + SEMICOLON: void, + LPAREN: void, + RPAREN: void, +}; + pub const Tokenizer = struct { buf: []u8, offset: u32, @@ -24,6 +57,7 @@ pub const Tokenizer = struct { if (c == '(') return Token{ .LPAREN = void{} }; if (c == ')') return Token{ .RPAREN = void{} }; if (c == '=') return Token{ .EQUALS = void{} }; + if (c == '+') return Token{ .PLUS = void{} }; const string = self.consume_string(); if (string.len == 0) return TokenizerError.TokenizingError; @@ -60,37 +94,6 @@ pub const Tokenizer = struct { } }; -pub const TokenType = enum { - // Keywords - LET, - PRINT, - - // Identifiers - IDENTIFIER, - - // Literals - NUMBER, - - // Operators - EQUALS, - - // Punctuation - SEMICOLON, - LPAREN, - RPAREN, -}; - -pub const Token = union(TokenType) { - LET: void, - PRINT: void, - IDENTIFIER: []u8, - NUMBER: i64, - EQUALS: void, - SEMICOLON: void, - LPAREN: void, - RPAREN: void, -}; - test "simple" { const tests = [_]struct { buf: []u8, @@ -132,7 +135,7 @@ test "simple" { defer token_list.deinit(); var tokenizer = try Tokenizer.init(t.buf); - while (tokenizer.next()) |token| { + while (try tokenizer.next()) |token| { try token_list.append(token); } try std.testing.expectEqualDeep(t.tokens, token_list.items); diff --git a/todo/0.src b/todo/0.src new file mode 100644 index 0000000..2784a86 --- /dev/null +++ b/todo/0.src @@ -0,0 +1,5 @@ +let x = 1; + +x = x; + +print(x); |