let nfa_to_dfa (n : nfa) : nfa =
let visited = Hashset.create n.next_q in
let statemapping = Hashtbl.create n.next_q in
let dfa = new_nfa_states 0 0 in
let sink_state = new_state dfa in
let cur_q = ref dfa.next_q in
let convert (q : stateset) : state =
try Hashtbl.find statemapping q
with Not_found ->
let res = !cur_q in
incr cur_q;
Hashtbl.replace statemapping q res;
res
in
let _ = dfa.s <- (convert (eps_closure n n.s)) in
let bigsigma = Charset.create_full () in
let _ = add_all_trans dfa sink_state sink_state in
let process_state (q : stateset) : stateset list =
let all_outbound = ref (Charset.create_empty ()) in
let process_out x =
let some_outbound = ref (Charset.create_empty ()) in
let mapping = all_delta ~create:false n.delta x in
Hashtbl.iter (fun z y ->
some_outbound := Charset.cup !some_outbound y) mapping;
all_outbound := Charset.cup !all_outbound !some_outbound in
let _ = StateSet.iter process_out q in
let not_covered = Charset.minus bigsigma !all_outbound in
let _ = add_set_trans dfa (convert q) not_covered sink_state in
let _ = if StateSet.exists ((=) n.f) q then
add_trans dfa (convert q) Epsilon dfa.f
in
let res = ref [] in
let process_symbol s =
let rhs_states = ref (StateSet.empty) in
let process_rhs q_rhs =
rhs_states := StateSet.union !rhs_states (eps_closure n q_rhs)
in
let process_lhs q_lhs =
StateSet.iter process_rhs (rhs n q_lhs s)
in
StateSet.iter process_lhs q;
res := !rhs_states :: !res;
add_trans dfa (convert q) (Character s) (convert !rhs_states)
in
Charset.iter process_symbol !all_outbound;
!res
in
let rec walk (q : stateset list) = match q with
| x::xs when not (mem visited x) ->
add visited x;
let to_enqueue = process_state x in
walk (List.rev_append xs to_enqueue)
| x::xs -> walk xs
| _ -> ()
in
walk [(eps_closure n n.s)];
dfa