2 * Copyright 2001-2007 Adrian Thurston <thurston@cs.queensu.ca>
5 /* This file is part of Ragel.
7 * Ragel is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * Ragel is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Ragel; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 /* Simple singly linked list append routine for the fill list. The new state
27 * goes to the end of the list. */
28 void MergeData::fillListAppend( StateAp
*state
)
32 if ( stfillHead
== 0 ) {
33 /* List is empty, state becomes head and tail. */
38 /* List is not empty, state goes after last element. */
39 stfillTail
->alg
.next
= state
;
44 /* Graph constructor. */
51 /* Misfit accounting is a switch, turned on only at specific times. It
52 * controls what happens when states have no way in from the outside
54 misfitAccounting(false)
58 /* Copy all graph data including transitions. */
59 FsmAp::FsmAp( const FsmAp
&graph
)
61 /* Lists start empty. Will be filled by copy. */
65 /* Copy in the entry points,
66 * pointers will be resolved later. */
67 entryPoints(graph
.entryPoints
),
68 startState(graph
.startState
),
71 /* Will be filled by copy. */
74 /* Misfit accounting is only on during merging. */
75 misfitAccounting(false)
77 /* Create the states and record their map in the original state. */
78 StateList::Iter origState
= graph
.stateList
;
79 for ( ; origState
.lte(); origState
++ ) {
80 /* Make the new state. */
81 StateAp
*newState
= new StateAp( *origState
);
83 /* Add the state to the list. */
84 stateList
.append( newState
);
86 /* Set the mapsTo item of the old state. */
87 origState
->alg
.stateMap
= newState
;
90 /* Derefernce all the state maps. */
91 for ( StateList::Iter state
= stateList
; state
.lte(); state
++ ) {
92 for ( TransList::Iter trans
= state
->outList
; trans
.lte(); trans
++ ) {
93 /* The points to the original in the src machine. The taget's duplicate
94 * is in the statemap. */
95 StateAp
*toState
= trans
->toState
!= 0 ? trans
->toState
->alg
.stateMap
: 0;
97 /* Attach The transition to the duplicate. */
99 attachTrans( state
, toState
, trans
);
102 /* Fix the eofTarg, if set. */
103 if ( state
->eofTarget
!= 0 )
104 state
->eofTarget
= state
->eofTarget
->alg
.stateMap
;
107 /* Fix the state pointers in the entry points array. */
108 EntryMapEl
*eel
= entryPoints
.data
;
109 for ( int e
= 0; e
< entryPoints
.length(); e
++, eel
++ ) {
110 /* Get the duplicate of the state. */
111 eel
->value
= eel
->value
->alg
.stateMap
;
113 /* Foreign in transitions must be built up when duping machines so
114 * increment it here. */
115 eel
->value
->foreignInTrans
+= 1;
118 /* Fix the start state pointer and the new start state's count of in
120 startState
= startState
->alg
.stateMap
;
121 startState
->foreignInTrans
+= 1;
123 /* Build the final state set. */
124 StateSet::Iter st
= graph
.finStateSet
;
125 for ( ; st
.lte(); st
++ )
126 finStateSet
.insert((*st
)->alg
.stateMap
);
129 /* Deletes all transition data then deletes each state. */
132 /* Delete all the transitions. */
133 for ( StateList::Iter state
= stateList
; state
.lte(); state
++ ) {
134 /* Iterate the out transitions, deleting them. */
135 state
->outList
.empty();
138 /* Delete all the states. */
142 /* Set a state final. The state has its isFinState set to true and the state
143 * is added to the finStateSet. */
144 void FsmAp::setFinState( StateAp
*state
)
146 /* Is it already a fin state. */
147 if ( state
->stateBits
& STB_ISFINAL
)
150 state
->stateBits
|= STB_ISFINAL
;
151 finStateSet
.insert( state
);
154 /* Set a state non-final. The has its isFinState flag set false and the state
155 * is removed from the final state set. */
156 void FsmAp::unsetFinState( StateAp
*state
)
158 /* Is it already a non-final state? */
159 if ( ! (state
->stateBits
& STB_ISFINAL
) )
162 /* When a state looses its final state status it must relinquish all the
163 * properties that are allowed only for final states. */
164 clearOutData( state
);
166 state
->stateBits
&= ~ STB_ISFINAL
;
167 finStateSet
.remove( state
);
170 /* Set and unset a state as the start state. */
171 void FsmAp::setStartState( StateAp
*state
)
173 /* Sould change from unset to set. */
174 assert( startState
== 0 );
177 if ( misfitAccounting
) {
178 /* If the number of foreign in transitions is about to go up to 1 then
179 * take it off the misfit list and put it on the head list. */
180 if ( state
->foreignInTrans
== 0 )
181 stateList
.append( misfitList
.detach( state
) );
184 /* Up the foreign in transitions to the state. */
185 state
->foreignInTrans
+= 1;
188 void FsmAp::unsetStartState()
190 /* Should change from set to unset. */
191 assert( startState
!= 0 );
193 /* Decrement the entry's count of foreign entries. */
194 startState
->foreignInTrans
-= 1;
196 if ( misfitAccounting
) {
197 /* If the number of foreign in transitions just went down to 0 then take
198 * it off the main list and put it on the misfit list. */
199 if ( startState
->foreignInTrans
== 0 )
200 misfitList
.append( stateList
.detach( startState
) );
206 /* Associate an id with a state. Makes the state a named entry point. Has no
207 * effect if the entry point is already mapped to the state. */
208 void FsmAp::setEntry( int id
, StateAp
*state
)
210 /* Insert the id into the state. If the state is already labelled with id,
212 if ( state
->entryIds
.insert( id
) ) {
213 /* Insert the entry and assert that it succeeds. */
214 entryPoints
.insertMulti( id
, state
);
216 if ( misfitAccounting
) {
217 /* If the number of foreign in transitions is about to go up to 1 then
218 * take it off the misfit list and put it on the head list. */
219 if ( state
->foreignInTrans
== 0 )
220 stateList
.append( misfitList
.detach( state
) );
223 /* Up the foreign in transitions to the state. */
224 state
->foreignInTrans
+= 1;
228 /* Remove the association of an id with a state. The state looses it's entry
229 * point status. Assumes that the id is indeed mapped to state. */
230 void FsmAp::unsetEntry( int id
, StateAp
*state
)
232 /* Find the entry point in on id. */
233 EntryMapEl
*enLow
= 0, *enHigh
= 0;
234 entryPoints
.findMulti( id
, enLow
, enHigh
);
235 while ( enLow
->value
!= state
)
238 /* Remove the record from the map. */
239 entryPoints
.remove( enLow
);
241 /* Remove the state's sense of the link. */
242 state
->entryIds
.remove( id
);
243 state
->foreignInTrans
-= 1;
244 if ( misfitAccounting
) {
245 /* If the number of foreign in transitions just went down to 0 then take
246 * it off the main list and put it on the misfit list. */
247 if ( state
->foreignInTrans
== 0 )
248 misfitList
.append( stateList
.detach( state
) );
252 /* Remove all association of an id with states. Assumes that the id is indeed
253 * mapped to a state. */
254 void FsmAp::unsetEntry( int id
)
256 /* Find the entry point in on id. */
257 EntryMapEl
*enLow
= 0, *enHigh
= 0;
258 entryPoints
.findMulti( id
, enLow
, enHigh
);
259 for ( EntryMapEl
*mel
= enLow
; mel
<= enHigh
; mel
++ ) {
260 /* Remove the state's sense of the link. */
261 mel
->value
->entryIds
.remove( id
);
262 mel
->value
->foreignInTrans
-= 1;
263 if ( misfitAccounting
) {
264 /* If the number of foreign in transitions just went down to 0
265 * then take it off the main list and put it on the misfit list. */
266 if ( mel
->value
->foreignInTrans
== 0 )
267 misfitList
.append( stateList
.detach( mel
->value
) );
271 /* Remove the records from the entry points map. */
272 entryPoints
.removeMulti( enLow
, enHigh
);
276 void FsmAp::changeEntry( int id
, StateAp
*to
, StateAp
*from
)
278 /* Find the entry in the entry map. */
279 EntryMapEl
*enLow
= 0, *enHigh
= 0;
280 entryPoints
.findMulti( id
, enLow
, enHigh
);
281 while ( enLow
->value
!= from
)
284 /* Change it to the new target. */
287 /* Remove from's sense of the link. */
288 from
->entryIds
.remove( id
);
289 from
->foreignInTrans
-= 1;
290 if ( misfitAccounting
) {
291 /* If the number of foreign in transitions just went down to 0 then take
292 * it off the main list and put it on the misfit list. */
293 if ( from
->foreignInTrans
== 0 )
294 misfitList
.append( stateList
.detach( from
) );
297 /* Add to's sense of the link. */
298 if ( to
->entryIds
.insert( id
) != 0 ) {
299 if ( misfitAccounting
) {
300 /* If the number of foreign in transitions is about to go up to 1 then
301 * take it off the misfit list and put it on the head list. */
302 if ( to
->foreignInTrans
== 0 )
303 stateList
.append( misfitList
.detach( to
) );
306 /* Up the foreign in transitions to the state. */
307 to
->foreignInTrans
+= 1;
312 /* Clear all entry points from a machine. */
313 void FsmAp::unsetAllEntryPoints()
315 for ( EntryMap::Iter en
= entryPoints
; en
.lte(); en
++ ) {
316 /* Kill all the state's entry points at once. */
317 if ( en
->value
->entryIds
.length() > 0 ) {
318 en
->value
->foreignInTrans
-= en
->value
->entryIds
.length();
320 if ( misfitAccounting
) {
321 /* If the number of foreign in transitions just went down to 0
322 * then take it off the main list and put it on the misfit
324 if ( en
->value
->foreignInTrans
== 0 )
325 misfitList
.append( stateList
.detach( en
->value
) );
328 /* Clear the set of ids out all at once. */
329 en
->value
->entryIds
.empty();
333 /* Now clear out the entry map all at once. */
337 /* Assigning an epsilon transition into final states. */
338 void FsmAp::epsilonTrans( int id
)
340 for ( StateSet::Iter fs
= finStateSet
; fs
.lte(); fs
++ )
341 (*fs
)->epsilonTrans
.append( id
);
344 /* Mark all states reachable from state. Traverses transitions forward. Used
345 * for removing states that have no path into them. */
346 void FsmAp::markReachableFromHere( StateAp
*state
)
348 /* Base case: return; */
349 if ( state
->stateBits
& STB_ISMARKED
)
352 /* Set this state as processed. We are going to visit all states that this
353 * state has a transition to. */
354 state
->stateBits
|= STB_ISMARKED
;
356 /* Recurse on all out transitions. */
357 for ( TransList::Iter trans
= state
->outList
; trans
.lte(); trans
++ ) {
358 if ( trans
->toState
!= 0 )
359 markReachableFromHere( trans
->toState
);
363 void FsmAp::markReachableFromHereStopFinal( StateAp
*state
)
365 /* Base case: return; */
366 if ( state
->stateBits
& STB_ISMARKED
)
369 /* Set this state as processed. We are going to visit all states that this
370 * state has a transition to. */
371 state
->stateBits
|= STB_ISMARKED
;
373 /* Recurse on all out transitions. */
374 for ( TransList::Iter trans
= state
->outList
; trans
.lte(); trans
++ ) {
375 StateAp
*toState
= trans
->toState
;
376 if ( toState
!= 0 && !toState
->isFinState() )
377 markReachableFromHereStopFinal( toState
);
381 /* Mark all states reachable from state. Traverse transitions backwards. Used
382 * for removing dead end paths in graphs. */
383 void FsmAp::markReachableFromHereReverse( StateAp
*state
)
385 /* Base case: return; */
386 if ( state
->stateBits
& STB_ISMARKED
)
389 /* Set this state as processed. We are going to visit all states with
390 * transitions into this state. */
391 state
->stateBits
|= STB_ISMARKED
;
393 /* Recurse on all items in transitions. */
394 for ( TransInList::Iter trans
= state
->inList
; trans
.lte(); trans
++ )
395 markReachableFromHereReverse( trans
->fromState
);
398 /* Determine if there are any entry points into a start state other than the
399 * start state. Setting starting transitions requires that the start state be
400 * isolated. In most cases a start state will already be isolated. */
401 bool FsmAp::isStartStateIsolated()
403 /* If there are any in transitions then the state is not isolated. */
404 if ( startState
->inList
.head
!= 0 )
407 /* If there are any entry points then isolated. */
408 if ( startState
->entryIds
.length() > 0 )
414 /* Bring in other's entry points. Assumes others states are going to be
415 * copied into this machine. */
416 void FsmAp::copyInEntryPoints( FsmAp
*other
)
418 /* Use insert multi because names are not unique. */
419 for ( EntryMap::Iter en
= other
->entryPoints
; en
.lte(); en
++ )
420 entryPoints
.insertMulti( en
->key
, en
->value
);
424 void FsmAp::unsetAllFinStates()
426 for ( StateSet::Iter st
= finStateSet
; st
.lte(); st
++ )
427 (*st
)->stateBits
&= ~ STB_ISFINAL
;
431 void FsmAp::setFinBits( int finStateBits
)
433 for ( int s
= 0; s
< finStateSet
.length(); s
++ )
434 finStateSet
.data
[s
]->stateBits
|= finStateBits
;
438 /* Tests the integrity of the transition lists and the fromStates. */
439 void FsmAp::verifyIntegrity()
441 for ( StateList::Iter state
= stateList
; state
.lte(); state
++ ) {
442 /* Walk the out transitions and assert fromState is correct. */
443 for ( TransList::Iter trans
= state
->outList
; trans
.lte(); trans
++ )
444 assert( trans
->fromState
== state
);
446 /* Walk the inlist and assert toState is correct. */
447 for ( TransInList::Iter trans
= state
->inList
; trans
.lte(); trans
++ )
448 assert( trans
->toState
== state
);
452 void FsmAp::verifyReachability()
454 /* Mark all the states that can be reached
455 * through the set of entry points. */
456 markReachableFromHere( startState
);
457 for ( EntryMap::Iter en
= entryPoints
; en
.lte(); en
++ )
458 markReachableFromHere( en
->value
);
460 /* Check that everything got marked. */
461 for ( StateList::Iter st
= stateList
; st
.lte(); st
++ ) {
462 /* Assert it got marked and then clear the mark. */
463 assert( st
->stateBits
& STB_ISMARKED
);
464 st
->stateBits
&= ~ STB_ISMARKED
;
468 void FsmAp::verifyNoDeadEndStates()
470 /* Mark all states that have paths to the final states. */
471 for ( StateSet::Iter pst
= finStateSet
; pst
.lte(); pst
++ )
472 markReachableFromHereReverse( *pst
);
474 /* Start state gets honorary marking. Must be done AFTER recursive call. */
475 startState
->stateBits
|= STB_ISMARKED
;
477 /* Make sure everything got marked. */
478 for ( StateList::Iter st
= stateList
; st
.lte(); st
++ ) {
479 /* Assert the state got marked and unmark it. */
480 assert( st
->stateBits
& STB_ISMARKED
);
481 st
->stateBits
&= ~ STB_ISMARKED
;
485 void FsmAp::depthFirstOrdering( StateAp
*state
)
487 /* Nothing to do if the state is already on the list. */
488 if ( state
->stateBits
& STB_ONLIST
)
491 /* Doing depth first, put state on the list. */
492 state
->stateBits
|= STB_ONLIST
;
493 stateList
.append( state
);
495 /* Recurse on everything ranges. */
496 for ( TransList::Iter tel
= state
->outList
; tel
.lte(); tel
++ ) {
497 if ( tel
->toState
!= 0 )
498 depthFirstOrdering( tel
->toState
);
502 /* Ordering states by transition connections. */
503 void FsmAp::depthFirstOrdering()
505 /* Init on state list flags. */
506 for ( StateList::Iter st
= stateList
; st
.lte(); st
++ )
507 st
->stateBits
&= ~STB_ONLIST
;
509 /* Clear out the state list, we will rebuild it. */
510 int stateListLen
= stateList
.length();
513 /* Add back to the state list from the start state and all other entry
516 depthFirstOrdering( errState
);
517 depthFirstOrdering( startState
);
518 for ( EntryMap::Iter en
= entryPoints
; en
.lte(); en
++ )
519 depthFirstOrdering( en
->value
);
521 /* Make sure we put everything back on. */
522 assert( stateListLen
== stateList
.length() );
525 /* Stable sort the states by final state status. */
526 void FsmAp::sortStatesByFinal()
528 /* Move forward through the list and throw final states onto the end. */
530 StateAp
*next
= stateList
.head
;
531 StateAp
*last
= stateList
.tail
;
532 while ( state
!= last
) {
533 /* Move forward and load up the next. */
537 /* Throw to the end? */
538 if ( state
->isFinState() ) {
539 stateList
.detach( state
);
540 stateList
.append( state
);
545 void FsmAp::setStateNumbers( int base
)
547 for ( StateList::Iter state
= stateList
; state
.lte(); state
++ )
548 state
->alg
.stateNum
= base
++;
552 bool FsmAp::checkErrTrans( StateAp
*state
, TransAp
*trans
)
554 /* Might go directly to error state. */
555 if ( trans
->toState
== 0 )
558 if ( trans
->prev
== 0 ) {
559 /* If this is the first transition. */
560 if ( keyOps
->minKey
< trans
->lowKey
)
564 /* Not the first transition. Compare against the prev. */
565 TransAp
*prev
= trans
->prev
;
566 Key nextKey
= prev
->highKey
;
568 if ( nextKey
< trans
->lowKey
)
574 bool FsmAp::checkErrTransFinish( StateAp
*state
)
576 /* Check if there are any ranges already. */
577 if ( state
->outList
.length() == 0 )
580 /* Get the last and check for a gap on the end. */
581 TransAp
*last
= state
->outList
.tail
;
582 if ( last
->highKey
< keyOps
->maxKey
)
588 bool FsmAp::hasErrorTrans()
591 for ( StateList::Iter st
= stateList
; st
.lte(); st
++ ) {
592 for ( TransList::Iter tr
= st
->outList
; tr
.lte(); tr
++ ) {
593 result
= checkErrTrans( st
, tr
);
597 result
= checkErrTransFinish( st
);