Continue building DFA

This commit is contained in:
Josh Holtrop 2021-05-25 15:44:23 -04:00
parent 214ece7d90
commit 37e1252ded
2 changed files with 49 additions and 10 deletions

View File

@ -4,6 +4,29 @@ module Imbecile
class DFA class DFA
class State class State
class Transition
attr_reader :code_point_range
attr_reader :destination
def initialize(code_point_range, destination)
@code_point_range = code_point_range
end
end
attr_accessor :accepts
attr_reader :transitions
def initialize
@transitions = []
end
def add_transition(code_point_range, destination)
@transitions << Transition.new(code_point_range, destination)
end
end end
def initialize(nfas) def initialize(nfas)
@ -11,34 +34,49 @@ module Imbecile
nfas.each do |nfa| nfas.each do |nfa|
start_nfa.start_state.add_transition(nil, nfa.start_state) start_nfa.start_state.add_transition(nil, nfa.start_state)
end end
@states = {} @nfa_state_sets = {}
@states = []
@to_process = Set.new @to_process = Set.new
nil_transition_states = start_nfa.start_state.nil_transition_states nil_transition_states = start_nfa.start_state.nil_transition_states
@states[nil_transition_states] = 0 register_nfa_state_set(nil_transition_states)
process_nfa_state_set(nil_transition_states) while @to_process.size > 0
state_set = @to_process.first
@to_process.delete(state_set)
process_nfa_state_set(state_set)
end
end end
private private
def register_nfa_state_set(nfa_state_set)
unless @nfa_state_sets.include?(nfa_state_set)
state_id = @states.size
@nfa_state_sets[nfa_state_set] = state_id
@states << State.new
@to_process << nfa_state_set
end
end
def process_nfa_state_set(nfa_state_set) def process_nfa_state_set(nfa_state_set)
state = @states[@nfa_state_sets[nfa_state_set]]
transitions = transitions_for(nfa_state_set) transitions = transitions_for(nfa_state_set)
while transitions.size > 0 while transitions.size > 0
subrange = CodePointRange.first_subrange(transitions.map(&:code_point_range)) subrange = CodePointRange.first_subrange(transitions.map(&:code_point_range))
dest_nfa_states = transitions.reduce(Set.new) do |result, transition| dest_nfa_states = transitions.reduce(Set.new) do |result, transition|
if transition.code_point_range.include?(subrange) if transition.code_point_range.include?(subrange)
result << transition.last result << transition.destination
end end
result result
end end
unless @states.include?(dest_nfa_states) register_nfa_state_set(dest_nfa_states)
@to_process << dest_nfa_states dest_state = @states[@nfa_state_sets[dest_nfa_states]]
end state.add_transition(subrange, dest_state)
transitions.delete_if do |transition| transitions.delete_if do |transition|
transition.code_point_range.last <= subrange.last transition.code_point_range.last <= subrange.last
end end
transitions.map! do |transition| transitions.map! do |transition|
if transition.code_point_range.first <= subrange.last if transition.code_point_range.first <= subrange.last
Transition.new(CodePointRange.new(subrange.last + 1, transition.code_point_range.last), transition.destination) NFA::State::Transition.new(CodePointRange.new(subrange.last + 1, transition.code_point_range.last), transition.destination)
else else
transition transition
end end
@ -46,8 +84,8 @@ module Imbecile
end end
end end
def transitions_for(states) def transitions_for(nfa_state_set)
states.reduce([]) do |result, state| nfa_state_set.reduce([]) do |result, state|
result + state.cp_transitions result + state.cp_transitions
end end
end end

View File

@ -12,6 +12,7 @@ module Imbecile
def initialize(code_point_range, destination) def initialize(code_point_range, destination)
@code_point_range = code_point_range @code_point_range = code_point_range
@destination = destination
end end
def nil? def nil?