Class: Ibex::LALR::LR0Collection
- Inherits:
-
Object
- Object
- Ibex::LALR::LR0Collection
- Defined in:
- lib/ibex/lalr/lr0_collection.rb,
sig/ibex/lalr/lr0_collection.rbs
Overview
Constructs only the LR(0) core collection. Keeping this separate from lookahead propagation makes the direct IELR phases reusable and gives them a stable, canonical-free input representation.
Constant Summary collapse
- AUGMENTED_PRODUCTION =
-1 #: Integer
Instance Method Summary collapse
- #augmented_production(index) ⇒ Integer
- #build ⇒ [ Array[core_set], transitions ]
- #closure(seed) ⇒ core_set
-
#initialize(grammar, starts: nil) ⇒ LR0Collection
constructor
A new instance of LR0Collection.
- #item_key(items) ⇒ Array[Integer]
- #lhs_for(production_id) ⇒ Integer
- #rhs_for(production_id) ⇒ Array[Integer]
- #shifted_kernels(items) ⇒ Hash[Integer, core_set]
Constructor Details
#initialize(grammar, starts: nil) ⇒ LR0Collection
Returns a new instance of LR0Collection.
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/ibex/lalr/lr0_collection.rb', line 24 def initialize(grammar, starts: nil) @grammar = grammar @starts = (starts || grammar.starts).dup raise ArgumentError, "starts must be a nonempty subset of grammar starts" if @starts.empty? || (@starts - grammar.starts).any? @productions_by_lhs = grammar.productions.group_by(&:lhs) @production_rhs = grammar.productions.map(&:rhs).freeze @augmented_production_ids = @starts.map { |name| AUGMENTED_PRODUCTION - grammar.starts.index(name) } @augmented_rhs = @starts.each_with_index.to_h do |name, index| symbol = grammar.symbol(name) || raise(Ibex::Error, "missing start symbol #{name}") [@augmented_production_ids.fetch(index), [symbol.id].freeze] end.freeze @item_key_stride = [*@production_rhs, *@augmented_rhs.values].map(&:length).max.to_i + 1 end |
Instance Method Details
#augmented_production(index) ⇒ Integer
63 64 65 |
# File 'lib/ibex/lalr/lr0_collection.rb', line 63 def augmented_production(index) @augmented_production_ids.fetch(index) end |
#build ⇒ [ Array[core_set], transitions ]
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/ibex/lalr/lr0_collection.rb', line 41 def build states = @starts.map { |name| closure(Set[[augmented_production(@starts.index(name)), 0]]) } transitions = [] #: transitions indexes = {} states.each_with_index { |items, index| indexes[item_key(items)] = index } cursor = 0 while cursor < states.length transitions[cursor] = {} shifted_kernels(states.fetch(cursor)).keys.sort.each do |symbol_id| target = closure(shifted_kernels(states.fetch(cursor)).fetch(symbol_id)) target_id = indexes[item_key(target)] ||= begin states << target states.length - 1 end transitions.fetch(cursor)[symbol_id] = target_id end cursor += 1 end [states, transitions] end |
#closure(seed) ⇒ core_set
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/ibex/lalr/lr0_collection.rb', line 94 def closure(seed) items = seed.dup queue = seed.to_a cursor = 0 while cursor < queue.length production_id, dot = queue.fetch(cursor) cursor += 1 symbol = @grammar.symbol_by_id(rhs_for(production_id)[dot]) next unless symbol&.nonterminal? @productions_by_lhs.fetch(symbol.id, []).each do |production| item = [production.id, 0].freeze queue << item if items.add?(item) end end items end |
#item_key(items) ⇒ Array[Integer]
113 114 115 116 117 |
# File 'lib/ibex/lalr/lr0_collection.rb', line 113 def item_key(items) items.map do |production_id, dot| ((production_id + @grammar.starts.length) * @item_key_stride) + dot end.sort end |
#lhs_for(production_id) ⇒ Integer
75 76 77 78 79 |
# File 'lib/ibex/lalr/lr0_collection.rb', line 75 def lhs_for(production_id) return rhs_for(production_id).fetch(0) if production_id.negative? @grammar.productions.fetch(production_id).lhs end |
#rhs_for(production_id) ⇒ Array[Integer]
68 69 70 71 72 |
# File 'lib/ibex/lalr/lr0_collection.rb', line 68 def rhs_for(production_id) return @augmented_rhs.fetch(production_id) if production_id.negative? @production_rhs.fetch(production_id) end |
#shifted_kernels(items) ⇒ Hash[Integer, core_set]
82 83 84 85 86 87 88 89 |
# File 'lib/ibex/lalr/lr0_collection.rb', line 82 def shifted_kernels(items) kernels = Hash.new { |hash, key| hash[key] = Set.new } #: Hash[Integer, core_set] items.each do |production_id, dot| symbol_id = rhs_for(production_id)[dot] kernels[symbol_id] << [production_id, dot + 1].freeze if symbol_id end kernels end |