public DFA <RegularLanguageState> BuildLanguage()
        {
            var transitionTableBuilder = new TransitionTableBuilder <RegularLanguageState>();
            var acceptingStates        = new HashSet <RegularLanguageState>();

            var visited = new HashSet <RegularLanguageState>();
            var toVisit = new HashSet <RegularLanguageState>();

            var startState = traverser.GetFirstPos(root);

            toVisit.Add(startState);

            while (toVisit.Count > 0)
            {
                var state = toVisit.First();

                toVisit.Remove(state);
                visited.Add(state);
                if (state.ContainsTerminalPosition())
                {
                    acceptingStates.Add(state);
                }

                foreach (char group in state.GetPositionGroups())
                {
                    var newState = new RegularLanguageState();
                    foreach (ConstantExpression pos in state.GetPositions(group))
                    {
                        newState.UnionWith(traverser.GetFollowPos(pos));
                    }

                    if (!newState.IsEmpty)
                    {
                        transitionTableBuilder.Add(
                            Edge.From(state).By(group).To(newState)
                            );
                        if (!visited.Contains(newState) && !toVisit.Contains(newState))
                        {
                            toVisit.Add(newState);
                        }
                    }
                }
            }

            return(new DFA <RegularLanguageState>(startState,
                                                  visited,
                                                  acceptingStates, transitionTableBuilder.Build()));
        }
            private void DFS(Expression start)
            {
                foreach (Expression expr in start)
                {
                    DFS(expr);
                }

                if (start is TerminalExpression)
                {
                    var newState = new RegularLanguageState(true);

                    firstPos[start] = newState;
                    lastPos[start]  = newState;
                    nullable[start] = false;
                }
                else if (start is ConstantExpression)
                {
                    var newState = new RegularLanguageState();
                    newState.AddPosition((ConstantExpression)start);

                    firstPos[start] = newState;
                    lastPos[start]  = newState;
                    nullable[start] = false;
                }
                else if (start is ConcatenationExpression)
                {
                    var ce = (ConcatenationExpression)start;

                    bool leftIsNullable  = nullable[ce.Left];
                    bool rightIsNullable = nullable[ce.Right];

                    if (leftIsNullable)
                    {
                        firstPos[start] = RegularLanguageState.Union(firstPos[ce.Left], firstPos[ce.Right]);
                    }
                    else
                    {
                        firstPos[start] = firstPos[ce.Left];
                    }

                    if (rightIsNullable)
                    {
                        lastPos[start] = RegularLanguageState.Union(lastPos[ce.Left], lastPos[ce.Right]);
                    }
                    else
                    {
                        lastPos[start] = lastPos[ce.Right];
                    }

                    nullable[start] = leftIsNullable && rightIsNullable;

                    var leftLastPos   = lastPos[ce.Left];
                    var rightFirstPos = firstPos[ce.Right];

                    foreach (char group in leftLastPos.GetPositionGroups())
                    {
                        foreach (ConstantExpression position in leftLastPos.GetPositions(group))
                        {
                            GetFollowPos(position).UnionWith(rightFirstPos);
                        }
                    }
                }
                else if (start is AlternationExpression)
                {
                    var ce = (AlternationExpression)start;

                    firstPos[start] = RegularLanguageState.Union(firstPos[ce.Left], firstPos[ce.Right]);
                    lastPos[start]  = RegularLanguageState.Union(lastPos[ce.Left], lastPos[ce.Right]);

                    nullable[start] = nullable[ce.Left] || nullable[ce.Right];
                }
                else if (start is IterationExpression)
                {
                    var ce = (IterationExpression)start;

                    firstPos[start] = firstPos[ce.Inner];
                    lastPos[start]  = lastPos[ce.Inner];

                    nullable[start] = true;

                    var leftLastPos   = lastPos[ce.Inner];
                    var rightFirstPos = firstPos[ce.Inner];

                    foreach (char group in leftLastPos.GetPositionGroups())
                    {
                        foreach (ConstantExpression position in leftLastPos.GetPositions(group))
                        {
                            GetFollowPos(position).UnionWith(rightFirstPos);
                        }
                    }
                }
            }