/// <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); }