Use portable types in the C/C++ code generator
[ragel-jkt.git] / ragel / redfsm.cpp
blob9a58752bed265fb2e27a98938c0cec7748db1aba
1 /*
2 * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
3 */
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
22 #include "redfsm.h"
23 #include "avlmap.h"
24 #include "mergesort.h"
25 #include <iostream>
26 #include <sstream>
28 using std::ostringstream;
30 string GenAction::nameOrLoc()
32 if ( name != 0 )
33 return string(name);
34 else {
35 ostringstream ret;
36 ret << loc.line << ":" << loc.col;
37 return ret.str();
41 RedFsmAp::RedFsmAp()
43 forcedErrorState(false),
44 nextActionId(0),
45 nextTransId(0),
46 startState(0),
47 errState(0),
48 errTrans(0),
49 firstFinState(0),
50 numFinStates(0),
51 bAnyToStateActions(false),
52 bAnyFromStateActions(false),
53 bAnyRegActions(false),
54 bAnyEofActions(false),
55 bAnyEofTrans(false),
56 bAnyActionGotos(false),
57 bAnyActionCalls(false),
58 bAnyActionRets(false),
59 bAnyRegActionRets(false),
60 bAnyRegActionByValControl(false),
61 bAnyRegNextStmt(false),
62 bAnyRegCurStateRef(false),
63 bAnyRegBreak(false),
64 bAnyConditions(false)
68 /* Does the machine have any actions. */
69 bool RedFsmAp::anyActions()
71 return actionMap.length() > 0;
74 void RedFsmAp::depthFirstOrdering( RedStateAp *state )
76 /* Nothing to do if the state is already on the list. */
77 if ( state->onStateList )
78 return;
80 /* Doing depth first, put state on the list. */
81 state->onStateList = true;
82 stateList.append( state );
84 /* At this point transitions should only be in ranges. */
85 assert( state->outSingle.length() == 0 );
86 assert( state->defTrans == 0 );
88 /* Recurse on everything ranges. */
89 for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) {
90 if ( rtel->value->targ != 0 )
91 depthFirstOrdering( rtel->value->targ );
95 /* Ordering states by transition connections. */
96 void RedFsmAp::depthFirstOrdering()
98 /* Init on state list flags. */
99 for ( RedStateList::Iter st = stateList; st.lte(); st++ )
100 st->onStateList = false;
102 /* Clear out the state list, we will rebuild it. */
103 int stateListLen = stateList.length();
104 stateList.abandon();
106 /* Add back to the state list from the start state and all other entry
107 * points. */
108 if ( startState != 0 )
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. */
123 nextStateId = 0;
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. */
137 state = next;
138 next = state->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. */
152 nextStateId = 0;
154 /* First pass to assign non final ids. */
155 for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
156 if ( ! st->isFinal )
157 st->id = nextStateId++;
160 /* Second pass to assign final ids. */
161 for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
162 if ( st->isFinal )
163 st->id = nextStateId++;
167 struct CmpStateById
169 static int compare( RedStateAp *st1, RedStateAp *st2 )
171 if ( st1->id < st2->id )
172 return -1;
173 else if ( st1->id > st2->id )
174 return 1;
175 else
176 return 0;
180 void RedFsmAp::sortByStateId()
182 /* Make the array. */
183 int pos = 0;
184 RedStateAp **ptrList = new RedStateAp*[stateList.length()];
185 for ( RedStateList::Iter st = stateList; st.lte(); st++, pos++ )
186 ptrList[pos] = st;
188 MergeSort<RedStateAp*, CmpStateById> mergeSort;
189 mergeSort.sort( ptrList, stateList.length() );
191 stateList.abandon();
192 for ( int st = 0; st < pos; st++ )
193 stateList.append( ptrList[st] );
195 delete[] ptrList;
198 /* Find the final state with the lowest id. */
199 void RedFsmAp::findFirstFinState()
201 for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
202 if ( st->isFinal && (firstFinState == 0 || st->id < firstFinState->id) )
203 firstFinState = st;
207 void RedFsmAp::assignActionLocs()
209 int nextLocation = 0;
210 for ( GenActionTableMap::Iter act = actionMap; act.lte(); act++ ) {
211 /* Store the loc, skip over the array and a null terminator. */
212 act->location = nextLocation;
213 nextLocation += act->key.length() + 1;
217 /* Check if we can extend the current range by displacing any ranges
218 * ahead to the singles. */
219 bool RedFsmAp::canExtend( const RedTransList &list, int pos )
221 /* Get the transition that we want to extend. */
222 RedTransAp *extendTrans = list[pos].value;
224 /* Look ahead in the transition list. */
225 for ( int next = pos + 1; next < list.length(); pos++, next++ ) {
226 /* If they are not continuous then cannot extend. */
227 Key nextKey = list[next].lowKey;
228 nextKey.decrement();
229 if ( list[pos].highKey != nextKey )
230 break;
232 /* Check for the extenstion property. */
233 if ( extendTrans == list[next].value )
234 return true;
236 /* If the span of the next element is more than one, then don't keep
237 * checking, it won't be moved to single. */
238 unsigned long long nextSpan = keyOps->span( list[next].lowKey, list[next].highKey );
239 if ( nextSpan > 1 )
240 break;
242 return false;
245 /* Move ranges to the singles list. */
246 void RedFsmAp::moveTransToSingle( RedStateAp *state )
248 RedTransList &range = state->outRange;
249 RedTransList &single = state->outSingle;
250 for ( int rpos = 0; rpos < range.length(); ) {
251 /* Check if this is a range we can extend. */
252 if ( canExtend( range, rpos ) ) {
253 /* Transfer singles over. */
254 while ( range[rpos].value != range[rpos+1].value ) {
255 /* Transfer the range to single. */
256 single.append( range[rpos+1] );
257 range.remove( rpos+1 );
260 /* Extend. */
261 range[rpos].highKey = range[rpos+1].highKey;
262 range.remove( rpos+1 );
264 /* Maybe move it to the singles. */
265 else if ( keyOps->span( range[rpos].lowKey, range[rpos].highKey ) == 1 ) {
266 single.append( range[rpos] );
267 range.remove( rpos );
269 else {
270 /* Keeping it in the ranges. */
271 rpos += 1;
276 /* Look through ranges and choose suitable single character transitions. */
277 void RedFsmAp::chooseSingle()
279 /* Loop the states. */
280 for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
281 /* Rewrite the transition list taking out the suitable single
282 * transtions. */
283 moveTransToSingle( st );
287 void RedFsmAp::makeFlat()
289 for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
290 if ( st->stateCondList.length() == 0 ) {
291 st->condLowKey = 0;
292 st->condHighKey = 0;
294 else {
295 st->condLowKey = st->stateCondList.head->lowKey;
296 st->condHighKey = st->stateCondList.tail->highKey;
298 unsigned long long span = keyOps->span( st->condLowKey, st->condHighKey );
299 st->condList = new GenCondSpace*[ span ];
300 memset( st->condList, 0, sizeof(GenCondSpace*)*span );
302 for ( GenStateCondList::Iter sci = st->stateCondList; sci.lte(); sci++ ) {
303 unsigned long long base, trSpan;
304 base = keyOps->span( st->condLowKey, sci->lowKey )-1;
305 trSpan = keyOps->span( sci->lowKey, sci->highKey );
306 for ( unsigned long long pos = 0; pos < trSpan; pos++ )
307 st->condList[base+pos] = sci->condSpace;
311 if ( st->outRange.length() == 0 ) {
312 st->lowKey = st->highKey = 0;
313 st->transList = 0;
315 else {
316 st->lowKey = st->outRange[0].lowKey;
317 st->highKey = st->outRange[st->outRange.length()-1].highKey;
318 unsigned long long span = keyOps->span( st->lowKey, st->highKey );
319 st->transList = new RedTransAp*[ span ];
320 memset( st->transList, 0, sizeof(RedTransAp*)*span );
322 for ( RedTransList::Iter trans = st->outRange; trans.lte(); trans++ ) {
323 unsigned long long base, trSpan;
324 base = keyOps->span( st->lowKey, trans->lowKey )-1;
325 trSpan = keyOps->span( trans->lowKey, trans->highKey );
326 for ( unsigned long long pos = 0; pos < trSpan; pos++ )
327 st->transList[base+pos] = trans->value;
330 /* Fill in the gaps with the default transition. */
331 for ( unsigned long long pos = 0; pos < span; pos++ ) {
332 if ( st->transList[pos] == 0 )
333 st->transList[pos] = st->defTrans;
340 /* A default transition has been picked, move it from the outRange to the
341 * default pointer. */
342 void RedFsmAp::moveToDefault( RedTransAp *defTrans, RedStateAp *state )
344 /* Rewrite the outRange, omitting any ranges that use
345 * the picked default. */
346 RedTransList outRange;
347 for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) {
348 /* If it does not take the default, copy it over. */
349 if ( rtel->value != defTrans )
350 outRange.append( *rtel );
353 /* Save off the range we just created into the state's range. */
354 state->outRange.transfer( outRange );
356 /* Store the default. */
357 state->defTrans = defTrans;
360 bool RedFsmAp::alphabetCovered( RedTransList &outRange )
362 /* Cannot cover without any out ranges. */
363 if ( outRange.length() == 0 )
364 return false;
366 /* If the first range doesn't start at the the lower bound then the
367 * alphabet is not covered. */
368 RedTransList::Iter rtel = outRange;
369 if ( keyOps->minKey < rtel->lowKey )
370 return false;
372 /* Check that every range is next to the previous one. */
373 rtel.increment();
374 for ( ; rtel.lte(); rtel++ ) {
375 Key highKey = rtel[-1].highKey;
376 highKey.increment();
377 if ( highKey != rtel->lowKey )
378 return false;
381 /* The last must extend to the upper bound. */
382 RedTransEl *last = &outRange[outRange.length()-1];
383 if ( last->highKey < keyOps->maxKey )
384 return false;
386 return true;
389 RedTransAp *RedFsmAp::chooseDefaultSpan( RedStateAp *state )
391 /* Make a set of transitions from the outRange. */
392 RedTransSet stateTransSet;
393 for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ )
394 stateTransSet.insert( rtel->value );
396 /* For each transition in the find how many alphabet characters the
397 * transition spans. */
398 unsigned long long *span = new unsigned long long[stateTransSet.length()];
399 memset( span, 0, sizeof(unsigned long long) * stateTransSet.length() );
400 for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) {
401 /* Lookup the transition in the set. */
402 RedTransAp **inSet = stateTransSet.find( rtel->value );
403 int pos = inSet - stateTransSet.data;
404 span[pos] += keyOps->span( rtel->lowKey, rtel->highKey );
407 /* Find the max span, choose it for making the default. */
408 RedTransAp *maxTrans = 0;
409 unsigned long long maxSpan = 0;
410 for ( RedTransSet::Iter rtel = stateTransSet; rtel.lte(); rtel++ ) {
411 if ( span[rtel.pos()] > maxSpan ) {
412 maxSpan = span[rtel.pos()];
413 maxTrans = *rtel;
417 delete[] span;
418 return maxTrans;
421 /* Pick default transitions from ranges for the states. */
422 void RedFsmAp::chooseDefaultSpan()
424 /* Loop the states. */
425 for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
426 /* Only pick a default transition if the alphabet is covered. This
427 * avoids any transitions in the out range that go to error and avoids
428 * the need for an ERR state. */
429 if ( alphabetCovered( st->outRange ) ) {
430 /* Pick a default transition by largest span. */
431 RedTransAp *defTrans = chooseDefaultSpan( st );
433 /* Rewrite the transition list taking out the transition we picked
434 * as the default and store the default. */
435 moveToDefault( defTrans, st );
440 RedTransAp *RedFsmAp::chooseDefaultGoto( RedStateAp *state )
442 /* Make a set of transitions from the outRange. */
443 RedTransSet stateTransSet;
444 for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) {
445 if ( rtel->value->targ == state->next )
446 return rtel->value;
448 return 0;
451 void RedFsmAp::chooseDefaultGoto()
453 /* Loop the states. */
454 for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
455 /* Pick a default transition. */
456 RedTransAp *defTrans = chooseDefaultGoto( st );
457 if ( defTrans == 0 )
458 defTrans = chooseDefaultSpan( st );
460 /* Rewrite the transition list taking out the transition we picked
461 * as the default and store the default. */
462 moveToDefault( defTrans, st );
466 RedTransAp *RedFsmAp::chooseDefaultNumRanges( RedStateAp *state )
468 /* Make a set of transitions from the outRange. */
469 RedTransSet stateTransSet;
470 for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ )
471 stateTransSet.insert( rtel->value );
473 /* For each transition in the find how many ranges use the transition. */
474 int *numRanges = new int[stateTransSet.length()];
475 memset( numRanges, 0, sizeof(int) * stateTransSet.length() );
476 for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) {
477 /* Lookup the transition in the set. */
478 RedTransAp **inSet = stateTransSet.find( rtel->value );
479 numRanges[inSet - stateTransSet.data] += 1;
482 /* Find the max number of ranges. */
483 RedTransAp *maxTrans = 0;
484 int maxNumRanges = 0;
485 for ( RedTransSet::Iter rtel = stateTransSet; rtel.lte(); rtel++ ) {
486 if ( numRanges[rtel.pos()] > maxNumRanges ) {
487 maxNumRanges = numRanges[rtel.pos()];
488 maxTrans = *rtel;
492 delete[] numRanges;
493 return maxTrans;
496 void RedFsmAp::chooseDefaultNumRanges()
498 /* Loop the states. */
499 for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
500 /* Pick a default transition. */
501 RedTransAp *defTrans = chooseDefaultNumRanges( st );
503 /* Rewrite the transition list taking out the transition we picked
504 * as the default and store the default. */
505 moveToDefault( defTrans, st );
509 RedTransAp *RedFsmAp::getErrorTrans( )
511 /* If the error trans has not been made aready, make it. */
512 if ( errTrans == 0 ) {
513 /* This insert should always succeed since no transition created by
514 * the user can point to the error state. */
515 errTrans = new RedTransAp( getErrorState(), 0, nextTransId++ );
516 RedTransAp *inRes = transSet.insert( errTrans );
517 assert( inRes != 0 );
519 return errTrans;
522 RedStateAp *RedFsmAp::getErrorState()
524 /* Something went wrong. An error state is needed but one was not supplied
525 * by the frontend. */
526 assert( errState != 0 );
527 return errState;
531 RedTransAp *RedFsmAp::allocateTrans( RedStateAp *targ, RedAction *action )
533 /* Create a reduced trans and look for it in the transiton set. */
534 RedTransAp redTrans( targ, action, 0 );
535 RedTransAp *inDict = transSet.find( &redTrans );
536 if ( inDict == 0 ) {
537 inDict = new RedTransAp( targ, action, nextTransId++ );
538 transSet.insert( inDict );
540 return inDict;
543 void RedFsmAp::partitionFsm( int nparts )
545 /* At this point the states are ordered by a depth-first traversal. We
546 * will allocate to partitions based on this ordering. */
547 this->nParts = nparts;
548 int partSize = stateList.length() / nparts;
549 int remainder = stateList.length() % nparts;
550 int numInPart = partSize;
551 int partition = 0;
552 if ( remainder-- > 0 )
553 numInPart += 1;
554 for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
555 st->partition = partition;
557 numInPart -= 1;
558 if ( numInPart == 0 ) {
559 partition += 1;
560 numInPart = partSize;
561 if ( remainder-- > 0 )
562 numInPart += 1;
567 void RedFsmAp::setInTrans()
569 /* First pass counts the number of transitions. */
570 for ( TransApSet::Iter trans = transSet; trans.lte(); trans++ )
571 trans->targ->numInTrans += 1;
573 /* Pass over states to allocate the needed memory. Reset the counts so we
574 * can use them as the current size. */
575 for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
576 st->inTrans = new RedTransAp*[st->numInTrans];
577 st->numInTrans = 0;
580 /* Second pass over transitions copies pointers into the in trans list. */
581 for ( TransApSet::Iter trans = transSet; trans.lte(); trans++ )
582 trans->targ->inTrans[trans->targ->numInTrans++] = trans;