diff options
| author | Nathan Reiner <nathan@nathanreiner.xyz> | 2025-04-26 16:55:08 +0200 |
|---|---|---|
| committer | Nathan Reiner <nathan@nathanreiner.xyz> | 2025-04-26 16:55:08 +0200 |
| commit | 922db9c5fc50b82182fb5a0b4e3c8bb18fc2e0ab (patch) | |
| tree | 0bb2f9098811d2af6ba44bcde17a1f77d4bd12a4 /src/recognizer.zig | |
| parent | cf4d53c3eb35028839e6b267230c23df68b1e94a (diff) | |
use gss
Diffstat (limited to 'src/recognizer.zig')
| -rw-r--r-- | src/recognizer.zig | 161 |
1 files changed, 81 insertions, 80 deletions
diff --git a/src/recognizer.zig b/src/recognizer.zig index 3adb7a4..1783db1 100644 --- a/src/recognizer.zig +++ b/src/recognizer.zig @@ -31,111 +31,112 @@ const State = struct { } }; -pub fn check(grammar: *Grammar, input: []const u8, allocator: std.mem.Allocator) !bool { - var stacks = std.ArrayList(std.ArrayList(State)).init(allocator); - defer { - for (stacks.items) |stack| { - stack.deinit(); - } - stacks.deinit(); - } +pub fn check(grammar: *Grammar, input: []const u8, inner_allocator: std.mem.Allocator) !bool { + var arena = std.heap.ArenaAllocator.init(inner_allocator); + defer arena.deinit(); + const allocator = arena.allocator(); const entry = grammar.entry_point(); + var queues = [2]std.ArrayList(*gss.Node(State)) { + std.ArrayList(*gss.Node(State)).init(allocator), + std.ArrayList(*gss.Node(State)).init(allocator), + }; + defer for (queues) |queue| queue.deinit(); + var processing_queue = &queues[0]; for (entry.rules()) |rule| { - const state = State { + const node = try allocator.create(gss.Node(State)); + node.* = gss.Node(State).init(State { .name = entry.name, .rule = rule, .inner_position = 0, .input_position = 0, - }; + }); - var stack = std.ArrayList(State).init(allocator); - try stack.append(state); - try stacks.append(stack); + try processing_queue.append(node); } - var remove_queue = std.ArrayList(usize).init(allocator); - defer remove_queue.deinit(); - var add_queue = std.ArrayList(std.ArrayList(State)).init(allocator); - defer add_queue.deinit(); + var next_processing_queue = &queues[1]; - while (stacks.items.len > 0) { - for (stacks.items, 0..) |*stack, stack_index| { - var state: *State = &stack.items[stack.items.len - 1]; - - if (state.inner_position == state.rule.len) { + while (processing_queue.items.len > 0) { + for (processing_queue.items) |node| { + if (node.state.inner_position == node.state.rule.len) { if ( - stack.items.len == 1 and - state.name == entry.name and - state.input_position == input.len + node.parent == null and + node.state.name == entry.name and + node.state.input_position == input.len ) { return true; } - const old_state = stack.pop(); - if (stack.items.len > 0) { - state = &stack.items[stack.items.len - 1]; - state.inner_position += 1; - state.input_position = old_state.input_position; - } else { - try remove_queue.append(stack_index); + const old_state, const parent_node = node.pop(allocator); + if (parent_node) |parent| { + const sibling = try parent.clone(State { + .name = parent.state.name, + .rule = parent.state.rule, + .inner_position = parent.state.inner_position + 1, + .input_position = old_state.input_position, + }, allocator); + try next_processing_queue.append(sibling); } - continue; - } - - const epsilon_only = state.input_position == input.len; + } else { + const epsilon_only = node.state.input_position == input.len; - switch (state.rule[state.inner_position]) { - .terminal => |t| { - if (!epsilon_only and input[state.input_position] == t) { - state.inner_position += 1; - state.input_position += 1; - } else { - try remove_queue.append(stack_index); - } - }, - .non_terminal => |n| { - const non_terminal = grammar.non_terminal_by_name(n); - const rules = non_terminal.rules(); + switch (node.state.rule[node.state.inner_position]) { + .terminal => |t| { + if (!epsilon_only and input[node.state.input_position] == t) { + const sibling = try node.clone(State { + .name = node.state.name, + .rule = node.state.rule, + .inner_position = node.state.inner_position + 1, + .input_position = node.state.input_position + 1, + }, allocator); + try next_processing_queue.append(sibling); + } + }, + .non_terminal => |n| { + const non_terminal = grammar.non_terminal_by_name(n); + const rules = non_terminal.rules(); - if (!epsilon_only and non_terminal.first.is_set(input[state.input_position])) { - for (rules) |rule| { - const next_state = State { - .name = non_terminal.name, - .rule = rule, - .inner_position = 0, - .input_position = state.input_position, - }; - var new_stack = try stack.clone(); - try new_stack.append(next_state); - try add_queue.append(new_stack); + if (!epsilon_only and non_terminal.first.is_set(input[node.state.input_position])) { + for (rules) |rule| { + const child = try node.push(State { + .name = non_terminal.name, + .rule = rule, + .inner_position = 0, + .input_position = node.state.input_position, + }, allocator); + try next_processing_queue.append(child); + } } - } - if (non_terminal.first.is_set(Character.EPSILON)) { - state.inner_position += 1; - } else { - try remove_queue.append(stack_index); - } - }, - .epsilon => { - state.inner_position += 1; - }, + if (non_terminal.first.is_set(Character.EPSILON)) { + const sibling = try node.clone(State { + .name = node.state.name, + .rule = node.state.rule, + .inner_position = node.state.inner_position + 1, + .input_position = node.state.input_position + }, allocator); + try next_processing_queue.append(sibling); + } + }, + .epsilon => { + const sibling = try node.clone(State { + .name = node.state.name, + .rule = node.state.rule, + .inner_position = node.state.inner_position + 1, + .input_position = node.state.input_position + }, allocator); + try next_processing_queue.append(sibling); + }, + } } } - for (remove_queue.items, 0..) |index, offset| { - const stack = stacks.orderedRemove(index - offset); - stack.deinit(); - } - - for (add_queue.items) |stack| { - try stacks.append(stack); - } - - remove_queue.clearAndFree(); - add_queue.clearAndFree(); + const swap = processing_queue; + processing_queue = next_processing_queue; + next_processing_queue = swap; + next_processing_queue.clearRetainingCapacity(); } return false; |