diff options
| author | Baitinq <[email protected]> | 2025-03-12 00:47:31 +0100 |
|---|---|---|
| committer | Baitinq <[email protected]> | 2025-03-12 00:47:43 +0100 |
| commit | da0788140e7afbc9b0bcbb937a29e2b08de08ec7 (patch) | |
| tree | ef6435c7c91f40926f01f5faa9b4dbc2946a5caf | |
| parent | Codegen: add bundled llvm (diff) | |
| parent | Codegen: Fix bug with functions without name (diff) | |
| download | interpreter-da0788140e7afbc9b0bcbb937a29e2b08de08ec7.tar.gz interpreter-da0788140e7afbc9b0bcbb937a29e2b08de08ec7.tar.bz2 interpreter-da0788140e7afbc9b0bcbb937a29e2b08de08ec7.zip | |
Merge branch 'master' into native-llvm
| -rw-r--r-- | README.md | 50 | ||||
| -rw-r--r-- | build.zig | 3 | ||||
| -rw-r--r-- | examples/10.src | 10 | ||||
| -rw-r--r-- | examples/12.src | 42 | ||||
| -rw-r--r-- | examples/13.src | 31 | ||||
| -rw-r--r-- | examples/7.src | 2 | ||||
| -rw-r--r-- | examples/8.src | 18 | ||||
| -rw-r--r-- | grammar.ebnf | 4 | ||||
| -rw-r--r-- | src/codegen.zig | 172 | ||||
| -rw-r--r-- | src/evaluator.zig | 13 | ||||
| -rw-r--r-- | src/parser.zig | 61 | ||||
| -rw-r--r-- | src/tokenizer.zig | 6 |
12 files changed, 257 insertions, 155 deletions
diff --git a/README.md b/README.md new file mode 100644 index 0000000..a6e18d3 --- /dev/null +++ b/README.md @@ -0,0 +1,50 @@ +# Programming Language + +Simple statically typed and compiled programming language implemented in Zig, with support for variables, control flow, functions, and code generation using LLVM. + +## Building and Running + +1. Ensure you have Zig and LLVM installed on your system. +2. Run the compiler on an example file: + ``` + zig build run -- examples/8.src compile + ``` +3. Link the generated object file to create an executable: + ``` + cc output.o + ``` +4. Run the executable: + ``` + ./a.out + ``` + +## Language Features + +- **Variables and Declarations**: Uses `let` for variable declaration. +- **Control Flow**: Supports `if` and `while` statements. +- **Functions**: Supports function declarations with parameters and return types. +- **Expressions**: Includes additive, multiplicative, equality, and unary expressions. +- **Code Generation with LLVM**: Translates AST to LLVM IR and generates object files for native execution. + +## Example Program + +```js +let main = () => i64 { + let fib = (n: i64) => i64 { + if n == 0 { + return 0; + }; + if n == 1 { + return 1; + }; + return fib(n-2) + fib(n-1); + }; + + let result = fib(30); + print(result); + return result; +}; +``` +``` +Output: 832040 +``` diff --git a/build.zig b/build.zig index 45fafa1..49df9a8 100644 --- a/build.zig +++ b/build.zig @@ -26,7 +26,8 @@ pub fn build(b: *std.Build) !void { .optimize = optimize, }); - exe_mod.linkSystemLibrary("llvm", .{}); + exe_mod.linkSystemLibrary("LLVM-18", .{}); + exe_mod.link_libc = true; // This creates another `std.Build.Step.Compile`, but this one builds an executable // rather than a static library. diff --git a/examples/10.src b/examples/10.src index 0ec38ea..59f91e1 100644 --- a/examples/10.src +++ b/examples/10.src @@ -1,14 +1,16 @@ let main = () => i64 { let counter = 0; - while !(counter == 10) { + while counter < 10 { print(counter); counter = counter + 1; }; - while counter == 0 { - print(0); + while true { + if counter == 10 { + return counter; + }; }; - return counter; + return 1; }; diff --git a/examples/12.src b/examples/12.src index 1bff280..a680efa 100644 --- a/examples/12.src +++ b/examples/12.src @@ -1,8 +1,38 @@ -let print_int = (n: i64) => i64 { - print(n); - return n; -}; +let main = () => i64 { + let factorial = (n: i64) => i64 { + let f = (acc: i64, n: i64) => i64 { + if n == 0 { + return acc; + }; + return f(acc * n, n - 1); + }; + return f(1, n); + }; + + let is_even = (n: i64) => bool { + if n % 2 == 0 { + return true; + }; + return false; + }; + + let sum_if = (predicate: (i64) => bool, limit: i64) => i64 { + let sum = 0; + let i = 0; + while i < limit { + if predicate(i) { + sum = sum + i; + }; + i = i + 1; + }; + return sum; + }; + + let fact_val = factorial(6); + print(fact_val); + + let even_sum = sum_if(is_even, 20); + print(even_sum); -let main = (argc: i64) => i64 { - return print_int(argc); + return 0; }; diff --git a/examples/13.src b/examples/13.src new file mode 100644 index 0000000..eeb5b32 --- /dev/null +++ b/examples/13.src @@ -0,0 +1,31 @@ +let main = () => i64 { + /* Iterative Fibonacci using while loop. */ + let fibonacci_iter = (n: i64) => i64 { + let a = 0; + let b = 1; + let i = 0; + while i < n { + let temp = b; + b = a + b; + a = temp; + i = i + 1; + }; + return a; + }; + + /* Recursive GCD using Euclid's algorithm. */ + let gcd = (a: i64, b: i64) => i64 { + if b == 0 { + return a; + }; + return gcd(b, a % b); + }; + + let fib_val = fibonacci_iter(10); + print(fib_val); + + let gcd_val = gcd(48, 18); + print(gcd_val); + + return 0; +}; diff --git a/examples/7.src b/examples/7.src index c0690b6..b10a350 100644 --- a/examples/7.src +++ b/examples/7.src @@ -2,7 +2,7 @@ let ten = () => i64 { return () => i64 { return 10; }(); -}; /* TODO */ +}; let main = () => i64 { let i = 4; diff --git a/examples/8.src b/examples/8.src index 73ea7aa..985ca77 100644 --- a/examples/8.src +++ b/examples/8.src @@ -1,14 +1,14 @@ -let fib = (n: i64) => i64 { - if n == 0 { - return 0; - }; - if n == 1 { - return 1; +let main = () => i64 { + let fib = (n: i64) => i64 { + if n == 0 { + return 0; + }; + if n == 1 { + return 1; + }; + return fib(n-2) + fib(n-1); }; - return fib(n-2) + fib(n-1); -}; -let main = () => i64 { let result = fib(30); print(result); return result; diff --git a/grammar.ebnf b/grammar.ebnf index ed87d7f..bbfe488 100644 --- a/grammar.ebnf +++ b/grammar.ebnf @@ -16,11 +16,11 @@ FunctionArguments ::= Expression ("," Expression)* Expression ::= EqualityExpression | AdditiveExpression -EqualityExpression ::= AdditiveExpression "==" AdditiveExpression +EqualityExpression ::= AdditiveExpression ("==" | "<" | ">") AdditiveExpression AdditiveExpression ::= MultiplicativeExpression (("+" | "-") MultiplicativeExpression)* -MultiplicativeExpression ::= UnaryExpression (("*" | "/") UnaryExpression)* +MultiplicativeExpression ::= UnaryExpression (("*" | "/" | "%") UnaryExpression)* UnaryExpression ::= ("!" | "-") UnaryExpression | PrimaryExpression diff --git a/src/codegen.zig b/src/codegen.zig index eb80c96..f734018 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -32,9 +32,10 @@ pub const CodeGen = struct { pub fn init(arena: std.mem.Allocator) !*CodeGen { // Initialize LLVM target.LLVMInitializeAllTargetInfos(); - _ = target.LLVMInitializeAllTargets(); - _ = target.LLVMInitializeAllAsmPrinters(); - _ = target.LLVMInitializeAllAsmParsers(); + target.LLVMInitializeAllTargetMCs(); + target.LLVMInitializeAllTargets(); + target.LLVMInitializeAllAsmPrinters(); + target.LLVMInitializeAllAsmParsers(); const module: types.LLVMModuleRef = core.LLVMModuleCreateWithName("module"); const builder = core.LLVMCreateBuilder(); @@ -50,8 +51,7 @@ pub const CodeGen = struct { const printf_function_type = core.LLVMFunctionType(core.LLVMVoidType(), @constCast(&[_]types.LLVMTypeRef{ core.LLVMPointerType(core.LLVMInt8Type(), 0), - core.LLVMInt64Type(), - }), 2, 1); + }), 1, 1); const printf_function = core.LLVMAddFunction(self.llvm_module, "printf", printf_function_type) orelse return CodeGenError.CompilationError; try self.environment.add_variable("printf", try self.create_variable(.{ .value = printf_function, @@ -72,10 +72,11 @@ pub const CodeGen = struct { // Generate code const triple = target_m.LLVMGetDefaultTargetTriple(); var target_ref: types.LLVMTargetRef = undefined; - var message: [*c]u8 = undefined; - _ = target_m.LLVMGetTargetFromTriple(triple, &target_ref, &message); - std.debug.print("Target output: {s}.\n", .{message}); - core.LLVMDisposeMessage(message); + var message: ?[*c]u8 = undefined; + const xd = target_m.LLVMGetTargetFromTriple(triple, &target_ref, &message.?); + std.debug.print("XD: {any}.\n", .{xd}); + // std.debug.print("Target output: {any}.\n", .{message}); + // core.LLVMDisposeMessage(message); const target_machine = target_m.LLVMCreateTargetMachine( target_ref, triple, @@ -97,9 +98,9 @@ pub const CodeGen = struct { ); std.debug.print("Object file generated: {s}\n", .{filename}); - _ = analysis.LLVMVerifyModule(self.llvm_module, types.LLVMAbortProcessAction, &message); - std.debug.print("Verification output: {s}.\n", .{message}); - core.LLVMDisposeMessage(message); + _ = analysis.LLVMVerifyModule(self.llvm_module, types.LLVMAbortProcessAction, &message.?); + // std.debug.print("Verification output: {any}.\n", .{message}); + // core.LLVMDisposeMessage(message); // Clean up LLVM resources defer core.LLVMDisposeBuilder(self.builder); @@ -165,9 +166,7 @@ pub const CodeGen = struct { .PRIMARY_EXPRESSION => |primary_expression| { std.debug.assert(primary_expression == .IDENTIFIER); function = self.environment.get_variable(primary_expression.IDENTIFIER.name) orelse return CodeGenError.CompilationError; - std.debug.print("STACK LVEL: {any} {s}\n", .{ function.stack_level.?, primary_expression.IDENTIFIER.name }); - if (function.stack_level.? > 0) { - std.debug.print("NOT GLOBAL FN! {s} {any}\n", .{ primary_expression.IDENTIFIER.name, function.stack_level }); + if (core.LLVMGetValueKind(function.value) != types.LLVMFunctionValueKind) { function.value = core.LLVMBuildLoad2(self.builder, core.LLVMPointerType(function.type, 0), function.value, ""); } }, @@ -212,7 +211,7 @@ pub const CodeGen = struct { for (if_statement.statements) |stmt| { try self.generate_statement(stmt); } - const merge_block = core.LLVMAppendBasicBlock(core.LLVMGetLastFunction(self.llvm_module), "else_block"); + const merge_block = core.LLVMAppendBasicBlock(core.LLVMGetLastFunction(self.llvm_module), "merge_block"); const last_instr = core.LLVMGetLastInstruction(then_block); if (core.LLVMIsATerminatorInst(last_instr) == null) { _ = core.LLVMBuildBr(self.builder, merge_block); @@ -242,10 +241,8 @@ pub const CodeGen = struct { for (while_statement.statements) |stmt| { try self.generate_statement(stmt); } - const last_instr = core.LLVMGetLastInstruction(inner_block); - if (core.LLVMIsATerminatorInst(last_instr) == null) { - _ = core.LLVMBuildBr(self.builder, while_block); - } + + _ = core.LLVMBuildBr(self.builder, while_block); core.LLVMPositionBuilderAtEnd(self.builder, outer_block); } @@ -271,29 +268,23 @@ pub const CodeGen = struct { const function_type = core.LLVMFunctionType(return_type, paramtypes.items.ptr, @intCast(paramtypes.items.len), 0) orelse return CodeGenError.CompilationError; const function = core.LLVMAddFunction(self.llvm_module, try std.fmt.allocPrintZ(self.arena, "{s}", .{name orelse "unnamed_func"}), function_type) orelse return CodeGenError.CompilationError; const function_entry = core.LLVMAppendBasicBlock(function, "entrypoint") orelse return CodeGenError.CompilationError; - - // Needed for recursive functions - if (name != null) { - const ptr = self.environment.get_variable(name.?); - // Global fn - if (ptr == null) { - try self.environment.add_variable(name.?, try self.create_variable(.{ - .value = function, - .type = function_type, - .stack_level = null, - })); - } else { - _ = core.LLVMBuildStore(self.builder, function, ptr.?.value) orelse return CodeGenError.CompilationError; - ptr.?.type = function_type; - try self.environment.add_variable(name.?, ptr.?); - } - } - core.LLVMPositionBuilderAtEnd(self.builder, function_entry); try self.environment.create_scope(); defer self.environment.drop_scope(); + var ptr: ?*Variable = null; + + // Needed for recursive functions + if (name != null) { + ptr = self.environment.get_variable(name.?); + try self.environment.add_variable(name.?, try self.create_variable(.{ + .value = function, + .type = function_type, + .stack_level = null, + })); + } + const params = try self.arena.alloc(types.LLVMValueRef, function_definition.parameters.len); core.LLVMGetParams(function, params.ptr); @@ -323,17 +314,21 @@ pub const CodeGen = struct { try self.generate_statement(stmt); } + // TODO: This should be done with a defer when `builder_pos` is declared, but for some reason it doesn't work core.LLVMPositionBuilderAtEnd(self.builder, builder_pos); // Global functions - if (self.environment.scope_stack.items.len == 2) { + if (name == null or self.environment.scope_stack.items.len == 2) { return try self.create_variable(.{ .value = function, .type = function_type, .stack_level = null, }); } - return self.environment.get_variable(name.?) orelse unreachable; + + _ = core.LLVMBuildStore(self.builder, function, ptr.?.value) orelse return CodeGenError.CompilationError; + ptr.?.type = function_type; + return ptr.?; }, .FUNCTION_CALL_STATEMENT => |*fn_call| { if (name != null) { @@ -371,18 +366,7 @@ pub const CodeGen = struct { } const loaded = core.LLVMBuildLoad2(self.builder, param_type, variable.value, ""); - if (name != null) { - const ptr = self.environment.get_variable(name.?).?; - _ = core.LLVMBuildStore(self.builder, loaded, ptr.value); - ptr.type = variable.type; - return ptr; - } - - return try self.create_variable(.{ - .value = loaded, - .type = variable.type, - .stack_level = null, - }); + return self.generate_literal(loaded, variable.type, name); }, }, .ADDITIVE_EXPRESSION => |exp| { @@ -396,44 +380,26 @@ pub const CodeGen = struct { result = core.LLVMBuildSub(self.builder, lhs_value.value, rhs_value.value, "") orelse return CodeGenError.CompilationError; } - if (name != null) { - const ptr = self.environment.get_variable(name.?) orelse unreachable; - _ = core.LLVMBuildStore(self.builder, result, ptr.value); - ptr.type = core.LLVMInt64Type(); - - return ptr; - } else { - return try self.create_variable(.{ - .value = result, - .type = core.LLVMInt64Type(), - .stack_level = null, - }); - } + return self.generate_literal(result, core.LLVMInt64Type(), name); }, .MULTIPLICATIVE_EXPRESSION => |exp| { const lhs_value = try self.generate_expression_value(exp.lhs, null); const rhs_value = try self.generate_expression_value(exp.rhs, null); var result: types.LLVMValueRef = undefined; - if (exp.multiplication) { - result = core.LLVMBuildMul(self.builder, lhs_value.value, rhs_value.value, "") orelse return CodeGenError.CompilationError; - } else { - result = core.LLVMBuildSDiv(self.builder, lhs_value.value, rhs_value.value, "") orelse return CodeGenError.CompilationError; + switch (exp.typ) { + .MUL => { + result = core.LLVMBuildMul(self.builder, lhs_value.value, rhs_value.value, "") orelse return CodeGenError.CompilationError; + }, + .DIV => { + result = core.LLVMBuildSDiv(self.builder, lhs_value.value, rhs_value.value, "") orelse return CodeGenError.CompilationError; + }, + .MOD => { + result = core.LLVMBuildSRem(self.builder, lhs_value.value, rhs_value.value, "") orelse return CodeGenError.CompilationError; + }, } - if (name != null) { - const ptr = self.environment.get_variable(name.?) orelse unreachable; - _ = core.LLVMBuildStore(self.builder, result, ptr.value); - ptr.type = core.LLVMInt64Type(); - - return ptr; - } else { - return try self.create_variable(.{ - .value = result, - .type = core.LLVMInt64Type(), - .stack_level = null, - }); - } + return self.generate_literal(result, core.LLVMInt64Type(), name); }, .UNARY_EXPRESSION => |exp| { const k = try self.generate_expression_value(exp.expression, null); @@ -452,48 +418,26 @@ pub const CodeGen = struct { }, } - if (name != null) { - const ptr = self.environment.get_variable(name.?) orelse unreachable; - - _ = core.LLVMBuildStore(self.builder, r, ptr.value); - ptr.type = t; - - return ptr; - } else { - return try self.create_variable(.{ - .value = r, - .type = t, - .stack_level = null, - }); - } + return self.generate_literal(r, t, name); }, .EQUALITY_EXPRESSION => |exp| { const lhs_value = try self.generate_expression_value(exp.lhs, null); const rhs_value = try self.generate_expression_value(exp.rhs, null); - const cmp = core.LLVMBuildICmp(self.builder, types.LLVMIntEQ, lhs_value.value, rhs_value.value, ""); - - if (name != null) { - const ptr = self.environment.get_variable(name.?) orelse unreachable; - - _ = core.LLVMBuildStore(self.builder, cmp, ptr.value); - ptr.type = core.LLVMInt1Type(); + const op: c_uint = switch (exp.typ) { + .EQ => types.LLVMIntEQ, + .LT => types.LLVMIntSLT, + .GT => types.LLVMIntSGT, + }; + const cmp = core.LLVMBuildICmp(self.builder, op, lhs_value.value, rhs_value.value, ""); - return ptr; - } else { - return try self.create_variable(.{ - .value = cmp, - .type = core.LLVMInt1Type(), - .stack_level = null, - }); - } + return self.generate_literal(cmp, core.LLVMInt1Type(), name); }, else => unreachable, }; } fn generate_literal(self: *CodeGen, literal_val: types.LLVMValueRef, literal_type: types.LLVMTypeRef, name: ?[]const u8) !*Variable { - var variable: types.LLVMValueRef = undefined; if (name != null) { if (self.environment.scope_stack.items.len == 1) { const ptr = try self.create_variable(.{ @@ -508,12 +452,10 @@ pub const CodeGen = struct { _ = core.LLVMBuildStore(self.builder, literal_val, ptr.value) orelse return CodeGenError.CompilationError; ptr.type = literal_type; return ptr; - } else { - variable = literal_val; } return try self.create_variable(.{ - .value = variable, + .value = literal_val, .type = literal_type, .stack_level = null, }); diff --git a/src/evaluator.zig b/src/evaluator.zig index 43380a1..fef08a2 100644 --- a/src/evaluator.zig +++ b/src/evaluator.zig @@ -177,8 +177,11 @@ pub const Evaluator = struct { const lhs = try self.get_expression_value(x.lhs) orelse return EvaluatorError.EvaluationError; const rhs = try self.get_expression_value(x.rhs) orelse return EvaluatorError.EvaluationError; std.debug.assert(lhs.* == .NUMBER and rhs.* == .NUMBER); - if (x.multiplication) return try self.create_variable(.{ .NUMBER = lhs.NUMBER * rhs.NUMBER }); - return try self.create_variable(.{ .NUMBER = @divFloor(lhs.NUMBER, rhs.NUMBER) }); + switch (x.typ) { + .MUL => return try self.create_variable(.{ .NUMBER = lhs.NUMBER * rhs.NUMBER }), + .DIV => return try self.create_variable(.{ .NUMBER = @divFloor(lhs.NUMBER, rhs.NUMBER) }), + .MOD => return try self.create_variable(.{ .NUMBER = @rem(lhs.NUMBER, rhs.NUMBER) }), + } }, .UNARY_EXPRESSION => |x| { const val = try self.get_expression_value(x.expression) orelse return EvaluatorError.EvaluationError; @@ -193,7 +196,11 @@ pub const Evaluator = struct { const lhs = try self.get_expression_value(x.lhs) orelse return EvaluatorError.EvaluationError; const rhs = try self.get_expression_value(x.rhs) orelse return EvaluatorError.EvaluationError; std.debug.assert(lhs.* == .NUMBER and rhs.* == .NUMBER); //TODO: Generic - return try self.create_variable(.{ .BOOLEAN = (lhs.NUMBER == rhs.NUMBER) }); + switch (x.typ) { + .EQ => return try self.create_variable(.{ .BOOLEAN = (lhs.NUMBER == rhs.NUMBER) }), + .GT => return try self.create_variable(.{ .BOOLEAN = (lhs.NUMBER > rhs.NUMBER) }), + .LT => return try self.create_variable(.{ .BOOLEAN = (lhs.NUMBER < rhs.NUMBER) }), + } }, .PRIMARY_EXPRESSION => |x| { switch (x) { diff --git a/src/parser.zig b/src/parser.zig index f7a6806..b0a469c 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -30,19 +30,16 @@ pub const Node = union(enum) { condition: *Node, statements: []*Node, }, - EQUALITY_EXPRESSION: struct { - lhs: *Node, - rhs: *Node, - }, + EQUALITY_EXPRESSION: struct { lhs: *Node, rhs: *Node, typ: EqualityExpressionType }, ADDITIVE_EXPRESSION: struct { addition: bool, lhs: *Node, rhs: *Node, }, MULTIPLICATIVE_EXPRESSION: struct { - multiplication: bool, lhs: *Node, rhs: *Node, + typ: MultiplicativeExpressionType, }, UNARY_EXPRESSION: struct { negation: bool, @@ -79,6 +76,18 @@ pub const Node = union(enum) { }, }; +pub const EqualityExpressionType = enum { + EQ, + LT, + GT, +}; + +pub const MultiplicativeExpressionType = enum { + MUL, + DIV, + MOD, +}; + pub const Parser = struct { tokens: []tokenizer.Token, offset: u32, @@ -266,20 +275,38 @@ pub const Parser = struct { return ParserError.ParsingError; } - // EqualityExpression ::= AdditiveExpression "==" AdditiveExpression + // EqualityExpression ::= AdditiveExpression ("==" | "<" | ">") AdditiveExpression fn parse_equality_expression(self: *Parser) ParserError!*Node { errdefer if (!self.try_context) std.debug.print("Error parsing equality expression {any}\n", .{self.peek_token()}); const lhs = try self.parse_additive_expression(); - _ = try self.parse_token(tokenizer.TokenType.EQUALS); - _ = try self.parse_token(tokenizer.TokenType.EQUALS); + var typ: EqualityExpressionType = undefined; + + if (self.accept_parse(struct { + fn parse(iself: *Parser) ParserError!*Node { + _ = try iself.parse_token(tokenizer.TokenType.EQUALS); + _ = try iself.parse_token(tokenizer.TokenType.EQUALS); + return try iself.create_node(.{ .PROGRAM = .{ + .statements = &[_]*Node{}, + } }); + } + }.parse) != null) { + typ = .EQ; + } else if (self.accept_token(tokenizer.TokenType.LESS) != null) { + typ = .LT; + } else if (self.accept_token(tokenizer.TokenType.GREATER) != null) { + typ = .GT; + } else { + return ParserError.ParsingError; + } const rhs = try self.parse_additive_expression(); return self.create_node(.{ .EQUALITY_EXPRESSION = .{ .lhs = lhs, .rhs = rhs, + .typ = typ, } }); } @@ -307,24 +334,30 @@ pub const Parser = struct { return lhs; } - // MultiplicativeExpression ::= UnaryExpression (("*" | "/") UnaryExpression)* + // MultiplicativeExpression ::= UnaryExpression (("*" | "/" | "%") UnaryExpression)* fn parse_multiplicative_expression(self: *Parser) ParserError!*Node { errdefer if (!self.try_context) std.debug.print("Error parsing additive expression {any}\n", .{self.peek_token()}); var lhs = try self.parse_unary_expression(); while (true) { - const mul = self.accept_token(tokenizer.TokenType.MUL); - const div = self.accept_token(tokenizer.TokenType.DIV); - - if (mul == null and div == null) break; + var typ: MultiplicativeExpressionType = undefined; + if (self.accept_token(tokenizer.TokenType.MUL) != null) { + typ = .MUL; + } else if (self.accept_token(tokenizer.TokenType.DIV) != null) { + typ = .DIV; + } else if (self.accept_token(tokenizer.TokenType.MOD) != null) { + typ = .MOD; + } else { + break; + } const rhs = try self.parse_unary_expression(); lhs = try self.create_node(.{ .MULTIPLICATIVE_EXPRESSION = .{ - .multiplication = mul != null, .lhs = lhs, .rhs = rhs, + .typ = typ, } }); } diff --git a/src/tokenizer.zig b/src/tokenizer.zig index 908c016..f0dcd26 100644 --- a/src/tokenizer.zig +++ b/src/tokenizer.zig @@ -25,7 +25,10 @@ pub const TokenType = union(enum) { MINUS: void, MUL: void, DIV: void, + MOD: void, BANG: void, + LESS: void, + GREATER: void, // Punctuation SEMICOLON: void, @@ -83,7 +86,10 @@ pub const Tokenizer = struct { if (self.accept_string("-")) return self.create_token(.{ .MINUS = void{} }); if (self.accept_string("*")) return self.create_token(.{ .MUL = void{} }); if (self.accept_string("/")) return self.create_token(.{ .DIV = void{} }); + if (self.accept_string("%")) return self.create_token(.{ .MOD = void{} }); if (self.accept_string("!")) return self.create_token(.{ .BANG = void{} }); + if (self.accept_string("<")) return self.create_token(.{ .LESS = void{} }); + if (self.accept_string(">")) return self.create_token(.{ .GREATER = void{} }); const string = self.consume_string(); if (string.len == 0) return TokenizerError.TokenizingError; |