/// <summary>
        /// Add a new node to the list, with value given by the dSt
        /// </summary>
        /// <param name="dSt"></param>
        internal void AddState(DFSA.DState dSt)
        {
            LinkedListNode <DFSA.DState> node = new LinkedListNode <DFSA.DState>(dSt);

            dSt.listNode = node;
            this.members.AddLast(node);
        }
        /// <summary>
        /// Move the node with value dSt from this partition to blk.
        /// </summary>
        /// <param name="dSt">value to be moved</param>
        /// <param name="blk">destination partition</param>
        internal void MoveMember(DFSA.DState dSt, PartitionBlock blk)
        {
            // Assert: dSt must belong to LinkedList this.members
            LinkedListNode <DFSA.DState> node = dSt.listNode;

            this.members.Remove(node);
            this.predCount--;
            blk.AddNode(node);
        }
        /// <summary>
        /// Maps old dfsa states to new states in the minimized set.
        /// </summary>
        /// <param name="dSt">The state to be mapped</param>
        /// <returns>The replacement state</returns>
        internal static DFSA.DState PMap(DFSA.DState dSt)
        {
            PartitionBlock blk = dSt.block as PartitionBlock;

            if (blk.MemberCount == 1)
            {
                return(dSt);
            }
            else
            {
                return(blk.FirstMember);
            }
        }
        /// <summary>
        /// The initial partitions are formed by the following
        /// rules:
        /// Every accept state shares a partition with all other
        /// accept states that have the same semantic action.
        /// All other states go in the partition "otherStates".
        ///
        /// Addendum, Version 0.3: start states must be kept out
        /// of the otherStates partition, otherwise prefixes can
        /// be chopped off by, for example, concluding that states
        /// {1,3} are equivalent in the following FSA.  They are,
        /// but the computation of yytext is broken if you merge!
        ///
        ///                 a     b     c     d
        /// (start state) 1---->2---->3---->4-----(5) (accept state)
        ///
        ///                  c     d
        /// (start state) 1---->7---->(5) (accept state)
        ///
        /// The inverse transition function is computed at the same
        /// time as the initial partition is performed.
        /// </summary>
        /// <param name="list">The list of all DStates</param>
        internal void PopulatePartitions(List <DFSA.DState> list)
        {
            PartitionBlock blk = null;

            dfsa.origLength = list.Count;
            for (int i = 1; i < list.Count; i++)
            {
                DFSA.DState dSt = list[i];
                if (dSt.accept != null)
                {
                    blk = FindPartition(dSt);
                }
                else if (dSt.isStart)
                {
                    blk = startStates;
                }
                else
                {
                    blk = otherStates;
                }
                blk.AddState(dSt);
                dSt.block = blk;
                // now create the inverse transition function
                for (int j = 0; j < dfsa.MaxSym; j++)
                {
                    DFSA.DState pred = dSt.GetNext(j);
                    if (pred != null)
                    {
                        pred.AddPredecessor(dSt, j);
                    }
                }
            }
            // Now add the eofState as an accept state.
            // This is *despite* the state not having an accept reference!
            blk = MkNewBlock();
            acceptStates.Add(blk);
            blk.AddState(list[0]);
            list[0].block = blk;
            // And now finally initialize the pair list.
            worklist.Push(startStates);
            worklist.Push(otherStates); // EXPERIMENTAL
            foreach (PartitionBlock lst in acceptStates)
            {
                worklist.Push(lst);
            }
        }
        /// <summary>
        /// Find an existing partition block with which dSt is compatible,
        /// or construct a new partition into which dSt can be placed.
        /// </summary>
        /// <param name="dSt"></param>
        /// <returns></returns>
        PartitionBlock FindPartition(DFSA.DState dSt)
        {
            foreach (PartitionBlock blk in acceptStates)
            {
                //  Assert every partition in acceptStates has at least one member.
                //  Assert every member has the same semantic action.
                //
                //  This would be a simple matter except for right context. Is such
                //  cases the action is an input backup, then the user action. For a
                //  pattern R1/R2 the regex R1.R2 (concatenation) is recognized
                //  and the buffer backed up to the position of the '/'.
                //  In the case of R1 of fixed length N we do "yyless(N);"
                //  In the case of R2 of fixed length N we do "yyless(yyleng-N);"
                //  If the first state in the partition has both lengths fixed
                //  we must choose one or the other backup action, and only add
                //  other states that are compatible with that choice.
                DFSA.DState first = blk.FirstMember;
                if (DFSA.SpansEqual(first.accept.aSpan, dSt.accept.aSpan))
                {
                    if (!first.HasRightContext && !dSt.HasRightContext)
                    {
                        return(blk);
                    }
                    else
                    {
                        if (first.lhCntx > 0 && first.lhCntx == dSt.lhCntx)
                        // From now on only add states with matching lhs length
                        {
                            first.rhCntx = 0; dSt.rhCntx = 0; return(blk);
                        }
                        if (first.rhCntx > 0 && first.rhCntx == dSt.rhCntx)
                        // From now on only add states with matching rhs length
                        {
                            first.lhCntx = 0; dSt.lhCntx = 0; return(blk);
                        }
                    }
                }
            }
            PartitionBlock nxt = MkNewBlock();

            acceptStates.Add(nxt);
            return(nxt);
        }