Kernel.RedgraphSourceReduction graph interface
This module exports the reduction graph data structures and functions for analyzing viable reductions in LR(1) parsers.
Proceeds in three steps:
A → α A translates to a cycle. The process also keeps track of lookahead symbols permitting each reduction to strictly simulate the behavior of an LR(1) automaton that possibly went through conflict resolution.But to recognize a reduction pattern, we have to do the reverse mapping: the user provides the target of a reduction (e.g. I want to reduce an expression), and we need to find the paths that can reach this target. So we introduce a "target" abstraction to which a reduction pattern translate to, a reverse index target_trie to go from a pattern to a set of targets, and we associate to each node of the graph the reachable targets.
Type definitions:
next: Subtrees reachable after reductionsreductions: Pending non ϵ-reductions at each node, grouped by depthaccepting, failing: Lookaheads that cause acceptance/failurestacks: Stack trees of ϵ-reductionsall_stacks, all_reductions: flattened ϵ-stacks and ϵ-reductionssub: Child nodes for each LR stateimmediates: States from which the reductions are immediate (ϵ-reductions by definition)targets: Targets reached by the current prefix.Advance: Move to next step (simulate a "pop" action on the stack, it does not depend on the actual stack contents)Switch: Transition to different goto targets (simulate a "goto" action on the stack, which depends on the state at the top of the stack)Key functions:
close_lr1_reductions: Compute reduction closures for all LR1 statesindex_targets: Build target trie and map targets to goto transitionsmake: Construct the minimized reduction graphinitial, follow: Navigate the reduction graphTricky implementation details:
filter_reductions function updates reduction lookahead sets when the lookahead domain is restricted to preserve LR(1) behaviors.type 'g stack_tree = {next : ('g Info.lr1 Fix.Indexing.index list
* 'g Info.terminal Utils.Misc.indexset
* 'g stack_tree)
list;reductions : ('g Info.nonterminal, 'g Info.terminal Utils.Misc.indexset)
Utils.Misc.indexmap
list;}Tree of possible ϵ-reduction stacks for an LR state.
next: Subtrees reachable after reductionsreductions: Pending non ϵ-reductions at each node, grouped by depthtype 'g reduction_closure = {accepting : 'g Info.terminal Utils.Misc.indexset;failing : 'g Info.terminal Utils.Misc.indexset;stacks : 'g stack_tree;all_stacks : ('g Info.lr1 Fix.Indexing.index list
* 'g Info.terminal Utils.Misc.indexset)
list;all_reductions : ('g Info.nonterminal, 'g Info.terminal Utils.Misc.indexset)
Utils.Misc.indexmap
list;}Complete ϵ-reductions information for an LR state.
accepting, failing: Lookaheads that cause acceptance/failurestacks: Stack trees of ϵ-reductionsall_stacks, all_reductions: flattened ϵ-stacks and ϵ-reductionsVector of reduction closures, indexed by LR(1) state.
Compute reduction closures for all LR(1) states. For each state, builds the tree of possible ε-reductions and collects all reachable stack suffixes and pending reductions.
Abstract identifier for a reduction target.
Map from target identifiers to their valid lookahead sets.
type 'g target_trie = private {mutable sub : ('g Info.lr1, 'g target_trie) Utils.Misc.indexmap;mutable immediates : 'g Info.lr1 Utils.Misc.indexset;mutable targets : ('g Info.lr1, 'g target Fix.Indexing.index)
Utils.Misc.indexmap;}Trie for indexing reduction targets reached by sequences of LR(1) states. E.g. if there is a goto transition `s0 -> s1` labelled `expression`, there will be a path `s0 -> s1` labelled `expression target` in the trie.
sub: Child nodes for each LR stateimmediates: States from which the reductions are immediate (ϵ-reductions by definition)targets: Targets reached by the current prefix.val index_targets :
'g Info.grammar ->
('g, 'g Info.lr1) reduction_closures ->
'g target_trie * ('g Info.goto_transition, 'g targets) Fix.Indexing.vectorBuild target trie and map targets to goto transitions. Creates a reverse index from reduction targets to the graph nodes where they can be reached, enabling pattern-based reduction queries.
Minimized reduction graph.
val make :
'g Info.grammar ->
('g, 'g Info.lr1) reduction_closures ->
('g Info.goto_transition, 'g targets) Fix.Indexing.vector ->
'g graphConstruct the minimized reduction graph. Builds a graph whose paths enumerate all stack suffixes consumable by reductions, then minimizes it using Valmari's algorithm.
Position in the reduction computation.
type 'g transition = {reached : 'g target Utils.Misc.indexset;reachable : 'g target Utils.Misc.indexset;step : 'g step Fix.Indexing.index;}Graph transition with reachability information.
reached: Targets reached by this transitionreachable: All targets reachable through this transitionstep: Destination step indextype 'g action = | Advance of 'g step Fix.Indexing.index| Switch of ('g Info.lr1, 'g transition list) Utils.Misc.indexmapAction at a given step of a reduction sequence.
Advance: Move to next step (simulate a "pop" on the stack)Switch: Branch on top-of-stack state (simulate a "goto")Get initial transitions for a given LR(1) state. Returns the list of transitions reachable from the graph's entry point when the top of the stack is in the given state.
Follow a step in the reduction graph. Returns the action to take at the given step: either advance to the next step or switch based on the current stack top state.
val filter_reductions :
'g Info.grammar ->
'g Info.terminal Utils.Misc.indexset ->
('n, 'g Info.terminal Utils.Misc.indexset) Utils.Misc.indexmap list ->
('n, 'g Info.terminal Utils.Misc.indexset) Utils.Misc.indexmap listFilter reduction lookahead sets to a restricted domain. Restricts the lookahead sets of reductions when the domain is narrowed, e.g., after conflict resolution. Preserves sharing when no filtering is needed.