Convert an NFA to a DFA(s)

    Each DFA is initially a set of NFA states without labels.  We start with the
    DFA for the start NFA.  Then we add labeled arcs to it pointing to another
    set of NFAs (the next state).  Finally, we do the same thing to every DFA
    that is found and return the list of states.

def nfa_to_dfa(start, end):
    """Convert an NFA to a DFA(s)

    Each DFA is initially a set of NFA states without labels.  We start with the
    DFA for the start NFA.  Then we add labeled arcs to it pointing to another
    set of NFAs (the next state).  Finally, we do the same thing to every DFA
    that is found and return the list of states.
    """
    base_nfas = set()
    start.find_unlabeled_states(base_nfas)
    state_stack = [DFA(base_nfas, end)]
    for state in state_stack:
        arcs = {}
        for nfa in state.nfas:
            for label, sub_nfa in nfa.arcs:
                if label is not None:
                    sub_nfa.find_unlabeled_states(arcs.setdefault(label, set()))
        for label, nfa_set in arcs.items():
            for st in state_stack:
                if st.nfas == nfa_set:
                    break
            else:
                st = DFA(nfa_set, end)
                state_stack.append(st)
            state.arc(st, label)
    return state_stack