:
/* No start state. */
startState(0),
+ errState(0),
/* Misfit accounting is a switch, turned on only at specific times. It
* controls what happens when states have no way in from the outside
* pointers will be resolved later. */
entryPoints(graph.entryPoints),
startState(graph.startState),
+ errState(0),
/* Will be filled by copy. */
finStateSet(),
depthFirstOrdering( startState );
for ( EntryMap::Iter en = entryPoints; en.lte(); en++ )
depthFirstOrdering( en->value );
+ if ( errState != 0 )
+ depthFirstOrdering( errState );
/* Make sure we put everything back on. */
assert( stateListLen == stateList.length() );
state->alg.stateNum = base++;
}
+
+bool FsmAp::checkErrTrans( StateAp *state, TransAp *trans )
+{
+ /* Might go directly to error state. */
+ if ( trans->toState == 0 )
+ return true;
+
+ if ( trans->prev == 0 ) {
+ /* If this is the first transition. */
+ if ( keyOps->minKey < trans->lowKey )
+ return true;
+ }
+ else {
+ /* Not the first transition. Compare against the prev. */
+ TransAp *prev = trans->prev;
+ Key nextKey = prev->highKey;
+ nextKey.increment();
+ if ( nextKey < trans->lowKey )
+ return true;
+ }
+ return false;
+}
+
+bool FsmAp::checkErrTransFinish( StateAp *state )
+{
+ /* Check if there are any ranges already. */
+ if ( state->outList.length() == 0 )
+ return true;
+ else {
+ /* Get the last and check for a gap on the end. */
+ TransAp *last = state->outList.tail;
+ if ( last->highKey < keyOps->maxKey )
+ return true;
+ }
+ return 0;
+}
+
+bool FsmAp::hasErrorTrans()
+{
+ bool result;
+ for ( StateList::Iter st = stateList; st.lte(); st++ ) {
+ for ( TransList::Iter tr = st->outList; tr.lte(); tr++ ) {
+ result = checkErrTrans( st, tr );
+ if ( result )
+ return true;
+ }
+ result = checkErrTransFinish( st );
+ if ( result )
+ return true;
+ }
+ return false;
+}
/* The start state. */
StateAp *startState;
+ /* Error state, possibly created only when the final machine has been
+ * created and the XML machine is about to be written. No transitions
+ * point to this state. */
+ StateAp *errState;
+
/* The set of final states. */
StateSet finStateSet;
/* Merge neighboring transitions go to the same state and have the same
* transitions data. */
void compressTransitions();
+
+ /* Returns true if there is a transtion (either explicit or by a gap) to
+ * the error state. */
+ bool checkErrTrans( StateAp *state, TransAp *trans );
+ bool checkErrTransFinish( StateAp *state );
+ bool hasErrorTrans();
};
/* Depends on the graph analysis. */
setLongestMatchData( sectionGraph );
+ /* Decide if an error state is necessary.
+ * 1. There is an error transition
+ * 2. There is a gap in the transitions
+ * 3. The longest match operator requires it. */
+ if ( lmRequiresErrorState || sectionGraph->hasErrorTrans() )
+ sectionGraph->errState = sectionGraph->addState();
+
/* State numbers need to be assigned such that all final states have a
* larger state id number than all non-final states. This enables the
* first_final mechanism to function correctly. We also want states to be
sectionGraph->depthFirstOrdering();
sectionGraph->sortStatesByFinal();
sectionGraph->setStateNumbers( 0 );
+
}
void ParseData::generateXML( ostream &out )
/* Start state. */
out << " <start_state>" << fsm->startState->alg.stateNum <<
- "</start_state>\n";
+ "</start_state>\n";
+
+ /* Error state. */
+ if ( fsm->errState != 0 ) {
+ out << " <error_state>" << fsm->errState->alg.stateNum <<
+ "</error_state>\n";
+ }
writeEntryPoints();
writeStateList();
allCondSpaces(0),
allStates(0),
nameIndex(0),
- startState(0),
+ startState(-1),
+ errState(-1),
getKeyExpr(0),
accessExpr(0),
curStateExpr(0),
allStates = new RedStateAp[length];
for ( unsigned long s = 0; s < length; s++ )
redFsm->stateList.append( allStates+s );
+
+ /* We get the start state as an offset, set the pointer now. */
+ assert( startState >= 0 );
+ redFsm->startState = allStates + startState;
+ if ( errState >= 0 )
+ redFsm->errState = allStates + errState;
+ for ( EntryIdVect::Iter en = entryPointIds; en.lte(); en++ )
+ redFsm->entryPoints.insert( allStates + *en );
}
void CodeGenData::setStartState( unsigned long startState )
this->startState = startState;
}
+void CodeGenData::setErrorState( unsigned long errState )
+{
+ this->errState = errState;
+}
+
void CodeGenData::addEntryPoint( char *name, unsigned long entryState )
{
entryPointIds.append( entryState );
void CodeGenData::closeMachine()
{
- if ( redFsm->forcedErrorState )
- redFsm->getErrorState();
-
- /* We get the start state as an offset, set the pointer now. */
- redFsm->startState = allStates + startState;
- for ( EntryIdVect::Iter en = entryPointIds; en.lte(); en++ )
- redFsm->entryPoints.insert( allStates + *en );
-
for ( ActionList::Iter a = actionList; a.lte(); a++ )
resolveTargetStates( a->inlineList );
RedStateAp *allStates;
NameInst **nameIndex;
int startState;
+ int errState;
ActionList actionList;
ConditionList conditionList;
CondSpaceList condSpaceList;
void initActionTableList( unsigned long length );
void initStateList( unsigned long length );
void setStartState( unsigned long startState );
+ void setErrorState( unsigned long errState );
void addEntryPoint( char *name, unsigned long entryState );
void setId( int snum, int id );
void setFinal( int snum );
RedStateAp *RedFsmAp::getErrorState()
{
- /* Check if we need to init the error trans. */
- if ( errState == 0 ) {
- errState = new RedStateAp();
- stateList.append( errState );
- }
+ /* Something went wrong. An error state is needed but one was not supplied
+ * by the frontend. */
+ assert( errState != 0 );
return errState;
}
token TAG_unknown, TAG_ragel, TAG_ragel_def, TAG_host, TAG_state_list,
TAG_state, TAG_trans_list, TAG_t, TAG_machine, TAG_start_state,
- TAG_action_list, TAG_action_table_list, TAG_action,
- TAG_action_table, TAG_alphtype, TAG_element, TAG_getkey,
- TAG_state_actions, TAG_entry_points, TAG_sub_action,
+ TAG_error_state, TAG_action_list, TAG_action_table_list,
+ TAG_action, TAG_action_table, TAG_alphtype, TAG_element,
+ TAG_getkey, TAG_state_actions, TAG_entry_points, TAG_sub_action,
TAG_cond_space_list, TAG_cond_space, TAG_cond_list, TAG_c;
# Inline block tokens.
machine_item_list: ;
machine_item: tag_start_state;
+machine_item: tag_error_state;
machine_item: tag_entry_points;
machine_item: tag_state_list;
machine_item: tag_action_list;
cgd->setStartState( startState );
};
+tag_error_state: TAG_error_state '/' TAG_error_state
+ final {
+ unsigned long errorState = strtoul( $3->tag->content, 0, 10 );
+ cgd->setErrorState( errorState );
+ };
+
tag_entry_points: TAG_entry_points entry_point_list '/' TAG_entry_points
final {
Attribute *errorAttr = $1->tag->findAttr( "error" );
case TAG_call: case TAG_next:
case TAG_entry: case TAG_set_tokend:
case TAG_set_act: case TAG_start_state:
- case TAG_state_actions: case TAG_action_table:
- case TAG_cond_space: case TAG_c:
+ case TAG_error_state: case TAG_state_actions:
+ case TAG_action_table: case TAG_cond_space:
+ case TAG_c:
tag->content = new char[scanner.buffer.length+1];
memcpy( tag->content, scanner.buffer.data,
scanner.buffer.length );
t, TAG_t
machine, TAG_machine
start_state, TAG_start_state
+error_state, TAG_error_state
action_list, TAG_action_list
action, TAG_action
action_table_list, TAG_action_table_list