2 * Copyright 2001-2006 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
24 #include "mergesort.h"
28 using std::ostringstream
;
30 /* KeyOps *keyOps = 0; */
32 string
GenAction::nameOrLoc()
38 ret
<< loc
.line
<< ":" << loc
.col
;
45 forcedErrorState(false),
53 bAnyToStateActions(false),
54 bAnyFromStateActions(false),
55 bAnyRegActions(false),
56 bAnyEofActions(false),
58 bAnyActionGotos(false),
59 bAnyActionCalls(false),
60 bAnyActionRets(false),
61 bAnyRegActionRets(false),
62 bAnyRegActionByValControl(false),
63 bAnyRegNextStmt(false),
64 bAnyRegCurStateRef(false),
70 /* Does the machine have any actions. */
71 bool RedFsmAp::anyActions()
73 return actionMap
.length() > 0;
76 void RedFsmAp::depthFirstOrdering( RedStateAp
*state
)
78 /* Nothing to do if the state is already on the list. */
79 if ( state
->onStateList
)
82 /* Doing depth first, put state on the list. */
83 state
->onStateList
= true;
84 stateList
.append( state
);
86 /* At this point transitions should only be in ranges. */
87 assert( state
->outSingle
.length() == 0 );
88 assert( state
->defTrans
== 0 );
90 /* Recurse on everything ranges. */
91 for ( RedTransList::Iter rtel
= state
->outRange
; rtel
.lte(); rtel
++ ) {
92 if ( rtel
->value
->targ
!= 0 )
93 depthFirstOrdering( rtel
->value
->targ
);
97 /* Ordering states by transition connections. */
98 void RedFsmAp::depthFirstOrdering()
100 /* Init on state list flags. */
101 for ( RedStateList::Iter st
= stateList
; st
.lte(); st
++ )
102 st
->onStateList
= false;
104 /* Clear out the state list, we will rebuild it. */
105 int stateListLen
= stateList
.length();
108 /* Add back to the state list from the start state and all other entry
110 if ( startState
!= 0 )
111 depthFirstOrdering( startState
);
112 for ( RedStateSet::Iter en
= entryPoints
; en
.lte(); en
++ )
113 depthFirstOrdering( *en
);
114 if ( forcedErrorState
)
115 depthFirstOrdering( errState
);
117 /* Make sure we put everything back on. */
118 assert( stateListLen
== stateList
.length() );
121 /* Assign state ids by appearance in the state list. */
122 void RedFsmAp::sequentialStateIds()
124 /* Table based machines depend on the state numbers starting at zero. */
126 for ( RedStateList::Iter st
= stateList
; st
.lte(); st
++ )
127 st
->id
= nextStateId
++;
130 /* Stable sort the states by final state status. */
131 void RedFsmAp::sortStatesByFinal()
133 /* Move forward through the list and throw final states onto the end. */
134 RedStateAp
*state
= 0;
135 RedStateAp
*next
= stateList
.head
;
136 RedStateAp
*last
= stateList
.tail
;
137 while ( state
!= last
) {
138 /* Move forward and load up the next. */
142 /* Throw to the end? */
143 if ( state
->isFinal
) {
144 stateList
.detach( state
);
145 stateList
.append( state
);
150 /* Assign state ids by final state state status. */
151 void RedFsmAp::sortStateIdsByFinal()
153 /* Table based machines depend on this starting at zero. */
156 /* First pass to assign non final ids. */
157 for ( RedStateList::Iter st
= stateList
; st
.lte(); st
++ ) {
159 st
->id
= nextStateId
++;
162 /* Second pass to assign final ids. */
163 for ( RedStateList::Iter st
= stateList
; st
.lte(); st
++ ) {
165 st
->id
= nextStateId
++;
171 static int compare( RedStateAp
*st1
, RedStateAp
*st2
)
173 if ( st1
->id
< st2
->id
)
175 else if ( st1
->id
> st2
->id
)
182 void RedFsmAp::sortByStateId()
184 /* Make the array. */
186 RedStateAp
**ptrList
= new RedStateAp
*[stateList
.length()];
187 for ( RedStateList::Iter st
= stateList
; st
.lte(); st
++, pos
++ )
190 MergeSort
<RedStateAp
*, CmpStateById
> mergeSort
;
191 mergeSort
.sort( ptrList
, stateList
.length() );
194 for ( int st
= 0; st
< pos
; st
++ )
195 stateList
.append( ptrList
[st
] );
200 /* Find the final state with the lowest id. */
201 void RedFsmAp::findFirstFinState()
203 for ( RedStateList::Iter st
= stateList
; st
.lte(); st
++ ) {
204 if ( st
->isFinal
&& (firstFinState
== 0 || st
->id
< firstFinState
->id
) )
209 void RedFsmAp::assignActionLocs()
211 int nextLocation
= 0;
212 for ( ActionTableMap::Iter act
= actionMap
; act
.lte(); act
++ ) {
213 /* Store the loc, skip over the array and a null terminator. */
214 act
->location
= nextLocation
;
215 nextLocation
+= act
->key
.length() + 1;
219 /* Check if we can extend the current range by displacing any ranges
220 * ahead to the singles. */
221 bool RedFsmAp::canExtend( const RedTransList
&list
, int pos
)
223 /* Get the transition that we want to extend. */
224 RedTransAp
*extendTrans
= list
[pos
].value
;
226 /* Look ahead in the transition list. */
227 for ( int next
= pos
+ 1; next
< list
.length(); pos
++, next
++ ) {
228 /* If they are not continuous then cannot extend. */
229 Key nextKey
= list
[next
].lowKey
;
231 if ( list
[pos
].highKey
!= nextKey
)
234 /* Check for the extenstion property. */
235 if ( extendTrans
== list
[next
].value
)
238 /* If the span of the next element is more than one, then don't keep
239 * checking, it won't be moved to single. */
240 unsigned long long nextSpan
= keyOps
->span( list
[next
].lowKey
, list
[next
].highKey
);
247 /* Move ranges to the singles list. */
248 void RedFsmAp::moveTransToSingle( RedStateAp
*state
)
250 RedTransList
&range
= state
->outRange
;
251 RedTransList
&single
= state
->outSingle
;
252 for ( int rpos
= 0; rpos
< range
.length(); ) {
253 /* Check if this is a range we can extend. */
254 if ( canExtend( range
, rpos
) ) {
255 /* Transfer singles over. */
256 while ( range
[rpos
].value
!= range
[rpos
+1].value
) {
257 /* Transfer the range to single. */
258 single
.append( range
[rpos
+1] );
259 range
.remove( rpos
+1 );
263 range
[rpos
].highKey
= range
[rpos
+1].highKey
;
264 range
.remove( rpos
+1 );
266 /* Maybe move it to the singles. */
267 else if ( keyOps
->span( range
[rpos
].lowKey
, range
[rpos
].highKey
) == 1 ) {
268 single
.append( range
[rpos
] );
269 range
.remove( rpos
);
272 /* Keeping it in the ranges. */
278 /* Look through ranges and choose suitable single character transitions. */
279 void RedFsmAp::chooseSingle()
281 /* Loop the states. */
282 for ( RedStateList::Iter st
= stateList
; st
.lte(); st
++ ) {
283 /* Rewrite the transition list taking out the suitable single
285 moveTransToSingle( st
);
289 void RedFsmAp::makeFlat()
291 for ( RedStateList::Iter st
= stateList
; st
.lte(); st
++ ) {
292 if ( st
->stateCondList
.length() == 0 ) {
297 st
->condLowKey
= st
->stateCondList
.head
->lowKey
;
298 st
->condHighKey
= st
->stateCondList
.tail
->highKey
;
300 unsigned long long span
= keyOps
->span( st
->condLowKey
, st
->condHighKey
);
301 st
->condList
= new GenCondSpace
*[ span
];
302 memset( st
->condList
, 0, sizeof(GenCondSpace
*)*span
);
304 for ( GenStateCondList::Iter sci
= st
->stateCondList
; sci
.lte(); sci
++ ) {
305 unsigned long long base
, trSpan
;
306 base
= keyOps
->span( st
->condLowKey
, sci
->lowKey
)-1;
307 trSpan
= keyOps
->span( sci
->lowKey
, sci
->highKey
);
308 for ( unsigned long long pos
= 0; pos
< trSpan
; pos
++ )
309 st
->condList
[base
+pos
] = sci
->condSpace
;
313 if ( st
->outRange
.length() == 0 ) {
314 st
->lowKey
= st
->highKey
= 0;
318 st
->lowKey
= st
->outRange
[0].lowKey
;
319 st
->highKey
= st
->outRange
[st
->outRange
.length()-1].highKey
;
320 unsigned long long span
= keyOps
->span( st
->lowKey
, st
->highKey
);
321 st
->transList
= new RedTransAp
*[ span
];
322 memset( st
->transList
, 0, sizeof(RedTransAp
*)*span
);
324 for ( RedTransList::Iter trans
= st
->outRange
; trans
.lte(); trans
++ ) {
325 unsigned long long base
, trSpan
;
326 base
= keyOps
->span( st
->lowKey
, trans
->lowKey
)-1;
327 trSpan
= keyOps
->span( trans
->lowKey
, trans
->highKey
);
328 for ( unsigned long long pos
= 0; pos
< trSpan
; pos
++ )
329 st
->transList
[base
+pos
] = trans
->value
;
332 /* Fill in the gaps with the default transition. */
333 for ( unsigned long long pos
= 0; pos
< span
; pos
++ ) {
334 if ( st
->transList
[pos
] == 0 )
335 st
->transList
[pos
] = st
->defTrans
;
342 /* A default transition has been picked, move it from the outRange to the
343 * default pointer. */
344 void RedFsmAp::moveToDefault( RedTransAp
*defTrans
, RedStateAp
*state
)
346 /* Rewrite the outRange, omitting any ranges that use
347 * the picked default. */
348 RedTransList outRange
;
349 for ( RedTransList::Iter rtel
= state
->outRange
; rtel
.lte(); rtel
++ ) {
350 /* If it does not take the default, copy it over. */
351 if ( rtel
->value
!= defTrans
)
352 outRange
.append( *rtel
);
355 /* Save off the range we just created into the state's range. */
356 state
->outRange
.transfer( outRange
);
358 /* Store the default. */
359 state
->defTrans
= defTrans
;
362 bool RedFsmAp::alphabetCovered( RedTransList
&outRange
)
364 /* Cannot cover without any out ranges. */
365 if ( outRange
.length() == 0 )
368 /* If the first range doesn't start at the the lower bound then the
369 * alphabet is not covered. */
370 RedTransList::Iter rtel
= outRange
;
371 if ( keyOps
->minKey
< rtel
->lowKey
)
374 /* Check that every range is next to the previous one. */
376 for ( ; rtel
.lte(); rtel
++ ) {
377 Key highKey
= rtel
[-1].highKey
;
379 if ( highKey
!= rtel
->lowKey
)
383 /* The last must extend to the upper bound. */
384 RedTransEl
*last
= &outRange
[outRange
.length()-1];
385 if ( last
->highKey
< keyOps
->maxKey
)
391 RedTransAp
*RedFsmAp::chooseDefaultSpan( RedStateAp
*state
)
393 /* Make a set of transitions from the outRange. */
394 RedTransSet stateTransSet
;
395 for ( RedTransList::Iter rtel
= state
->outRange
; rtel
.lte(); rtel
++ )
396 stateTransSet
.insert( rtel
->value
);
398 /* For each transition in the find how many alphabet characters the
399 * transition spans. */
400 unsigned long long *span
= new unsigned long long[stateTransSet
.length()];
401 memset( span
, 0, sizeof(unsigned long long) * stateTransSet
.length() );
402 for ( RedTransList::Iter rtel
= state
->outRange
; rtel
.lte(); rtel
++ ) {
403 /* Lookup the transition in the set. */
404 RedTransAp
**inSet
= stateTransSet
.find( rtel
->value
);
405 int pos
= inSet
- stateTransSet
.data
;
406 span
[pos
] += keyOps
->span( rtel
->lowKey
, rtel
->highKey
);
409 /* Find the max span, choose it for making the default. */
410 RedTransAp
*maxTrans
= 0;
411 unsigned long long maxSpan
= 0;
412 for ( RedTransSet::Iter rtel
= stateTransSet
; rtel
.lte(); rtel
++ ) {
413 if ( span
[rtel
.pos()] > maxSpan
) {
414 maxSpan
= span
[rtel
.pos()];
423 /* Pick default transitions from ranges for the states. */
424 void RedFsmAp::chooseDefaultSpan()
426 /* Loop the states. */
427 for ( RedStateList::Iter st
= stateList
; st
.lte(); st
++ ) {
428 /* Only pick a default transition if the alphabet is covered. This
429 * avoids any transitions in the out range that go to error and avoids
430 * the need for an ERR state. */
431 if ( alphabetCovered( st
->outRange
) ) {
432 /* Pick a default transition by largest span. */
433 RedTransAp
*defTrans
= chooseDefaultSpan( st
);
435 /* Rewrite the transition list taking out the transition we picked
436 * as the default and store the default. */
437 moveToDefault( defTrans
, st
);
442 RedTransAp
*RedFsmAp::chooseDefaultGoto( RedStateAp
*state
)
444 /* Make a set of transitions from the outRange. */
445 RedTransSet stateTransSet
;
446 for ( RedTransList::Iter rtel
= state
->outRange
; rtel
.lte(); rtel
++ ) {
447 if ( rtel
->value
->targ
== state
->next
)
453 void RedFsmAp::chooseDefaultGoto()
455 /* Loop the states. */
456 for ( RedStateList::Iter st
= stateList
; st
.lte(); st
++ ) {
457 /* Pick a default transition. */
458 RedTransAp
*defTrans
= chooseDefaultGoto( st
);
460 defTrans
= chooseDefaultSpan( st
);
462 /* Rewrite the transition list taking out the transition we picked
463 * as the default and store the default. */
464 moveToDefault( defTrans
, st
);
468 RedTransAp
*RedFsmAp::chooseDefaultNumRanges( RedStateAp
*state
)
470 /* Make a set of transitions from the outRange. */
471 RedTransSet stateTransSet
;
472 for ( RedTransList::Iter rtel
= state
->outRange
; rtel
.lte(); rtel
++ )
473 stateTransSet
.insert( rtel
->value
);
475 /* For each transition in the find how many ranges use the transition. */
476 int *numRanges
= new int[stateTransSet
.length()];
477 memset( numRanges
, 0, sizeof(int) * stateTransSet
.length() );
478 for ( RedTransList::Iter rtel
= state
->outRange
; rtel
.lte(); rtel
++ ) {
479 /* Lookup the transition in the set. */
480 RedTransAp
**inSet
= stateTransSet
.find( rtel
->value
);
481 numRanges
[inSet
- stateTransSet
.data
] += 1;
484 /* Find the max number of ranges. */
485 RedTransAp
*maxTrans
= 0;
486 int maxNumRanges
= 0;
487 for ( RedTransSet::Iter rtel
= stateTransSet
; rtel
.lte(); rtel
++ ) {
488 if ( numRanges
[rtel
.pos()] > maxNumRanges
) {
489 maxNumRanges
= numRanges
[rtel
.pos()];
498 void RedFsmAp::chooseDefaultNumRanges()
500 /* Loop the states. */
501 for ( RedStateList::Iter st
= stateList
; st
.lte(); st
++ ) {
502 /* Pick a default transition. */
503 RedTransAp
*defTrans
= chooseDefaultNumRanges( st
);
505 /* Rewrite the transition list taking out the transition we picked
506 * as the default and store the default. */
507 moveToDefault( defTrans
, st
);
511 RedTransAp
*RedFsmAp::getErrorTrans( )
513 /* If the error trans has not been made aready, make it. */
514 if ( errTrans
== 0 ) {
515 /* This insert should always succeed since no transition created by
516 * the user can point to the error state. */
517 errTrans
= new RedTransAp( getErrorState(), 0, nextTransId
++ );
518 RedTransAp
*inRes
= transSet
.insert( errTrans
);
519 assert( inRes
!= 0 );
524 RedStateAp
*RedFsmAp::getErrorState()
526 /* Something went wrong. An error state is needed but one was not supplied
527 * by the frontend. */
528 assert( errState
!= 0 );
533 RedTransAp
*RedFsmAp::allocateTrans( RedStateAp
*targ
, RedAction
*action
)
535 /* Create a reduced trans and look for it in the transiton set. */
536 RedTransAp
redTrans( targ
, action
, 0 );
537 RedTransAp
*inDict
= transSet
.find( &redTrans
);
539 inDict
= new RedTransAp( targ
, action
, nextTransId
++ );
540 transSet
.insert( inDict
);
545 void RedFsmAp::partitionFsm( int nparts
)
547 /* At this point the states are ordered by a depth-first traversal. We
548 * will allocate to partitions based on this ordering. */
549 this->nParts
= nparts
;
550 int partSize
= stateList
.length() / nparts
;
551 int remainder
= stateList
.length() % nparts
;
552 int numInPart
= partSize
;
554 if ( remainder
-- > 0 )
556 for ( RedStateList::Iter st
= stateList
; st
.lte(); st
++ ) {
557 st
->partition
= partition
;
560 if ( numInPart
== 0 ) {
562 numInPart
= partSize
;
563 if ( remainder
-- > 0 )
569 void RedFsmAp::setInTrans()
571 /* First pass counts the number of transitions. */
572 for ( TransApSet::Iter trans
= transSet
; trans
.lte(); trans
++ )
573 trans
->targ
->numInTrans
+= 1;
575 /* Pass over states to allocate the needed memory. Reset the counts so we
576 * can use them as the current size. */
577 for ( RedStateList::Iter st
= stateList
; st
.lte(); st
++ ) {
578 st
->inTrans
= new RedTransAp
*[st
->numInTrans
];
582 /* Second pass over transitions copies pointers into the in trans list. */
583 for ( TransApSet::Iter trans
= transSet
; trans
.lte(); trans
++ )
584 trans
->targ
->inTrans
[trans
->targ
->numInTrans
++] = trans
;