123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584 |
- /*
- * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
- */
- /* This file is part of Ragel.
- *
- * Ragel is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * Ragel is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Ragel; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
- #include "redfsm.h"
- #include "avlmap.h"
- #include "mergesort.h"
- #include <iostream>
- #include <sstream>
- using std::ostringstream;
- string GenAction::nameOrLoc()
- {
- if ( name != 0 )
- return string(name);
- else {
- ostringstream ret;
- ret << loc.line << ":" << loc.col;
- return ret.str();
- }
- }
- RedFsmAp::RedFsmAp()
- :
- forcedErrorState(false),
- nextActionId(0),
- nextTransId(0),
- startState(0),
- errState(0),
- errTrans(0),
- firstFinState(0),
- numFinStates(0),
- bAnyToStateActions(false),
- bAnyFromStateActions(false),
- bAnyRegActions(false),
- bAnyEofActions(false),
- bAnyEofTrans(false),
- bAnyActionGotos(false),
- bAnyActionCalls(false),
- bAnyActionRets(false),
- bAnyActionByValControl(false),
- bAnyRegActionRets(false),
- bAnyRegActionByValControl(false),
- bAnyRegNextStmt(false),
- bAnyRegCurStateRef(false),
- bAnyRegBreak(false),
- bAnyConditions(false)
- {
- }
- /* Does the machine have any actions. */
- bool RedFsmAp::anyActions()
- {
- return actionMap.length() > 0;
- }
- void RedFsmAp::depthFirstOrdering( RedStateAp *state )
- {
- /* Nothing to do if the state is already on the list. */
- if ( state->onStateList )
- return;
- /* Doing depth first, put state on the list. */
- state->onStateList = true;
- stateList.append( state );
-
- /* At this point transitions should only be in ranges. */
- assert( state->outSingle.length() == 0 );
- assert( state->defTrans == 0 );
- /* Recurse on everything ranges. */
- for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) {
- if ( rtel->value->targ != 0 )
- depthFirstOrdering( rtel->value->targ );
- }
- }
- /* Ordering states by transition connections. */
- void RedFsmAp::depthFirstOrdering()
- {
- /* Init on state list flags. */
- for ( RedStateList::Iter st = stateList; st.lte(); st++ )
- st->onStateList = false;
-
- /* Clear out the state list, we will rebuild it. */
- int stateListLen = stateList.length();
- stateList.abandon();
- /* Add back to the state list from the start state and all other entry
- * points. */
- if ( startState != 0 )
- depthFirstOrdering( startState );
- for ( RedStateSet::Iter en = entryPoints; en.lte(); en++ )
- depthFirstOrdering( *en );
- if ( forcedErrorState )
- depthFirstOrdering( errState );
-
- /* Make sure we put everything back on. */
- assert( stateListLen == stateList.length() );
- }
- /* Assign state ids by appearance in the state list. */
- void RedFsmAp::sequentialStateIds()
- {
- /* Table based machines depend on the state numbers starting at zero. */
- nextStateId = 0;
- for ( RedStateList::Iter st = stateList; st.lte(); st++ )
- st->id = nextStateId++;
- }
- /* Stable sort the states by final state status. */
- void RedFsmAp::sortStatesByFinal()
- {
- /* Move forward through the list and throw final states onto the end. */
- RedStateAp *state = 0;
- RedStateAp *next = stateList.head;
- RedStateAp *last = stateList.tail;
- while ( state != last ) {
- /* Move forward and load up the next. */
- state = next;
- next = state->next;
- /* Throw to the end? */
- if ( state->isFinal ) {
- stateList.detach( state );
- stateList.append( state );
- }
- }
- }
- /* Assign state ids by final state state status. */
- void RedFsmAp::sortStateIdsByFinal()
- {
- /* Table based machines depend on this starting at zero. */
- nextStateId = 0;
- /* First pass to assign non final ids. */
- for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
- if ( ! st->isFinal )
- st->id = nextStateId++;
- }
- /* Second pass to assign final ids. */
- for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
- if ( st->isFinal )
- st->id = nextStateId++;
- }
- }
- struct CmpStateById
- {
- static int compare( RedStateAp *st1, RedStateAp *st2 )
- {
- if ( st1->id < st2->id )
- return -1;
- else if ( st1->id > st2->id )
- return 1;
- else
- return 0;
- }
- };
- void RedFsmAp::sortByStateId()
- {
- /* Make the array. */
- int pos = 0;
- RedStateAp **ptrList = new RedStateAp*[stateList.length()];
- for ( RedStateList::Iter st = stateList; st.lte(); st++, pos++ )
- ptrList[pos] = st;
-
- MergeSort<RedStateAp*, CmpStateById> mergeSort;
- mergeSort.sort( ptrList, stateList.length() );
- stateList.abandon();
- for ( int st = 0; st < pos; st++ )
- stateList.append( ptrList[st] );
- delete[] ptrList;
- }
- /* Find the final state with the lowest id. */
- void RedFsmAp::findFirstFinState()
- {
- for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
- if ( st->isFinal && (firstFinState == 0 || st->id < firstFinState->id) )
- firstFinState = st;
- }
- }
- void RedFsmAp::assignActionLocs()
- {
- int nextLocation = 0;
- for ( GenActionTableMap::Iter act = actionMap; act.lte(); act++ ) {
- /* Store the loc, skip over the array and a null terminator. */
- act->location = nextLocation;
- nextLocation += act->key.length() + 1;
- }
- }
- /* Check if we can extend the current range by displacing any ranges
- * ahead to the singles. */
- bool RedFsmAp::canExtend( const RedTransList &list, int pos )
- {
- /* Get the transition that we want to extend. */
- RedTransAp *extendTrans = list[pos].value;
- /* Look ahead in the transition list. */
- for ( int next = pos + 1; next < list.length(); pos++, next++ ) {
- /* If they are not continuous then cannot extend. */
- Key nextKey = list[next].lowKey;
- nextKey.decrement();
- if ( list[pos].highKey != nextKey )
- break;
- /* Check for the extenstion property. */
- if ( extendTrans == list[next].value )
- return true;
- /* If the span of the next element is more than one, then don't keep
- * checking, it won't be moved to single. */
- unsigned long long nextSpan = keyOps->span( list[next].lowKey, list[next].highKey );
- if ( nextSpan > 1 )
- break;
- }
- return false;
- }
- /* Move ranges to the singles list. */
- void RedFsmAp::moveTransToSingle( RedStateAp *state )
- {
- RedTransList &range = state->outRange;
- RedTransList &single = state->outSingle;
- for ( int rpos = 0; rpos < range.length(); ) {
- /* Check if this is a range we can extend. */
- if ( canExtend( range, rpos ) ) {
- /* Transfer singles over. */
- while ( range[rpos].value != range[rpos+1].value ) {
- /* Transfer the range to single. */
- single.append( range[rpos+1] );
- range.remove( rpos+1 );
- }
-
- /* Extend. */
- range[rpos].highKey = range[rpos+1].highKey;
- range.remove( rpos+1 );
- }
- /* Maybe move it to the singles. */
- else if ( keyOps->span( range[rpos].lowKey, range[rpos].highKey ) == 1 ) {
- single.append( range[rpos] );
- range.remove( rpos );
- }
- else {
- /* Keeping it in the ranges. */
- rpos += 1;
- }
- }
- }
- /* Look through ranges and choose suitable single character transitions. */
- void RedFsmAp::chooseSingle()
- {
- /* Loop the states. */
- for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
- /* Rewrite the transition list taking out the suitable single
- * transtions. */
- moveTransToSingle( st );
- }
- }
- void RedFsmAp::makeFlat()
- {
- for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
- if ( st->stateCondList.length() == 0 ) {
- st->condLowKey = 0;
- st->condHighKey = 0;
- }
- else {
- st->condLowKey = st->stateCondList.head->lowKey;
- st->condHighKey = st->stateCondList.tail->highKey;
- unsigned long long span = keyOps->span( st->condLowKey, st->condHighKey );
- st->condList = new GenCondSpace*[ span ];
- memset( st->condList, 0, sizeof(GenCondSpace*)*span );
- for ( GenStateCondList::Iter sci = st->stateCondList; sci.lte(); sci++ ) {
- unsigned long long base, trSpan;
- base = keyOps->span( st->condLowKey, sci->lowKey )-1;
- trSpan = keyOps->span( sci->lowKey, sci->highKey );
- for ( unsigned long long pos = 0; pos < trSpan; pos++ )
- st->condList[base+pos] = sci->condSpace;
- }
- }
- if ( st->outRange.length() == 0 ) {
- st->lowKey = st->highKey = 0;
- st->transList = 0;
- }
- else {
- st->lowKey = st->outRange[0].lowKey;
- st->highKey = st->outRange[st->outRange.length()-1].highKey;
- unsigned long long span = keyOps->span( st->lowKey, st->highKey );
- st->transList = new RedTransAp*[ span ];
- memset( st->transList, 0, sizeof(RedTransAp*)*span );
-
- for ( RedTransList::Iter trans = st->outRange; trans.lte(); trans++ ) {
- unsigned long long base, trSpan;
- base = keyOps->span( st->lowKey, trans->lowKey )-1;
- trSpan = keyOps->span( trans->lowKey, trans->highKey );
- for ( unsigned long long pos = 0; pos < trSpan; pos++ )
- st->transList[base+pos] = trans->value;
- }
- /* Fill in the gaps with the default transition. */
- for ( unsigned long long pos = 0; pos < span; pos++ ) {
- if ( st->transList[pos] == 0 )
- st->transList[pos] = st->defTrans;
- }
- }
- }
- }
- /* A default transition has been picked, move it from the outRange to the
- * default pointer. */
- void RedFsmAp::moveToDefault( RedTransAp *defTrans, RedStateAp *state )
- {
- /* Rewrite the outRange, omitting any ranges that use
- * the picked default. */
- RedTransList outRange;
- for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) {
- /* If it does not take the default, copy it over. */
- if ( rtel->value != defTrans )
- outRange.append( *rtel );
- }
- /* Save off the range we just created into the state's range. */
- state->outRange.transfer( outRange );
- /* Store the default. */
- state->defTrans = defTrans;
- }
- bool RedFsmAp::alphabetCovered( RedTransList &outRange )
- {
- /* Cannot cover without any out ranges. */
- if ( outRange.length() == 0 )
- return false;
- /* If the first range doesn't start at the the lower bound then the
- * alphabet is not covered. */
- RedTransList::Iter rtel = outRange;
- if ( keyOps->minKey < rtel->lowKey )
- return false;
- /* Check that every range is next to the previous one. */
- rtel.increment();
- for ( ; rtel.lte(); rtel++ ) {
- Key highKey = rtel[-1].highKey;
- highKey.increment();
- if ( highKey != rtel->lowKey )
- return false;
- }
- /* The last must extend to the upper bound. */
- RedTransEl *last = &outRange[outRange.length()-1];
- if ( last->highKey < keyOps->maxKey )
- return false;
- return true;
- }
- RedTransAp *RedFsmAp::chooseDefaultSpan( RedStateAp *state )
- {
- /* Make a set of transitions from the outRange. */
- RedTransSet stateTransSet;
- for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ )
- stateTransSet.insert( rtel->value );
-
- /* For each transition in the find how many alphabet characters the
- * transition spans. */
- unsigned long long *span = new unsigned long long[stateTransSet.length()];
- memset( span, 0, sizeof(unsigned long long) * stateTransSet.length() );
- for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) {
- /* Lookup the transition in the set. */
- RedTransAp **inSet = stateTransSet.find( rtel->value );
- int pos = inSet - stateTransSet.data;
- span[pos] += keyOps->span( rtel->lowKey, rtel->highKey );
- }
- /* Find the max span, choose it for making the default. */
- RedTransAp *maxTrans = 0;
- unsigned long long maxSpan = 0;
- for ( RedTransSet::Iter rtel = stateTransSet; rtel.lte(); rtel++ ) {
- if ( span[rtel.pos()] > maxSpan ) {
- maxSpan = span[rtel.pos()];
- maxTrans = *rtel;
- }
- }
- delete[] span;
- return maxTrans;
- }
- /* Pick default transitions from ranges for the states. */
- void RedFsmAp::chooseDefaultSpan()
- {
- /* Loop the states. */
- for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
- /* Only pick a default transition if the alphabet is covered. This
- * avoids any transitions in the out range that go to error and avoids
- * the need for an ERR state. */
- if ( alphabetCovered( st->outRange ) ) {
- /* Pick a default transition by largest span. */
- RedTransAp *defTrans = chooseDefaultSpan( st );
- /* Rewrite the transition list taking out the transition we picked
- * as the default and store the default. */
- moveToDefault( defTrans, st );
- }
- }
- }
- RedTransAp *RedFsmAp::chooseDefaultGoto( RedStateAp *state )
- {
- /* Make a set of transitions from the outRange. */
- RedTransSet stateTransSet;
- for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) {
- if ( rtel->value->targ == state->next )
- return rtel->value;
- }
- return 0;
- }
- void RedFsmAp::chooseDefaultGoto()
- {
- /* Loop the states. */
- for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
- /* Pick a default transition. */
- RedTransAp *defTrans = chooseDefaultGoto( st );
- if ( defTrans == 0 )
- defTrans = chooseDefaultSpan( st );
- /* Rewrite the transition list taking out the transition we picked
- * as the default and store the default. */
- moveToDefault( defTrans, st );
- }
- }
- RedTransAp *RedFsmAp::chooseDefaultNumRanges( RedStateAp *state )
- {
- /* Make a set of transitions from the outRange. */
- RedTransSet stateTransSet;
- for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ )
- stateTransSet.insert( rtel->value );
-
- /* For each transition in the find how many ranges use the transition. */
- int *numRanges = new int[stateTransSet.length()];
- memset( numRanges, 0, sizeof(int) * stateTransSet.length() );
- for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) {
- /* Lookup the transition in the set. */
- RedTransAp **inSet = stateTransSet.find( rtel->value );
- numRanges[inSet - stateTransSet.data] += 1;
- }
- /* Find the max number of ranges. */
- RedTransAp *maxTrans = 0;
- int maxNumRanges = 0;
- for ( RedTransSet::Iter rtel = stateTransSet; rtel.lte(); rtel++ ) {
- if ( numRanges[rtel.pos()] > maxNumRanges ) {
- maxNumRanges = numRanges[rtel.pos()];
- maxTrans = *rtel;
- }
- }
- delete[] numRanges;
- return maxTrans;
- }
- void RedFsmAp::chooseDefaultNumRanges()
- {
- /* Loop the states. */
- for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
- /* Pick a default transition. */
- RedTransAp *defTrans = chooseDefaultNumRanges( st );
- /* Rewrite the transition list taking out the transition we picked
- * as the default and store the default. */
- moveToDefault( defTrans, st );
- }
- }
- RedTransAp *RedFsmAp::getErrorTrans( )
- {
- /* If the error trans has not been made aready, make it. */
- if ( errTrans == 0 ) {
- /* This insert should always succeed since no transition created by
- * the user can point to the error state. */
- errTrans = new RedTransAp( getErrorState(), 0, nextTransId++ );
- RedTransAp *inRes = transSet.insert( errTrans );
- assert( inRes != 0 );
- }
- return errTrans;
- }
- RedStateAp *RedFsmAp::getErrorState()
- {
- /* Something went wrong. An error state is needed but one was not supplied
- * by the frontend. */
- assert( errState != 0 );
- return errState;
- }
- RedTransAp *RedFsmAp::allocateTrans( RedStateAp *targ, RedAction *action )
- {
- /* Create a reduced trans and look for it in the transiton set. */
- RedTransAp redTrans( targ, action, 0 );
- RedTransAp *inDict = transSet.find( &redTrans );
- if ( inDict == 0 ) {
- inDict = new RedTransAp( targ, action, nextTransId++ );
- transSet.insert( inDict );
- }
- return inDict;
- }
- void RedFsmAp::partitionFsm( int nparts )
- {
- /* At this point the states are ordered by a depth-first traversal. We
- * will allocate to partitions based on this ordering. */
- this->nParts = nparts;
- int partSize = stateList.length() / nparts;
- int remainder = stateList.length() % nparts;
- int numInPart = partSize;
- int partition = 0;
- if ( remainder-- > 0 )
- numInPart += 1;
- for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
- st->partition = partition;
- numInPart -= 1;
- if ( numInPart == 0 ) {
- partition += 1;
- numInPart = partSize;
- if ( remainder-- > 0 )
- numInPart += 1;
- }
- }
- }
- void RedFsmAp::setInTrans()
- {
- /* First pass counts the number of transitions. */
- for ( TransApSet::Iter trans = transSet; trans.lte(); trans++ )
- trans->targ->numInTrans += 1;
- /* Pass over states to allocate the needed memory. Reset the counts so we
- * can use them as the current size. */
- for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
- st->inTrans = new RedTransAp*[st->numInTrans];
- st->numInTrans = 0;
- }
- /* Second pass over transitions copies pointers into the in trans list. */
- for ( TransApSet::Iter trans = transSet; trans.lte(); trans++ )
- trans->targ->inTrans[trans->targ->numInTrans++] = trans;
- }
|