diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/grammar.zig | 576 | ||||
| -rw-r--r-- | src/pex/optimizer/root.zig | 6 | ||||
| -rw-r--r-- | src/recognizer.zig | 8 |
3 files changed, 299 insertions, 291 deletions
diff --git a/src/grammar.zig b/src/grammar.zig index eaea3d4..9b61af9 100644 --- a/src/grammar.zig +++ b/src/grammar.zig @@ -10,372 +10,374 @@ non_terminals: []NonTerminal, allocator: std.mem.Allocator, pub fn parse(entry: []const u8, buffer: []const u8, allocator: std.mem.Allocator) !Self { - var lines = std.mem.tokenizeScalar(u8, buffer, '\n'); - var names = std.StringHashMap(usize).init(allocator); - defer names.deinit(); + var lines = std.mem.tokenizeScalar(u8, buffer, '\n'); + var names = std.StringHashMap(usize).init(allocator); + defer names.deinit(); - while (lines.next()) |line| { - const name = try NonTerminal.parse_name(line); + while (lines.next()) |line| { + const name = try NonTerminal.parse_name(line); - if (!names.contains(name)) { - try names.put(name, names.count() + 1); - } - } + if (!names.contains(name)) { + try names.put(name, names.count() + 1); + } + } - lines = std.mem.tokenizeScalar(u8, buffer, '\n'); - var self = Self { - .non_terminals = try allocator.alloc(NonTerminal, names.count() + 1), - .allocator = allocator, - }; - errdefer self.deinit(); + lines = std.mem.tokenizeScalar(u8, buffer, '\n'); + var self = Self { + .non_terminals = try allocator.alloc(NonTerminal, names.count() + 1), + .allocator = allocator, + }; + errdefer self.deinit(); - { - var iterator = names.iterator(); - while (iterator.next()) |name_entry| { - self.non_terminals[name_entry.value_ptr.*] = try NonTerminal.init( - name_entry.key_ptr.*, - name_entry.value_ptr.*, - allocator - ); - } - } + { + var iterator = names.iterator(); + while (iterator.next()) |name_entry| { + self.non_terminals[name_entry.value_ptr.*] = try NonTerminal.init( + name_entry.key_ptr.*, + name_entry.value_ptr.*, + allocator + ); + } + } - { - self.non_terminals[0] = try NonTerminal.init("_start", 0, allocator); - const init_rule = try allocator.alloc(Character, 1); - init_rule[0] = Character { - .non_terminal = names.get(entry) orelse return error.MissingRule, - }; + { + self.non_terminals[0] = try NonTerminal.init("_start", 0, allocator); + const init_rule = try allocator.alloc(Character, 1); + init_rule[0] = Character { + .non_terminal = names.get(entry) orelse return error.MissingRule, + }; - try self.non_terminals[0].add_rule(Rule { - .items = init_rule - }); - } + try self.non_terminals[0].add_rule(Rule { + .items = init_rule + }); + } - while (lines.next()) |line| { - const name = try NonTerminal.parse_name(line); - try self.non_terminal_by_id( - names.get(name) orelse return error.MissingRule - ).parse_and_add_variants(line, &names); - } + while (lines.next()) |line| { + const name = try NonTerminal.parse_name(line); + try self.non_terminal_by_id( + names.get(name) orelse return error.MissingRule + ).parse_and_add_variants(line, &names); + } - self.generate_first(); - self.generate_follows(); + self.generate_first(); + self.generate_follows(); - return self; + std.debug.print("{}\n", .{self}); + + return self; } pub fn deinit(self: *Self) void { - for (self.non_terminals) |*non_terminal| { - non_terminal.deinit(); - } + for (self.non_terminals) |*non_terminal| { + non_terminal.deinit(); + } - self.allocator.free(self.non_terminals); - self.* = undefined; + self.allocator.free(self.non_terminals); + self.* = undefined; } pub inline fn non_terminal_by_id(self: *Self, id: usize) *NonTerminal { - return &self.non_terminals[id]; + return &self.non_terminals[id]; } pub inline fn entry_point(self: *Self) *NonTerminal { - return self.non_terminal_by_id(0); + return self.non_terminal_by_id(0); } fn generate_first(self: *Self) void { - var modified = true; + var modified = true; - while (modified) { - modified = false; + while (modified) { + modified = false; - for (self.non_terminals) |*non_terminal| { - for (non_terminal.rules()) |*rule| { - switch (rule.items[0]) { - .terminal => |t| { - modified = modified or !non_terminal.first.is_set(t); - non_terminal.first.set(t); - rule.first.set(t); - }, + for (self.non_terminals) |*non_terminal| { + for (non_terminal.rules()) |*rule| { + switch (rule.items[0]) { + .terminal => |t| { + modified = modified or !non_terminal.first.is_set(t); + non_terminal.first.set(t); + rule.first.set(t); + }, - .non_terminal, .epsilon => { - var insert_epsilon = true; + .non_terminal, .epsilon => { + var insert_epsilon = true; - for (rule.items) |*char| { - switch (char.*) { - .terminal => |t| { - modified = modified or !non_terminal.first.is_set(t); - non_terminal.first.set(t); - rule.first.set(t); - insert_epsilon = false; - break; - }, - .non_terminal => |n| { - const first = self.non_terminal_by_id(n).first; - for (first.charset, 0..) |child_first, index| { - if (index == Character.EPSILON) continue; + for (rule.items) |*char| { + switch (char.*) { + .terminal => |t| { + modified = modified or !non_terminal.first.is_set(t); + non_terminal.first.set(t); + rule.first.set(t); + insert_epsilon = false; + break; + }, + .non_terminal => |n| { + const first = self.non_terminal_by_id(n).first; + for (first.charset, 0..) |child_first, index| { + if (index == Character.EPSILON) continue; - modified = modified or (!non_terminal.first.is_set(index) and child_first); - non_terminal.first.set_if(index, child_first); - rule.first.set_if(index, child_first); - } + modified = modified or (!non_terminal.first.is_set(index) and child_first); + non_terminal.first.set_if(index, child_first); + rule.first.set_if(index, child_first); + } - if (!first.is_set(Character.EPSILON)) { - insert_epsilon = false; - break; - } - }, - .epsilon => {}, - } - } + if (!first.is_set(Character.EPSILON)) { + insert_epsilon = false; + break; + } + }, + .epsilon => {}, + } + } - if (insert_epsilon and !non_terminal.first.is_set(Character.EPSILON)) { - modified = true; - non_terminal.first.set(Character.EPSILON); - rule.first.set(Character.EPSILON); - } - }, - } - } - } - } + if (insert_epsilon and !non_terminal.first.is_set(Character.EPSILON)) { + modified = true; + non_terminal.first.set(Character.EPSILON); + rule.first.set(Character.EPSILON); + } + }, + } + } + } + } } fn generate_follows(self: *Self) void { - self.entry_point().follows.set(Character.END); - var modified = true; + self.entry_point().follows.set(Character.END); + var modified = true; - while (modified) { - modified = false; + while (modified) { + modified = false; - for (self.non_terminals) |*non_terminal| { - for (non_terminal.rules()) |rule| { - for (0..rule.items.len) |character_index| { + for (self.non_terminals) |*non_terminal| { + for (non_terminal.rules()) |rule| { + for (0..rule.items.len) |character_index| { - switch (rule.items[character_index]) { - .non_terminal => |n| { - const current_non_terminal = self.non_terminal_by_id(n); - const ends_with_epsilon = brk: { - for (character_index + 1..rule.items.len) |peek_index| { - switch (rule.items[peek_index]) { - .terminal => |t| { - modified = modified or !current_non_terminal.follows.is_set(t); - current_non_terminal.follows.set(t); - break :brk false; - }, - .non_terminal => |peek_n| { - const peek_non_terminal = self.non_terminal_by_id(peek_n); - for (peek_non_terminal.first.charset, 0..) |is_set, index| { - if (Character.EPSILON == index) continue; + switch (rule.items[character_index]) { + .non_terminal => |n| { + const current_non_terminal = self.non_terminal_by_id(n); + const ends_with_epsilon = brk: { + for (character_index + 1..rule.items.len) |peek_index| { + switch (rule.items[peek_index]) { + .terminal => |t| { + modified = modified or !current_non_terminal.follows.is_set(t); + current_non_terminal.follows.set(t); + break :brk false; + }, + .non_terminal => |peek_n| { + const peek_non_terminal = self.non_terminal_by_id(peek_n); + for (peek_non_terminal.first.charset, 0..) |is_set, index| { + if (Character.EPSILON == index) continue; - modified = modified or (!current_non_terminal.follows.is_set(index) and is_set); - current_non_terminal.follows.set_if(index, is_set); - } + modified = modified or (!current_non_terminal.follows.is_set(index) and is_set); + current_non_terminal.follows.set_if(index, is_set); + } - if (!peek_non_terminal.first.is_set(Character.EPSILON)) { - break :brk false; - } - }, - .epsilon => {}, - } - } - break :brk true; - }; + if (!peek_non_terminal.first.is_set(Character.EPSILON)) { + break :brk false; + } + }, + .epsilon => {}, + } + } + break :brk true; + }; - if (ends_with_epsilon) { - for (non_terminal.follows.charset, 0..) |is_set, char_index| { - modified = modified or (!current_non_terminal.follows.is_set(char_index) and is_set); - current_non_terminal.follows.set_if(char_index, is_set); - } - } - }, - else => {} - } + if (ends_with_epsilon) { + for (non_terminal.follows.charset, 0..) |is_set, char_index| { + modified = modified or (!current_non_terminal.follows.is_set(char_index) and is_set); + current_non_terminal.follows.set_if(char_index, is_set); + } + } + }, + else => {} + } - } - } - } - } + } + } + } + } } pub fn is_next_char(self: *const Self, rule_slice: []Character, current: usize, char: u8) bool { - var is_char_in_first = false; - var is_epsilon_in_first = true; + var is_char_in_first = false; + var is_epsilon_in_first = true; - for (rule_slice) |character| { - switch(character) { - .terminal => |c| { - is_char_in_first = c == char; - break; - }, - .non_terminal => |n| { - is_char_in_first = self.non_terminals[n].first.is_set(char); + for (rule_slice) |character| { + switch(character) { + .terminal => |c| { + is_char_in_first = c == char; + break; + }, + .non_terminal => |n| { + is_char_in_first = self.non_terminals[n].first.is_set(char); - if (is_char_in_first or !self.non_terminals[n].first.is_set(Character.EPSILON)) { - break; - } - }, - else => {}, - } - } + if (is_char_in_first or !self.non_terminals[n].first.is_set(Character.EPSILON)) { + break; + } + }, + else => {}, + } + } - for (rule_slice) |character| { - switch(character) { - .terminal => is_epsilon_in_first = false, - .non_terminal => |n| { - if (!self.non_terminals[n].first.is_set(Character.EPSILON)) { - is_epsilon_in_first = false; - break; - } - }, - else => {}, - } - } + for (rule_slice) |character| { + switch(character) { + .terminal => is_epsilon_in_first = false, + .non_terminal => |n| { + if (!self.non_terminals[n].first.is_set(Character.EPSILON)) { + is_epsilon_in_first = false; + break; + } + }, + else => {}, + } + } - const result = is_char_in_first or ( - is_epsilon_in_first and - self.non_terminals[current].follows.is_set(char) - ); + const result = is_char_in_first or ( + is_epsilon_in_first and + self.non_terminals[current].follows.is_set(char) + ); - return result; + return result; } pub fn format( - self: *const Self, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, + self: *const Self, + comptime fmt: []const u8, + options: std.fmt.FormatOptions, + writer: anytype, ) !void { - _ = fmt; - _ = options; + _ = fmt; + _ = options; - for (self.non_terminals) |non_terminal| { - try writer.print("[{}] ", .{non_terminal}); - } + for (self.non_terminals) |non_terminal| { + try writer.print("[{}] ", .{non_terminal}); + } } test "expr" { - const text = - \\S -> B A - \\A -> '+' B A - \\A -> '' - \\B -> D C - \\C -> '*' D C - \\C -> '' - \\D -> '(' S ')' - \\D -> 'a' | 'b' - ; + const text = + \\S -> B A + \\A -> '+' B A + \\A -> '' + \\B -> D C + \\C -> '*' D C + \\C -> '' + \\D -> '(' S ')' + \\D -> 'a' | 'b' + ; - const allocator = std.testing.allocator; - var grammar = try Self.parse("S", text, allocator); - defer grammar.deinit(); + const allocator = std.testing.allocator; + var grammar = try Self.parse("S", text, allocator); + defer grammar.deinit(); - try grammar.non_terminal_by_id(1).first.expect(&[_]u9 { '(', 'a', 'b' }); - try grammar.non_terminal_by_id(2).first.expect(&[_]u9 { '+', Character.EPSILON }); - try grammar.non_terminal_by_id(3).first.expect(&[_]u9 { '(', 'a', 'b' }); - try grammar.non_terminal_by_id(4).first.expect(&[_]u9 { '*', Character.EPSILON }); - try grammar.non_terminal_by_id(5).first.expect(&[_]u9 { '(', 'a', 'b' }); + try grammar.non_terminal_by_id(1).first.expect(&[_]u9 { '(', 'a', 'b' }); + try grammar.non_terminal_by_id(2).first.expect(&[_]u9 { '+', Character.EPSILON }); + try grammar.non_terminal_by_id(3).first.expect(&[_]u9 { '(', 'a', 'b' }); + try grammar.non_terminal_by_id(4).first.expect(&[_]u9 { '*', Character.EPSILON }); + try grammar.non_terminal_by_id(5).first.expect(&[_]u9 { '(', 'a', 'b' }); - try grammar.non_terminal_by_id(1).follows.expect(&[_]u9 { ')', Character.END }); - try grammar.non_terminal_by_id(2).follows.expect(&[_]u9 { ')', Character.END }); - try grammar.non_terminal_by_id(3).follows.expect(&[_]u9 { '+', ')', Character.END }); - try grammar.non_terminal_by_id(4).follows.expect(&[_]u9 { '+', ')', Character.END }); - try grammar.non_terminal_by_id(5).follows.expect(&[_]u9 { '*', '+', ')', Character.END }); + try grammar.non_terminal_by_id(1).follows.expect(&[_]u9 { ')', Character.END }); + try grammar.non_terminal_by_id(2).follows.expect(&[_]u9 { ')', Character.END }); + try grammar.non_terminal_by_id(3).follows.expect(&[_]u9 { '+', ')', Character.END }); + try grammar.non_terminal_by_id(4).follows.expect(&[_]u9 { '+', ')', Character.END }); + try grammar.non_terminal_by_id(5).follows.expect(&[_]u9 { '*', '+', ')', Character.END }); } test "sample 0" { - const text = - \\S -> A C B | C 'bb' | B 'a' - \\A -> 'da' | B C - \\B -> 'g' | '' - \\C -> 'h' | '' - ; + const text = + \\S -> A C B | C 'bb' | B 'a' + \\A -> 'da' | B C + \\B -> 'g' | '' + \\C -> 'h' | '' + ; - const allocator = std.testing.allocator; - var grammar = try Self.parse("S", text, allocator); - defer grammar.deinit(); + const allocator = std.testing.allocator; + var grammar = try Self.parse("S", text, allocator); + defer grammar.deinit(); - try grammar.non_terminal_by_id(1).first.expect(&[_]u9 { 'd', 'g', 'h', 'b', 'a', Character.EPSILON }); - try grammar.non_terminal_by_id(2).first.expect(&[_]u9 { 'd', 'g', 'h', Character.EPSILON }); - try grammar.non_terminal_by_id(3).first.expect(&[_]u9 { 'g', Character.EPSILON }); - try grammar.non_terminal_by_id(4).first.expect(&[_]u9 { 'h', Character.EPSILON }); + try grammar.non_terminal_by_id(1).first.expect(&[_]u9 { 'd', 'g', 'h', 'b', 'a', Character.EPSILON }); + try grammar.non_terminal_by_id(2).first.expect(&[_]u9 { 'd', 'g', 'h', Character.EPSILON }); + try grammar.non_terminal_by_id(3).first.expect(&[_]u9 { 'g', Character.EPSILON }); + try grammar.non_terminal_by_id(4).first.expect(&[_]u9 { 'h', Character.EPSILON }); - try grammar.non_terminal_by_id(1).follows.expect(&[_]u9 { Character.END }); - try grammar.non_terminal_by_id(2).follows.expect(&[_]u9 { 'g', 'h', Character.END }); - try grammar.non_terminal_by_id(3).follows.expect(&[_]u9 { 'a', 'g', 'h', Character.END }); - try grammar.non_terminal_by_id(4).follows.expect(&[_]u9 { 'b', 'g', 'h', Character.END }); + try grammar.non_terminal_by_id(1).follows.expect(&[_]u9 { Character.END }); + try grammar.non_terminal_by_id(2).follows.expect(&[_]u9 { 'g', 'h', Character.END }); + try grammar.non_terminal_by_id(3).follows.expect(&[_]u9 { 'a', 'g', 'h', Character.END }); + try grammar.non_terminal_by_id(4).follows.expect(&[_]u9 { 'b', 'g', 'h', Character.END }); } test "sample 1" { - const text = - \\S -> 'a' A B 'b' - \\A -> 'c' - \\A -> '' - \\B -> 'd' - \\B -> '' - ; + const text = + \\S -> 'a' A B 'b' + \\A -> 'c' + \\A -> '' + \\B -> 'd' + \\B -> '' + ; - const allocator = std.testing.allocator; - var grammar = try Self.parse("S", text, allocator); - defer grammar.deinit(); + const allocator = std.testing.allocator; + var grammar = try Self.parse("S", text, allocator); + defer grammar.deinit(); - try grammar.non_terminal_by_id(1).first.expect(&[_]u9 { 'a' }); - try grammar.non_terminal_by_id(2).first.expect(&[_]u9 { 'c', Character.EPSILON }); - try grammar.non_terminal_by_id(3).first.expect(&[_]u9 { 'd', Character.EPSILON }); + try grammar.non_terminal_by_id(1).first.expect(&[_]u9 { 'a' }); + try grammar.non_terminal_by_id(2).first.expect(&[_]u9 { 'c', Character.EPSILON }); + try grammar.non_terminal_by_id(3).first.expect(&[_]u9 { 'd', Character.EPSILON }); - try grammar.non_terminal_by_id(1).follows.expect(&[_]u9 { Character.END }); - try grammar.non_terminal_by_id(2).follows.expect(&[_]u9 { 'b', 'd' }); - try grammar.non_terminal_by_id(3).follows.expect(&[_]u9 { 'b' }); + try grammar.non_terminal_by_id(1).follows.expect(&[_]u9 { Character.END }); + try grammar.non_terminal_by_id(2).follows.expect(&[_]u9 { 'b', 'd' }); + try grammar.non_terminal_by_id(3).follows.expect(&[_]u9 { 'b' }); } test "sample 2" { - const text = - \\S -> A B - \\S -> 'e' D 'a' - \\A -> 'ab' - \\A -> 'c' - \\B -> 'd' C - \\C -> 'e' C - \\C -> '' - \\D -> 'f' D - \\D -> '' - ; + const text = + \\S -> A B + \\S -> 'e' D 'a' + \\A -> 'ab' + \\A -> 'c' + \\B -> 'd' C + \\C -> 'e' C + \\C -> '' + \\D -> 'f' D + \\D -> '' + ; - const allocator = std.testing.allocator; - var grammar = try Self.parse("S", text, allocator); - defer grammar.deinit(); + const allocator = std.testing.allocator; + var grammar = try Self.parse("S", text, allocator); + defer grammar.deinit(); - try grammar.non_terminal_by_id(1).first.expect(&[_]u9 { 'a', 'c', 'e' }); - try grammar.non_terminal_by_id(2).first.expect(&[_]u9 { 'a', 'c' }); - try grammar.non_terminal_by_id(3).first.expect(&[_]u9 { 'd' }); - try grammar.non_terminal_by_id(4).first.expect(&[_]u9 { 'e', Character.EPSILON }); - try grammar.non_terminal_by_id(5).first.expect(&[_]u9 { 'f', Character.EPSILON }); + try grammar.non_terminal_by_id(1).first.expect(&[_]u9 { 'a', 'c', 'e' }); + try grammar.non_terminal_by_id(2).first.expect(&[_]u9 { 'a', 'c' }); + try grammar.non_terminal_by_id(3).first.expect(&[_]u9 { 'd' }); + try grammar.non_terminal_by_id(4).first.expect(&[_]u9 { 'e', Character.EPSILON }); + try grammar.non_terminal_by_id(5).first.expect(&[_]u9 { 'f', Character.EPSILON }); - try grammar.non_terminal_by_id(1).follows.expect(&[_]u9 { Character.END }); - try grammar.non_terminal_by_id(2).follows.expect(&[_]u9 { 'd' }); - try grammar.non_terminal_by_id(3).follows.expect(&[_]u9 { Character.END }); - try grammar.non_terminal_by_id(4).follows.expect(&[_]u9 { Character.END }); - try grammar.non_terminal_by_id(5).follows.expect(&[_]u9 { 'a' }); + try grammar.non_terminal_by_id(1).follows.expect(&[_]u9 { Character.END }); + try grammar.non_terminal_by_id(2).follows.expect(&[_]u9 { 'd' }); + try grammar.non_terminal_by_id(3).follows.expect(&[_]u9 { Character.END }); + try grammar.non_terminal_by_id(4).follows.expect(&[_]u9 { Character.END }); + try grammar.non_terminal_by_id(5).follows.expect(&[_]u9 { 'a' }); } test "sample 3" { - const text = - \\S -> A S 'd' - \\S -> B S - \\S -> '' - \\A -> 'a' - \\A -> 'c' - \\B -> 'a' - \\B -> 'b' - ; + const text = + \\S -> A S 'd' + \\S -> B S + \\S -> '' + \\A -> 'a' + \\A -> 'c' + \\B -> 'a' + \\B -> 'b' + ; - const allocator = std.testing.allocator; - var grammar = try Self.parse("S", text, allocator); - defer grammar.deinit(); + const allocator = std.testing.allocator; + var grammar = try Self.parse("S", text, allocator); + defer grammar.deinit(); - try grammar.non_terminal_by_id(1).first.expect(&[_]u9 { 'a', 'b', 'c', Character.EPSILON }); - try grammar.non_terminal_by_id(2).first.expect(&[_]u9 { 'a', 'c' }); - try grammar.non_terminal_by_id(3).first.expect(&[_]u9 { 'a', 'b' }); + try grammar.non_terminal_by_id(1).first.expect(&[_]u9 { 'a', 'b', 'c', Character.EPSILON }); + try grammar.non_terminal_by_id(2).first.expect(&[_]u9 { 'a', 'c' }); + try grammar.non_terminal_by_id(3).first.expect(&[_]u9 { 'a', 'b' }); - try grammar.non_terminal_by_id(1).follows.expect(&[_]u9 { 'd', Character.END }); - try grammar.non_terminal_by_id(2).follows.expect(&[_]u9 { 'a', 'b', 'c', 'd' }); - try grammar.non_terminal_by_id(3).follows.expect(&[_]u9 { 'a', 'b', 'c', 'd', Character.END }); + try grammar.non_terminal_by_id(1).follows.expect(&[_]u9 { 'd', Character.END }); + try grammar.non_terminal_by_id(2).follows.expect(&[_]u9 { 'a', 'b', 'c', 'd' }); + try grammar.non_terminal_by_id(3).follows.expect(&[_]u9 { 'a', 'b', 'c', 'd', Character.END }); } diff --git a/src/pex/optimizer/root.zig b/src/pex/optimizer/root.zig index 68ce968..18c05df 100644 --- a/src/pex/optimizer/root.zig +++ b/src/pex/optimizer/root.zig @@ -13,9 +13,9 @@ pub fn optimize_block( target.* = try raw.clone(allocator, node_pool); _ = blocks; - for (target.heads.items) |head| { - try hard_link_right_recursion(target, head); - } + //for (target.heads.items) |head| { + // try hard_link_right_recursion(target, head); + //} } pub fn hard_link_right_recursion( diff --git a/src/recognizer.zig b/src/recognizer.zig index 6af7de1..967aba0 100644 --- a/src/recognizer.zig +++ b/src/recognizer.zig @@ -113,26 +113,31 @@ pub fn check( for (input) |character| { for (processing_queue.items) |base| { try forward_queue.append(.{ base.state, base }); - try node_cache.put(base.state, base); + + std.debug.print("-----\n", .{}); while (forward_queue.pop()) |checkpoint| { const pex_node, const last_node = checkpoint; switch (pex_node.instruction) { .check => |t| if (t == character) { + std.debug.print("check '{}'\n", .{t}); if (pex_node.next) |next| { const node = try graph.clone(last_node, next); try next_processing_queue.append(node); } }, .@"return" => { + std.debug.print("return\n", .{}); for (last_node.parents.items) |parent| { if (parent.state.next) |next| { + std.debug.print("return to {}\n", .{next}); try forward_queue.append(.{next, parent}); } } }, .call => |id| { + std.debug.print("call <{}>\n", .{id}); const non_terminal = pex.grammar.non_terminal_by_id(id); for (non_terminal.rules(), pex.blocks[id].heads.items) |child_rule, head| { if ( @@ -152,6 +157,7 @@ pub fn check( } }, .jump => |jump_next| { + std.debug.print("jump {any}\n", .{jump_next.items}); if (pex_node.next) |next| { try forward_queue.append(.{next, last_node}); } |