diff options
Diffstat (limited to 'src/redfsm.cc')
-rw-r--r-- | src/redfsm.cc | 1192 |
1 files changed, 0 insertions, 1192 deletions
diff --git a/src/redfsm.cc b/src/redfsm.cc deleted file mode 100644 index 1b83e5b5..00000000 --- a/src/redfsm.cc +++ /dev/null @@ -1,1192 +0,0 @@ -/* - * Copyright 2001-2018 Adrian Thurston <thurston@colm.net> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include "redfsm.h" -#include "avlmap.h" -#include "mergesort.h" -#include "fsmgraph.h" -#include <iostream> -#include <sstream> -#include <ctime> - -using std::ostringstream; - -GenInlineItem::~GenInlineItem() -{ - if ( children != 0 ) { - children->empty(); - delete children; - } -} - -string GenAction::nameOrLoc() -{ - if ( name.empty() ) { - ostringstream ret; - ret << loc.line << ":" << loc.col; - return ret.str(); - } - else { - return name; - } -} - -RedFsmAp::RedFsmAp( FsmCtx *fsmCtx, int machineId ) -: - keyOps(fsmCtx->keyOps), - fsmCtx(fsmCtx), - machineId(machineId), - forcedErrorState(false), - nextActionId(0), - nextTransId(0), - nextCondId(0), - startState(0), - errState(0), - errTrans(0), - errCond(0), - firstFinState(0), - numFinStates(0), - bAnyToStateActions(false), - bAnyFromStateActions(false), - bAnyRegActions(false), - bAnyEofActions(false), - bAnyEofTrans(false), - bAnyEofActivity(false), - bAnyActionGotos(false), - bAnyActionCalls(false), - bAnyActionNcalls(false), - bAnyActionRets(false), - bAnyActionNrets(false), - bAnyActionByValControl(false), - bAnyRegActionRets(false), - bAnyRegActionByValControl(false), - bAnyRegNextStmt(false), - bAnyRegCurStateRef(false), - bAnyRegBreak(false), - bAnyRegNbreak(false), - bUsingAct(false), - bAnyNfaStates(false), - bAnyNfaPushPops(false), - bAnyNfaPushes(false), - bAnyNfaPops(false), - bAnyTransCondRefs(false), - bAnyNfaCondRefs(false), - nextClass(0), - classMap(0) -{ -} - -RedFsmAp::~RedFsmAp() -{ - for ( RedStateList::Iter st = stateList; st.lte(); st++ ) { - delete[] st->transList; - if ( st->nfaTargs != 0 ) - delete st->nfaTargs; - if ( st->inConds != 0 ) - delete[] st->inConds; - if ( st->inCondTests != 0 ) - delete[] st->inCondTests; - } - - delete[] allStates; - if ( classMap != 0 ) - delete[] classMap; - - for ( TransApSet::Iter ti = transSet; ti.lte(); ti++ ) { - if ( ti->condSpace != 0 ) - delete[] ti->v.outConds; - } - - condSet.empty(); - transSet.empty(); -} - -/* 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++ ) { - for ( int c = 0; c < rtel->value->numConds(); c++ ) { - RedCondPair *cond = rtel->value->outCond( c ); - if ( cond->targ != 0 ) - depthFirstOrdering( cond->targ ); - } - } - - if ( state->nfaTargs ) { - for ( RedNfaTargs::Iter s = *state->nfaTargs; s.lte(); s++ ) - depthFirstOrdering( s->state ); - } -} - -/* 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() ); -} - -void RedFsmAp::breadthFirstAdd( RedStateAp *state ) -{ - if ( state->onStateList ) - return; - - state->onStateList = true; - stateList.append( state ); -} - -void RedFsmAp::breadthFirstOrdering() -{ - /* 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(); - - if ( startState != 0 ) - breadthFirstAdd( startState ); - - int depth = 0; - int nextLevel = stateList.length(); - int pos = 0; - - /* To implement breadth-first we traverse the current list (assuming a - * start state) and add children. */ - RedStateAp *cur = stateList.head; - while ( cur != 0 ) { - /* Recurse on everything ranges. */ - for ( RedTransList::Iter rtel = cur->outRange; rtel.lte(); rtel++ ) { - for ( int c = 0; c < rtel->value->numConds(); c++ ) { - RedCondPair *cond = rtel->value->outCond( c ); - if ( cond->targ != 0 ) - breadthFirstAdd( cond->targ ); - } - } - - if ( cur->nfaTargs ) { - for ( RedNfaTargs::Iter s = *cur->nfaTargs; s.lte(); s++ ) - breadthFirstAdd( s->state ); - } - - cur = cur->next; - pos += 1; - - if ( pos == nextLevel ) { - depth += 1; - nextLevel = stateList.length(); - } - } - - for ( RedStateSet::Iter en = entryPoints; en.lte(); en++ ) - depthFirstOrdering( *en ); - if ( forcedErrorState ) - depthFirstOrdering( errState ); - - assert( stateListLen == stateList.length() ); -} - -#ifdef SCORE_ORDERING -void RedFsmAp::readScores() -{ - /* - * Reads processed transitions logged by ASM codegen when LOG_TRANS is - * enabled. Process with: - * - * cat trans-log | sort -n -k 1 -k 2 -k 3 | uniq -c | sort -r -n -k1 -r > scores - */ - FILE *sfn = fopen( "scores", "r" ); - - scores = new long*[nextStateId]; - for ( int i = 0; i < nextStateId; i++ ) { - scores[i] = new long[256]; - memset( scores[i], 0, sizeof(long) * 256 ); - } - - long score, m, state, ch; - while ( true ) { - int n = fscanf( sfn, "%ld %ld %ld %ld\n", &score, &m, &state, &ch ); - if ( n != 4 ) - break; - if ( m == machineId ) - scores[state][ch] = score; - } - fclose( sfn ); - - /* Init on state list flags. */ - for ( RedStateList::Iter st = stateList; st.lte(); st++ ) { - RedTransList::Iter rtel = st->outRange; - int chi = 0; - while ( rtel.lte() ) { - /* 1. Bring chi up to lower end of out range. */ - while ( chi < rtel->lowKey.getVal() ) { - chi++; - } - - /* 2. While inside lower, add in score. */ - while ( chi <= rtel->highKey.getVal() ) { - rtel->score += scores[st->id][chi]; - chi++; - } - - /* 3. Next range. */ - rtel++; - } - } -} - -/* This second pass will collect any states that didn't make it in the first - * pass. Used for depth-first and breadth-first passes. */ -void RedFsmAp::scoreSecondPass( RedStateAp *state ) -{ - /* Nothing to do if the state is already on the list. */ - if ( state->onListRest ) - return; - - /* Doing depth first, put state on the list. */ - state->onListRest = true; - - if ( !state->onStateList ) { - 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++ ) { - for ( int c = 0; c < rtel->value->numConds(); c++ ) { - RedCondPair *cond = rtel->value->outCond( c ); - if ( cond->targ != 0 ) - scoreSecondPass( cond->targ ); - } - } - - if ( state->nfaTargs ) { - for ( RedNfaTargs::Iter s = *state->nfaTargs; s.lte(); s++ ) - scoreSecondPass( s->state ); - } -} - -void RedFsmAp::scoreOrderingDepth( 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->score > 10 ) { - for ( int c = 0; c < rtel->value->numConds(); c++ ) { - RedCondPair *cond = rtel->value->outCond( c ); - if ( cond->targ != 0 ) - scoreOrderingDepth( cond->targ ); - } - } - } -} - -void RedFsmAp::scoreOrderingDepth() -{ - readScores(); - - /* Init on state list flags. */ - for ( RedStateList::Iter st = stateList; st.lte(); st++ ) { - st->onStateList = false; - st->onListRest = false; - } - - /* Clear out the state list, we will rebuild it. */ - int stateListLen = stateList.length(); - stateList.abandon(); - - scoreOrderingDepth( startState ); - - scoreSecondPass( startState ); - for ( RedStateSet::Iter en = entryPoints; en.lte(); en++ ) - scoreSecondPass( *en ); - if ( forcedErrorState ) - scoreSecondPass( errState ); - - assert( stateListLen == stateList.length() ); -} - -void RedFsmAp::scoreOrderingBreadth() -{ - readScores(); - - /* Init on state list flags. */ - for ( RedStateList::Iter st = stateList; st.lte(); st++ ) { - st->onStateList = false; - st->onListRest = false; - } - - /* Clear out the state list, we will rebuild it. */ - int stateListLen = stateList.length(); - stateList.abandon(); - - if ( startState != 0 ) - breadthFirstAdd( startState ); - - int depth = 0; - int nextLevel = stateList.length(); - int pos = 0; - - /* To implement breadth-first we traverse the current list (assuming a - * start state) and add children. */ - RedStateAp *cur = stateList.head; - while ( cur != 0 ) { - /* Recurse on everything ranges. */ - for ( RedTransList::Iter rtel = cur->outRange; rtel.lte(); rtel++ ) { - if ( rtel->score > 100 ) { - for ( int c = 0; c < rtel->value->numConds(); c++ ) { - RedCondPair *cond = rtel->value->outCond( c ); - if ( cond->targ != 0 ) - breadthFirstAdd( cond->targ ); - } - } - } - - cur = cur->next; - pos += 1; - - if ( pos == nextLevel ) { - depth += 1; - nextLevel = stateList.length(); - } - } - - scoreSecondPass( startState ); - for ( RedStateSet::Iter en = entryPoints; en.lte(); en++ ) - scoreSecondPass( *en ); - if ( forcedErrorState ) - scoreSecondPass( errState ); - - assert( stateListLen == stateList.length() ); -} -#endif - -void RedFsmAp::randomizedOrdering() -{ - 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(); - - srand( time( 0 ) ); - - for ( int i = nextStateId; i > 0; i-- ) { - /* Pick one from 0 ... i (how many are left). */ - int nth = rand() % i; - - /* Go forward through the list adding the nth. Need to scan because - * there are items already added in the list. */ - for ( int j = 0; j < nextStateId; j++ ) { - if ( !allStates[j].onStateList ) { - if ( nth == 0 ) { - /* Add. */ - allStates[j].onStateList = true; - stateList.append( &allStates[j] ); - break; - } - else { - nth -= 1; - } - } - } - } - 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 move 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; - keyOps->decrement( nextKey ); - if ( keyOps->ne( 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 if it means we can extend some ranges, or if - * the spans are of length one. */ -void RedFsmAp::moveSelectTransToSingle( 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; - } - } -} - -void RedFsmAp::moveAllTransToSingle( RedStateAp *state ) -{ - RedTransList &range = state->outRange; - RedTransList &single = state->outSingle; - for ( int rpos = 0; rpos < range.length(); rpos++ ) { - - RedTransEl el = range[rpos]; - unsigned long long span = keyOps->span( el.lowKey, el.highKey ); - - Key key = el.lowKey; - for ( unsigned long long pos = 0; pos < span; pos++ ) { - el.lowKey = el.highKey = key; - single.append( el ); - keyOps->increment( key ); - } - } - range.empty(); -} - -/* Look through ranges and choose suitable single character transitions. */ -void RedFsmAp::moveSelectTransToSingle() -{ - /* Loop the states. */ - for ( RedStateList::Iter st = stateList; st.lte(); st++ ) { - /* Rewrite the transition list taking out the suitable single - * transtions. */ - moveSelectTransToSingle( st ); - } -} - -void RedFsmAp::moveAllTransToSingle() -{ - /* Loop the states. */ - for ( RedStateList::Iter st = stateList; st.lte(); st++ ) { - /* Rewrite the transition list taking out the suitable single - * transtions. */ - moveAllTransToSingle( st ); - } -} - -void RedFsmAp::makeFlat() -{ - for ( RedStateList::Iter st = stateList; st.lte(); st++ ) { - 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; - } - } - } -} - -void RedFsmAp::characterClass( EquivList &equiv ) -{ - /* Find the global low and high keys. */ - bool anyTrans = false; - Key lowKey = keyOps->maxKey; - Key highKey = keyOps->minKey; - for ( RedStateList::Iter st = stateList; st.lte(); st++ ) { - if ( st->outRange.length() == 0 ) - continue; - - st->lowKey = st->outRange[0].lowKey; - st->highKey = st->outRange[st->outRange.length()-1].highKey; - - if ( keyOps->lt( st->lowKey, lowKey ) ) - lowKey = st->lowKey; - - if ( keyOps->gt( st->highKey, highKey ) ) - highKey = st->highKey; - - anyTrans = true; - } - - if ( ! anyTrans ) { - this->lowKey = lowKey; - this->highKey = highKey; - this->classMap = 0; - this->nextClass = 1; - return; - } - - long long next = 1; - equiv.append( new EquivClass( lowKey, highKey, next++ ) ); - - /* Start with a single equivalence class and break it up using range - * boundaries of each state. This will tell us what the equivalence class - * ranges are. These are the ranges that always go to the same state, - * across all states. */ - for ( RedStateList::Iter st = stateList; st.lte(); st++ ) { - if ( st->outRange.length() == 0 ) - continue; - - EquivList newList; - PairKeyMap uniqPairs; - - /* What is the set of unique transitions (*for this state) */ - EquivAlloc uniqTrans; - for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) { - if ( ! uniqTrans.find( rtel->value ) ) - uniqTrans.insert( rtel->value, next++ ); - } - - /* Merge with whole-machine equiv classes. */ - typedef RangePairIter< PiList<EquivClass>, PiVector<RedTransEl> > RangePairIterPiListEquivClassPiVectorRedTransEl; - for ( RangePairIterPiListEquivClassPiVectorRedTransEl - pair( fsmCtx, equiv, st->outRange ); !pair.end(); pair++ ) - { - switch ( pair.userState ) { - - case RangePairIterPiListEquivClassPiVectorRedTransEl::RangeOverlap: { - /* Look up the char for s2. */ - EquivAllocEl *s2El = uniqTrans.find( pair.s2Tel.trans->value ); - - /* Can't use either equiv classes, find uniques. */ - PairKey pairKey( pair.s1Tel.trans->value, s2El->value ); - PairKeyMapEl *pairEl = uniqPairs.find( pairKey ); - if ( ! pairEl ) - pairEl = uniqPairs.insert( pairKey, next++ ); - - EquivClass *equivClass = new EquivClass( - pair.s1Tel.lowKey, pair.s1Tel.highKey, - pairEl->value ); - newList.append( equivClass ); - break; - } - - case RangePairIterPiListEquivClassPiVectorRedTransEl::RangeInS1: { - EquivClass *equivClass = new EquivClass( - pair.s1Tel.lowKey, pair.s1Tel.highKey, - pair.s1Tel.trans->value ); - newList.append( equivClass ); - break; - } - - case RangePairIterPiListEquivClassPiVectorRedTransEl::RangeInS2: { - /* Look up the char for s2. */ - EquivAllocEl *s2El = uniqTrans.find( pair.s2Tel.trans->value ); - - EquivClass *equivClass = new EquivClass( - pair.s2Tel.lowKey, pair.s2Tel.highKey, - s2El->value ); - newList.append( equivClass ); - break; - } - - case RangePairIterPiListEquivClassPiVectorRedTransEl::BreakS1: - case RangePairIterPiListEquivClassPiVectorRedTransEl::BreakS2: - break; - } - } - - equiv.empty(); - equiv.transfer( newList ); - } - - /* Reduce to sequential. */ - next = 0; - BstMap<long long, long long> map; - for ( EquivClass *c = equiv.head; c != 0; c = c->next ) { - BstMapEl<long long, long long> *el = map.find( c->value ); - if ( ! el ) - el = map.insert( c->value, next++ ); - c->value = el->value; - } - - /* Build the map and emit arrays from the range-based equiv classes. Will - * likely crash if there are no transitions in the FSM. */ - long long maxSpan = keyOps->span( lowKey, highKey ); - long long *dest = new long long[maxSpan]; - memset( dest, 0, sizeof(long long) * maxSpan ); - - for ( EquivClass *c = equiv.head; c != 0; c = c->next ) { - long long base = keyOps->span( lowKey, c->lowKey ) - 1; - long long span = keyOps->span( c->lowKey, c->highKey ); - for ( long long s = 0; s < span; s++ ) - dest[base + s] = c->value; - } - - this->lowKey = lowKey; - this->highKey = highKey; - this->classMap = dest; - this->nextClass = next; - -} - -void RedFsmAp::makeFlatClass() -{ - EquivList equiv; - characterClass( equiv ); - - /* Expand the transitions. This uses the equivalence classes. */ - for ( RedStateList::Iter st = stateList; st.lte(); st++ ) { - if ( st->outRange.length() == 0 ) { - st->lowKey = st->highKey = 0; - st->low = st->high = 0; - st->transList = 0; - } - else { - st->lowKey = st->outRange[0].lowKey; - st->highKey = st->outRange[st->outRange.length()-1].highKey; - - /* Compute low and high in class space. Use a pair iter to find all - * the clases. Alleviates the need to iterate the whole input - * alphabet. */ - st->low = nextClass; - st->high = -1; - for ( RangePairIter< PiList<EquivClass>, PiVector<RedTransEl> > - pair( fsmCtx, equiv, st->outRange ); !pair.end(); pair++ ) - { - if ( pair.userState == RangePairIter<PiList<EquivClass>, PiVector<RedTransEl> >::RangeOverlap || - pair.userState == RangePairIter<PiList<EquivClass>, PiVector<RedTransEl> >::RangeInS2 ) - { - long long off = keyOps->span( lowKey, pair.s2Tel.lowKey ) - 1; - if ( classMap[off] < st->low ) - st->low = classMap[off]; - if ( classMap[off] > st->high ) - st->high = classMap[off]; - } - } - - long long span = st->high - st->low + 1; - st->transList = new RedTransAp*[ span ]; - memset( st->transList, 0, sizeof(RedTransAp*)*span ); - - for ( RangePairIter< PiList<EquivClass>, PiVector<RedTransEl> > - pair( fsmCtx, equiv, st->outRange ); !pair.end(); pair++ ) - { - if ( pair.userState == RangePairIter< PiList<EquivClass>, PiVector<RedTransEl> >::RangeOverlap || - pair.userState == RangePairIter< PiList<EquivClass>, PiVector<RedTransEl> >::RangeInS2 ) - { - long long off = keyOps->span( lowKey, pair.s2Tel.lowKey ) - 1; - st->transList[ classMap[off] - st->low ] = pair.s2Tel.trans->value; - } - } - - /* Fill in the gaps with the default transition. */ - for ( long long pos = 0; pos < span; pos++ ) { - if ( st->transList[pos] == 0 ) - st->transList[pos] = st->defTrans; - } - } - } - - equiv.empty(); -} - - -/* 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->lt( 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; - keyOps->increment( highKey ); - if ( keyOps->ne( highKey, rtel->lowKey ) ) - return false; - } - - /* The last must extend to the upper bound. */ - RedTransEl *last = &outRange[outRange.length()-1]; - if ( keyOps->lt( 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++ ) { - for ( int c = 0; c < rtel->value->numConds(); c++ ) { - RedCondPair *cond = rtel->value->outCond(c); - if ( cond->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 ); - } -} - -RedCondAp *RedFsmAp::getErrorCond() -{ - return allocateCond( getErrorState(), 0 ); -} - -RedTransAp *RedFsmAp::getErrorTrans() -{ - return allocateTrans( getErrorState(), 0 ); -} - -RedStateAp *RedFsmAp::getErrorState() -{ - /* Something went wrong. An error state is needed but one was not supplied - * by the frontend. */ - assert( errState != 0 ); - return errState; -} - -/* Makes a plain transition. */ -RedTransAp *RedFsmAp::allocateTrans( RedStateAp *targ, RedAction *action ) -{ - /* Create a reduced trans and look for it in the transiton set. */ - RedTransAp redTrans( 0, 0, targ, action ); - RedTransAp *inDict = transSet.find( &redTrans ); - if ( inDict == 0 ) { - inDict = new RedTransAp( nextTransId++, nextCondId++, targ, action ); - transSet.insert( inDict ); - } - return inDict; -} - -/* Makes a cond list transition. */ -RedTransAp *RedFsmAp::allocateTrans( GenCondSpace *condSpace, - RedCondEl *outConds, int numConds, RedCondAp *errCond ) -{ - /* Create a reduced trans and look for it in the transiton set. */ - RedTransAp redTrans( 0, condSpace, outConds, numConds, errCond ); - RedTransAp *inDict = transSet.find( &redTrans ); - if ( inDict == 0 ) { - inDict = new RedTransAp( nextTransId++, condSpace, outConds, numConds, errCond ); - transSet.insert( inDict ); - } - else { - /* Need to free the out cond vector. */ - delete[] outConds; - } - return inDict; -} - -RedCondAp *RedFsmAp::allocateCond( RedStateAp *targ, RedAction *action ) -{ - /* Create a reduced trans and look for it in the transiton set. */ - RedCondAp redCond( targ, action, 0 ); - RedCondAp *inDict = condSet.find( &redCond ); - if ( inDict == 0 ) { - inDict = new RedCondAp( targ, action, nextCondId++ ); - condSet.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 ( CondApSet::Iter trans = condSet; trans.lte(); trans++ ) - trans->p.targ->numInConds += 1; - - for ( TransApSet::Iter trans = transSet; trans.lte(); trans++ ) { - if ( trans->condSpace == 0 ) - trans->p.targ->numInConds += 1; - else { - /* We have a placement choice here, but associate it with the - * first. */ - RedCondPair *pair = trans->outCond( 0 ); - pair->targ->numInCondTests += 1; - } - } - - /* Allocate. Reset the counts so we can use them as the current size. */ - for ( RedStateList::Iter st = stateList; st.lte(); st++ ) { - st->inConds = new RedCondPair*[st->numInConds]; - st->numInConds = 0; - - st->inCondTests = new RedTransAp*[st->numInCondTests]; - st->numInCondTests = 0; - } - - /* Fill the arrays. */ - for ( CondApSet::Iter trans = condSet; trans.lte(); trans++ ) { - RedStateAp *targ = trans->p.targ; - targ->inConds[targ->numInConds++] = &trans->p; - } - - for ( TransApSet::Iter trans = transSet; trans.lte(); trans++ ) { - if ( trans->condSpace == 0 ) { - RedStateAp *targ = trans->p.targ; - targ->inConds[targ->numInConds++] = &trans->p; - } - else { - RedCondPair *pair = trans->outCond( 0 ); - RedStateAp *targ = pair->targ; - targ->inCondTests[targ->numInCondTests++] = trans; - } - } -} |