void DumpFiniteAutomaton(FiniteAutomatonState<char> state, ISet<FiniteAutomatonState<char>> visited)
        {
            if (visited.Contains(state))
                return;
            visited.Add(state);

            Debug.WriteLine(state.GetHashCode() + ": ");
            if (state.AcceptTerminals != null)
            {
                foreach (var term in state.AcceptTerminals)
                {
                    Debug.WriteLine("  Accept " + term.Name);
                }
            }
            if (state.RejectTerminals != null)
            {
                foreach (var term in state.RejectTerminals)
                {
                    Debug.WriteLine("  Reject " + term.Name);
                }
            }
            if (state.Transitions != null)
            {
                foreach (var trans in state.Transitions)
                {
                    Debug.WriteLine("  Transition:");
                    Debug.WriteLine("    Match Expression: " + trans.Characters);
                    Debug.WriteLine("    MatchEof: " + trans.MatchEpsilon);
                    Debug.WriteLine("    MatchEpsilon: " + trans.MatchEpsilon);
                    Debug.WriteLine("    Target: " + trans.Target.GetHashCode());
                }
                foreach (var trans in state.Transitions)
                {
                    DumpFiniteAutomaton(trans.Target, visited);
                }
            }
        }