The frontend is now responsible for creating the error state, if needed. The
authorthurston <thurston@052ea7fc-9027-0410-9066-f65837a77df0>
Sun, 4 Feb 2007 03:15:18 +0000 (03:15 +0000)
committerthurston <thurston@052ea7fc-9027-0410-9066-f65837a77df0>
Sun, 4 Feb 2007 03:15:18 +0000 (03:15 +0000)
error state id is passed using the <error_state> tag.

git-svn-id: http://svn.complang.org/ragel/trunk@72 052ea7fc-9027-0410-9066-f65837a77df0

ragel/fsmbase.cpp
ragel/fsmgraph.h
ragel/parsedata.cpp
ragel/xmlcodegen.cpp
redfsm/gendata.cpp
redfsm/gendata.h
redfsm/redfsm.cpp
redfsm/xmlparse.kh
redfsm/xmlparse.kl
redfsm/xmlscan.rl
redfsm/xmltags.gperf

index 9976fae..96b3488 100644 (file)
@@ -46,6 +46,7 @@ FsmAp::FsmAp()
 :
        /* 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
@@ -65,6 +66,7 @@ FsmAp::FsmAp( const FsmAp &graph )
         * pointers will be resolved later. */
        entryPoints(graph.entryPoints),
        startState(graph.startState),
+       errState(0),
 
        /* Will be filled by copy. */
        finStateSet(),
@@ -509,6 +511,8 @@ void FsmAp::depthFirstOrdering()
        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() );
@@ -540,3 +544,55 @@ void FsmAp::setStateNumbers( int base )
                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;
+}
index 3b29856..e47525a 100644 (file)
@@ -971,6 +971,11 @@ struct FsmAp
        /* 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;
 
@@ -1369,6 +1374,12 @@ struct FsmAp
        /* 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();
 };
 
 
index 2352bb8..5332286 100644 (file)
@@ -1309,6 +1309,13 @@ void ParseData::prepareMachineGen( GraphDictEl *graphDictEl )
        /* 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
@@ -1319,6 +1326,7 @@ void ParseData::prepareMachineGen( GraphDictEl *graphDictEl )
        sectionGraph->depthFirstOrdering();
        sectionGraph->sortStatesByFinal();
        sectionGraph->setStateNumbers( 0 );
+
 }
 
 void ParseData::generateXML( ostream &out )
index 3831c3e..f2bb591 100644 (file)
@@ -595,7 +595,13 @@ void XMLCodeGen::writeMachine()
 
        /* 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();
index db5b8da..7a1963c 100644 (file)
@@ -37,7 +37,8 @@ CodeGenData::CodeGenData( ostream &out )
        allCondSpaces(0),
        allStates(0),
        nameIndex(0),
-       startState(0),
+       startState(-1),
+       errState(-1),
        getKeyExpr(0),
        accessExpr(0),
        curStateExpr(0),
@@ -83,6 +84,14 @@ void CodeGenData::initStateList( unsigned long length )
        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 )
@@ -90,6 +99,11 @@ 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 );
@@ -227,14 +241,6 @@ void CodeGenData::resolveTargetStates( InlineList *inlineList )
 
 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 );
 
index ec22e15..e0ee6df 100644 (file)
@@ -59,6 +59,7 @@ struct CodeGenData
        RedStateAp *allStates;
        NameInst **nameIndex;
        int startState;
+       int errState;
        ActionList actionList;
        ConditionList conditionList;
        CondSpaceList condSpaceList;
@@ -83,6 +84,7 @@ struct CodeGenData
        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 );
index c8495ee..9b1af9b 100644 (file)
@@ -491,11 +491,9 @@ RedTransAp *RedFsmAp::getErrorTrans( )
 
 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;
 }
 
index eda8384..38d6703 100644 (file)
@@ -104,9 +104,9 @@ struct Parser
 
                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.
index 78d895e..0d90418 100644 (file)
@@ -220,6 +220,7 @@ machine_item_list: machine_item_list machine_item;
 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;
@@ -236,6 +237,12 @@ tag_start_state: TAG_start_state '/' TAG_start_state
                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" );
index b826a02..988f589 100644 (file)
@@ -313,8 +313,9 @@ int xml_parse( std::istream &input, char *fileName,
                                        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 );
index 31c32d1..ca7baac 100644 (file)
@@ -36,6 +36,7 @@ trans_list, TAG_trans_list
 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