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
27 using std::ostringstream;
31 string Action::nameOrLoc()
37 ret << loc.line << ":" << loc.col;
45 forcedErrorState(false),
52 bAnyToStateActions(false),
53 bAnyFromStateActions(false),
54 bAnyRegActions(false),
55 bAnyEofActions(false),
56 bAnyActionGotos(false),
57 bAnyActionCalls(false),
58 bAnyActionRets(false),
59 bAnyRegActionRets(false),
60 bAnyRegActionByValControl(false),
61 bAnyRegNextStmt(false),
62 bAnyRegCurStateRef(false),
64 bAnyLmSwitchError(false),
69 /* Does the machine have any actions. */
70 bool RedFsmAp::anyActions()
72 return actionMap.length() > 0;
75 void RedFsmAp::depthFirstOrdering( RedStateAp *state )
77 /* Nothing to do if the state is already on the list. */
78 if ( state->onStateList )
81 /* Doing depth first, put state on the list. */
82 state->onStateList = true;
83 stateList.append( state );
85 /* At this point transitions should only be in ranges. */
86 assert( state->outSingle.length() == 0 );
87 assert( state->defTrans == 0 );
89 /* Recurse on everything ranges. */
90 for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) {
91 if ( rtel->value->targ != 0 )
92 depthFirstOrdering( rtel->value->targ );
96 /* Ordering states by transition connections. */
97 void RedFsmAp::depthFirstOrdering()
99 /* Init on state list flags. */
100 for ( RedStateList::Iter st = stateList; st.lte(); st++ )
101 st->onStateList = false;
103 /* Clear out the state list, we will rebuild it. */
104 int stateListLen = stateList.length();
107 /* Add back to the state list from the start state and all other entry
109 depthFirstOrdering( startState );
110 for ( RedStateSet::Iter en = entryPoints; en.lte(); en++ )
111 depthFirstOrdering( *en );
112 if ( forcedErrorState )
113 depthFirstOrdering( errState );
115 /* Make sure we put everything back on. */
116 assert( stateListLen == stateList.length() );
119 /* Assign state ids by appearance in the state list. */
120 void RedFsmAp::sequentialStateIds()
122 /* Table based machines depend on the state numbers starting at zero. */
124 for ( RedStateList::Iter st = stateList; st.lte(); st++ )
125 st->id = nextStateId++;
128 /* Stable sort the states by final state status. */
129 void RedFsmAp::sortStatesByFinal()
131 /* Move forward through the list and throw final states onto the end. */
132 RedStateAp *state = 0;
133 RedStateAp *next = stateList.head;
134 RedStateAp *last = stateList.tail;
135 while ( state != last ) {
136 /* Move forward and load up the next. */
140 /* Throw to the end? */
141 if ( state->isFinal ) {
142 stateList.detach( state );
143 stateList.append( state );
148 /* Assign state ids by final state state status. */
149 void RedFsmAp::sortStateIdsByFinal()
151 /* Table based machines depend on this starting at zero. */
154 /* First pass to assign non final ids. */
155 for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
157 st->id = nextStateId++;
160 /* Second pass to assign final ids. */
161 for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
163 st->id = nextStateId++;
167 /* Find the final state with the lowest id. */
168 void RedFsmAp::findFirstFinState()
170 for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
171 if ( st->isFinal && (firstFinState == 0 || st->id < firstFinState->id) )
176 void RedFsmAp::assignActionLocs()
178 int nextLocation = 0;
179 for ( ActionTableMap::Iter act = actionMap; act.lte(); act++ ) {
180 /* Store the loc, skip over the array and a null terminator. */
181 act->location = nextLocation;
182 nextLocation += act->key.length() + 1;
186 /* Check if we can extend the current range by displacing any ranges
187 * ahead to the singles. */
188 bool RedFsmAp::canExtend( const RedTransList &list, int pos )
190 /* Get the transition that we want to extend. */
191 RedTransAp *extendTrans = list[pos].value;
193 /* Look ahead in the transition list. */
194 for ( int next = pos + 1; next < list.length(); pos++, next++ ) {
195 /* If they are not continuous then cannot extend. */
196 Key nextKey = list[next].lowKey;
198 if ( list[pos].highKey != nextKey )
201 /* Check for the extenstion property. */
202 if ( extendTrans == list[next].value )
205 /* If the span of the next element is more than one, then don't keep
206 * checking, it won't be moved to single. */
207 unsigned long long nextSpan = keyOps->span( list[next].lowKey, list[next].highKey );
214 /* Move ranges to the singles list. */
215 void RedFsmAp::moveTransToSingle( RedStateAp *state )
217 RedTransList &range = state->outRange;
218 RedTransList &single = state->outSingle;
219 for ( int rpos = 0; rpos < range.length(); ) {
220 /* Check if this is a range we can extend. */
221 if ( canExtend( range, rpos ) ) {
222 /* Transfer singles over. */
223 while ( range[rpos].value != range[rpos+1].value ) {
224 /* Transfer the range to single. */
225 single.append( range[rpos+1] );
226 range.remove( rpos+1 );
230 range[rpos].highKey = range[rpos+1].highKey;
231 range.remove( rpos+1 );
233 /* Maybe move it to the singles. */
234 else if ( keyOps->span( range[rpos].lowKey, range[rpos].highKey ) == 1 ) {
235 single.append( range[rpos] );
236 range.remove( rpos );
239 /* Keeping it in the ranges. */
245 /* Look through ranges and choose suitable single character transitions. */
246 void RedFsmAp::chooseSingle()
248 /* Loop the states. */
249 for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
250 /* Rewrite the transition list taking out the suitable single
252 moveTransToSingle( st );
256 void RedFsmAp::makeFlat()
258 for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
259 if ( st->stateCondList.length() == 0 ) {
264 st->condLowKey = st->stateCondList.head->lowKey;
265 st->condHighKey = st->stateCondList.tail->highKey;
267 unsigned long long span = keyOps->span( st->condLowKey, st->condHighKey );
268 st->condList = new CondSpace*[ span ];
269 memset( st->condList, 0, sizeof(CondSpace*)*span );
271 for ( StateCondList::Iter sci = st->stateCondList; sci.lte(); sci++ ) {
272 unsigned long long base, trSpan;
273 base = keyOps->span( st->condLowKey, sci->lowKey )-1;
274 trSpan = keyOps->span( sci->lowKey, sci->highKey );
275 for ( unsigned long long pos = 0; pos < trSpan; pos++ )
276 st->condList[base+pos] = sci->condSpace;
280 if ( st->outRange.length() == 0 ) {
281 st->lowKey = st->highKey = 0;
285 st->lowKey = st->outRange[0].lowKey;
286 st->highKey = st->outRange[st->outRange.length()-1].highKey;
287 unsigned long long span = keyOps->span( st->lowKey, st->highKey );
288 st->transList = new RedTransAp*[ span ];
289 memset( st->transList, 0, sizeof(RedTransAp*)*span );
291 for ( RedTransList::Iter trans = st->outRange; trans.lte(); trans++ ) {
292 unsigned long long base, trSpan;
293 base = keyOps->span( st->lowKey, trans->lowKey )-1;
294 trSpan = keyOps->span( trans->lowKey, trans->highKey );
295 for ( unsigned long long pos = 0; pos < trSpan; pos++ )
296 st->transList[base+pos] = trans->value;
299 /* Fill in the gaps with the default transition. */
300 for ( unsigned long long pos = 0; pos < span; pos++ ) {
301 if ( st->transList[pos] == 0 )
302 st->transList[pos] = st->defTrans;
309 /* A default transition has been picked, move it from the outRange to the
310 * default pointer. */
311 void RedFsmAp::moveToDefault( RedTransAp *defTrans, RedStateAp *state )
313 /* Rewrite the outRange, omitting any ranges that use
314 * the picked default. */
315 RedTransList outRange;
316 for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) {
317 /* If it does not take the default, copy it over. */
318 if ( rtel->value != defTrans )
319 outRange.append( *rtel );
322 /* Save off the range we just created into the state's range. */
323 state->outRange.shallowCopy( outRange );
326 /* Store the default. */
327 state->defTrans = defTrans;
330 bool RedFsmAp::alphabetCovered( RedTransList &outRange )
332 /* Cannot cover without any out ranges. */
333 if ( outRange.length() == 0 )
336 /* If the first range doesn't start at the the lower bound then the
337 * alphabet is not covered. */
338 RedTransList::Iter rtel = outRange;
339 if ( keyOps->minKey < rtel->lowKey )
342 /* Check that every range is next to the previous one. */
344 for ( ; rtel.lte(); rtel++ ) {
345 Key highKey = rtel[-1].highKey;
347 if ( highKey != rtel->lowKey )
351 /* The last must extend to the upper bound. */
352 RedTransEl *last = &outRange[outRange.length()-1];
353 if ( last->highKey < keyOps->maxKey )
359 RedTransAp *RedFsmAp::chooseDefaultSpan( RedStateAp *state )
361 /* Make a set of transitions from the outRange. */
362 RedTransSet stateTransSet;
363 for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ )
364 stateTransSet.insert( rtel->value );
366 /* For each transition in the find how many alphabet characters the
367 * transition spans. */
368 unsigned long long *span = new unsigned long long[stateTransSet.length()];
369 memset( span, 0, sizeof(unsigned long long) * stateTransSet.length() );
370 for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) {
371 /* Lookup the transition in the set. */
372 RedTransAp **inSet = stateTransSet.find( rtel->value );
373 int pos = inSet - stateTransSet.data;
374 span[pos] += keyOps->span( rtel->lowKey, rtel->highKey );
377 /* Find the max span, choose it for making the default. */
378 RedTransAp *maxTrans = 0;
379 unsigned long long maxSpan = 0;
380 for ( RedTransSet::Iter rtel = stateTransSet; rtel.lte(); rtel++ ) {
381 if ( span[rtel.pos()] > maxSpan ) {
382 maxSpan = span[rtel.pos()];
391 /* Pick default transitions from ranges for the states. */
392 void RedFsmAp::chooseDefaultSpan()
394 /* Loop the states. */
395 for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
396 /* Only pick a default transition if the alphabet is covered. This
397 * avoids any transitions in the out range that go to error and avoids
398 * the need for an ERR state. */
399 if ( alphabetCovered( st->outRange ) ) {
400 /* Pick a default transition by largest span. */
401 RedTransAp *defTrans = chooseDefaultSpan( st );
403 /* Rewrite the transition list taking out the transition we picked
404 * as the default and store the default. */
405 moveToDefault( defTrans, st );
410 RedTransAp *RedFsmAp::chooseDefaultGoto( RedStateAp *state )
412 /* Make a set of transitions from the outRange. */
413 RedTransSet stateTransSet;
414 for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) {
415 if ( rtel->value->targ == state->next )
421 void RedFsmAp::chooseDefaultGoto()
423 /* Loop the states. */
424 for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
425 /* Pick a default transition. */
426 RedTransAp *defTrans = chooseDefaultGoto( st );
428 defTrans = chooseDefaultSpan( st );
430 /* Rewrite the transition list taking out the transition we picked
431 * as the default and store the default. */
432 moveToDefault( defTrans, st );
436 RedTransAp *RedFsmAp::chooseDefaultNumRanges( RedStateAp *state )
438 /* Make a set of transitions from the outRange. */
439 RedTransSet stateTransSet;
440 for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ )
441 stateTransSet.insert( rtel->value );
443 /* For each transition in the find how many ranges use the transition. */
444 int *numRanges = new int[stateTransSet.length()];
445 memset( numRanges, 0, sizeof(int) * stateTransSet.length() );
446 for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) {
447 /* Lookup the transition in the set. */
448 RedTransAp **inSet = stateTransSet.find( rtel->value );
449 numRanges[inSet - stateTransSet.data] += 1;
452 /* Find the max number of ranges. */
453 RedTransAp *maxTrans = 0;
454 int maxNumRanges = 0;
455 for ( RedTransSet::Iter rtel = stateTransSet; rtel.lte(); rtel++ ) {
456 if ( numRanges[rtel.pos()] > maxNumRanges ) {
457 maxNumRanges = numRanges[rtel.pos()];
466 void RedFsmAp::chooseDefaultNumRanges()
468 /* Loop the states. */
469 for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
470 /* Pick a default transition. */
471 RedTransAp *defTrans = chooseDefaultNumRanges( st );
473 /* Rewrite the transition list taking out the transition we picked
474 * as the default and store the default. */
475 moveToDefault( defTrans, st );
479 RedTransAp *RedFsmAp::getErrorTrans( )
481 /* If the error trans has not been made aready, make it. */
482 if ( errTrans == 0 ) {
483 /* This insert should always succeed since no transition created by
484 * the user can point to the error state. */
485 errTrans = new RedTransAp( getErrorState(), 0, nextTransId++ );
486 RedTransAp *inRes = transSet.insert( errTrans );
487 assert( inRes != 0 );
492 RedStateAp *RedFsmAp::getErrorState()
494 /* Check if we need to init the error trans. */
495 if ( errState == 0 ) {
496 errState = new RedStateAp();
497 stateList.append( errState );
503 RedTransAp *RedFsmAp::allocateTrans( RedStateAp *targ, RedAction *action )
505 /* Create a reduced trans and look for it in the transiton set. */
506 RedTransAp redTrans( targ, action, 0 );
507 RedTransAp *inDict = transSet.find( &redTrans );
509 inDict = new RedTransAp( targ, action, nextTransId++ );
510 transSet.insert( inDict );
515 void RedFsmAp::partitionFsm( int nparts )
517 /* At this point the states are ordered by a depth-first traversal. We
518 * will allocate to partitions based on this ordering. */
519 this->nParts = nparts;
520 int partSize = stateList.length() / nparts;
521 int remainder = stateList.length() % nparts;
522 int numInPart = partSize;
524 if ( remainder-- > 0 )
526 for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
527 st->partition = partition;
530 if ( numInPart == 0 ) {
532 numInPart = partSize;
533 if ( remainder-- > 0 )
539 void RedFsmAp::setInTrans()
541 /* First pass counts the number of transitions. */
542 for ( TransApSet::Iter trans = transSet; trans.lte(); trans++ )
543 trans->targ->numInTrans += 1;
545 /* Pass over states to allocate the needed memory. Reset the counts so we
546 * can use them as the current size. */
547 for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
548 st->inTrans = new RedTransAp*[st->numInTrans];
552 /* Second pass over transitions copies pointers into the in trans list. */
553 for ( TransApSet::Iter trans = transSet; trans.lte(); trans++ )
554 trans->targ->inTrans[trans->targ->numInTrans++] = trans;