"eof" is no longer a write command.
[external/ragel.git] / ragel / xmlcodegen.cpp
index 021c97e..8cbe738 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2005, 2006 Adrian Thurston <thurston@cs.queensu.ca>
+ *  Copyright 2005-2007 Adrian Thurston <thurston@complang.org>
  */
 
 /*  This file is part of Ragel.
@@ -175,26 +175,24 @@ void XMLCodeGen::writeTransList( StateAp *state )
        out << "      </trans_list>\n";
 }
 
-void XMLCodeGen::writeLmSwitch( InlineItem *item )
+void XMLCodeGen::writeEofTrans( StateAp *state )
 {
-       LongestMatch *longestMatch = item->longestMatch;
-
-       out << "<lm_switch";
-       if ( longestMatch->lmSwitchHandlesError )
-               out << " handles_error=\"t\"";
-       out << ">\n";
+       RedActionTable *eofActions = 0;
+       if ( state->eofActionTable.length() > 0 )
+               eofActions = actionTableMap.find( state->eofActionTable );
        
-       for ( LmPartList::Iter lmi = *longestMatch->longestMatchList; lmi.lte(); lmi++ ) {
-               if ( lmi->inLmSelect && lmi->action != 0 ) {
-                       /* Open the action. Write it with the context that sets up _p 
-                        * when doing control flow changes from inside the machine. */
-                       out << "      <sub_action id=\"" << lmi->longestMatchId << "\">";
-                       writeInlineList( lmi->action->inlineList, item );
-                       out << "</sub_action>\n";
-               }
-       }
+       /* The <eof_t> is used when there is an eof target, otherwise the eof
+        * action goes into state actions. */
+       if ( state->eofTarget != 0 ) {
+               out << "      <eof_t>" << state->eofTarget->alg.stateNum;
 
-       out << "    </lm_switch><exec><get_tokend></get_tokend></exec>";
+               if ( eofActions != 0 )
+                       out << " " << eofActions->id;
+               else
+                       out << " x"; 
+
+               out << "</eof_t>" << endl;
+       }
 }
 
 void XMLCodeGen::writeText( InlineItem *item )
@@ -206,91 +204,7 @@ void XMLCodeGen::writeText( InlineItem *item )
                out << "</text>";
 }
 
-void XMLCodeGen::writeCtrlFlow( InlineItem *item, InlineItem *context )
-{
-       if ( context != 0 ) {
-               out << "<sub_action>";
-
-               switch ( context->type ) {
-               case InlineItem::LmOnLast:
-                       out << "<exec><get_tokend></get_tokend></exec>";
-                       break;
-               case InlineItem::LmOnNext:
-                       out << "<exec><get_tokend></get_tokend></exec>";
-                       break;
-               case InlineItem::LmOnLagBehind:
-                       out << "<exec><get_tokend></get_tokend></exec>";
-                       break;
-               case InlineItem::LmSwitch:
-                       out << "<exec><get_tokend></get_tokend></exec>";
-                       break;
-               default: break;
-               }
-       }
-
-       switch ( item->type ) {
-       case InlineItem::Goto:
-               writeGoto( item, context );
-               break;
-       case InlineItem::GotoExpr:
-               writeGotoExpr( item, context );
-               break;
-       case InlineItem::Call:
-               writeCall( item, context );
-               break;
-       case InlineItem::CallExpr:
-               writeCallExpr( item, context );
-               break;
-       case InlineItem::Next:
-               writeNext( item, context );
-               break;
-       case InlineItem::NextExpr:
-               writeNextExpr( item, context );
-               break;
-       case InlineItem::Break:
-               out << "<break></break>";
-               break;
-       case InlineItem::Ret: 
-               out << "<ret></ret>";
-               break;
-       default: break;
-       }
-
-       if ( context != 0 )
-               out << "</sub_action>";
-}
-
-void XMLCodeGen::writePtrMod( InlineItem *item, InlineItem *context )
-{
-       if ( context != 0 && ( context->type == InlineItem::LmOnNext ||
-                       context->type == InlineItem::LmOnLagBehind ||
-                       context->type == InlineItem::LmSwitch ) )
-       {
-               switch ( item->type ) {
-               case InlineItem::Hold:
-                       out << "<holdte></holdte>";
-                       break;
-               case InlineItem::Exec:
-                       writeActionExecTE( item );
-                       break;
-               default: break;
-               }
-       }
-       else {
-               switch ( item->type ) {
-               case InlineItem::Hold:
-                       out << "<hold></hold>";
-                       break;
-               case InlineItem::Exec:
-                       writeActionExec( item );
-                       break;
-               default: break;
-               }
-       }
-}
-
-
-void XMLCodeGen::writeGoto( InlineItem *item, InlineItem *context )
+void XMLCodeGen::writeGoto( InlineItem *item )
 {
        if ( pd->generatingSectionSubset )
                out << "<goto>-1</goto>";
@@ -300,7 +214,7 @@ void XMLCodeGen::writeGoto( InlineItem *item, InlineItem *context )
        }
 }
 
-void XMLCodeGen::writeCall( InlineItem *item, InlineItem *context )
+void XMLCodeGen::writeCall( InlineItem *item )
 {
        if ( pd->generatingSectionSubset )
                out << "<call>-1</call>";
@@ -310,7 +224,7 @@ void XMLCodeGen::writeCall( InlineItem *item, InlineItem *context )
        }
 }
 
-void XMLCodeGen::writeNext( InlineItem *item, InlineItem *context )
+void XMLCodeGen::writeNext( InlineItem *item )
 {
        if ( pd->generatingSectionSubset )
                out << "<next>-1</next>";
@@ -320,28 +234,28 @@ void XMLCodeGen::writeNext( InlineItem *item, InlineItem *context )
        }
 }
 
-void XMLCodeGen::writeGotoExpr( InlineItem *item, InlineItem *context )
+void XMLCodeGen::writeGotoExpr( InlineItem *item )
 {
        out << "<goto_expr>";
-       writeInlineList( item->children, 0 );
+       writeInlineList( item->children );
        out << "</goto_expr>";
 }
 
-void XMLCodeGen::writeCallExpr( InlineItem *item, InlineItem *context )
+void XMLCodeGen::writeCallExpr( InlineItem *item )
 {
        out << "<call_expr>";
-       writeInlineList( item->children, 0 );
+       writeInlineList( item->children );
        out << "</call_expr>";
 }
 
-void XMLCodeGen::writeNextExpr( InlineItem *item, InlineItem *context )
+void XMLCodeGen::writeNextExpr( InlineItem *item )
 {
        out << "<next_expr>";
-       writeInlineList( item->children, 0 );
+       writeInlineList( item->children );
        out << "</next_expr>";
 }
 
-void XMLCodeGen::writeEntry( InlineItem * item )
+void XMLCodeGen::writeEntry( InlineItem *item )
 {
        if ( pd->generatingSectionSubset )
                out << "<entry>-1</entry>";
@@ -354,62 +268,118 @@ void XMLCodeGen::writeEntry( InlineItem * item )
 void XMLCodeGen::writeActionExec( InlineItem *item )
 {
        out << "<exec>";
-       writeInlineList( item->children, 0 );
+       writeInlineList( item->children );
        out << "</exec>";
 }
 
-void XMLCodeGen::writeActionExecTE( InlineItem *item )
-{
-       out << "<execte>";
-       writeInlineList( item->children, 0 );
-       out << "</execte>";
-}
-
 void XMLCodeGen::writeLmOnLast( InlineItem *item )
 {
        out << "<set_tokend>1</set_tokend>";
+
        if ( item->longestMatchPart->action != 0 ) {
                out << "<sub_action>";
-               writeInlineList( item->longestMatchPart->action->inlineList, item );
+               writeInlineList( item->longestMatchPart->action->inlineList );
                out << "</sub_action>";
        }
-       out << "<exec><get_tokend></get_tokend></exec>";
 }
 
 void XMLCodeGen::writeLmOnNext( InlineItem *item )
 {
        out << "<set_tokend>0</set_tokend>";
+       out << "<hold></hold>";
+
        if ( item->longestMatchPart->action != 0 ) {
                out << "<sub_action>";
-               writeInlineList( item->longestMatchPart->action->inlineList, item );
+               writeInlineList( item->longestMatchPart->action->inlineList );
                out << "</sub_action>";
        }
-       out << "<exec><get_tokend></get_tokend></exec>";
 }
 
 void XMLCodeGen::writeLmOnLagBehind( InlineItem *item )
 {
+       out << "<exec><get_tokend></get_tokend></exec>";
+
        if ( item->longestMatchPart->action != 0 ) {
                out << "<sub_action>";
-               writeInlineList( item->longestMatchPart->action->inlineList, item );
+               writeInlineList( item->longestMatchPart->action->inlineList );
                out << "</sub_action>";
        }
-       out << "<exec><get_tokend></get_tokend></exec>";
 }
 
+void XMLCodeGen::writeLmSwitch( InlineItem *item )
+{
+       LongestMatch *longestMatch = item->longestMatch;
+       out << "<lm_switch>\n";
+
+       /* We can't put the <exec> here because we may need to handle the error
+        * case and in that case p should not be changed. Instead use a default
+        * label in the switch to adjust p when user actions are not set. An id of
+        * -1 indicates the default. */
 
-void XMLCodeGen::writeInlineList( InlineList *inlineList, InlineItem *context )
+       if ( longestMatch->lmSwitchHandlesError ) {
+               /* If the switch handles error then we should have also forced the
+                * error state. */
+               assert( fsm->errState != 0 );
+
+               out << "        <sub_action id=\"0\">";
+               out << "<goto>" << fsm->errState->alg.stateNum << "</goto>";
+               out << "</sub_action>\n";
+       }
+       
+       bool needDefault = false;
+       for ( LmPartList::Iter lmi = *longestMatch->longestMatchList; lmi.lte(); lmi++ ) {
+               if ( lmi->inLmSelect ) {
+                       if ( lmi->action == 0 )
+                               needDefault = true;
+                       else {
+                               /* Open the action. Write it with the context that sets up _p 
+                                * when doing control flow changes from inside the machine. */
+                               out << "        <sub_action id=\"" << lmi->longestMatchId << "\">";
+                               out << "<exec><get_tokend></get_tokend></exec>";
+                               writeInlineList( lmi->action->inlineList );
+                               out << "</sub_action>\n";
+                       }
+               }
+       }
+
+       if ( needDefault ) {
+               out << "        <sub_action id=\"-1\"><exec><get_tokend>"
+                               "</get_tokend></exec></sub_action>\n";
+       }
+
+       out << "    </lm_switch>";
+}
+
+void XMLCodeGen::writeInlineList( InlineList *inlineList )
 {
        for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
                switch ( item->type ) {
                case InlineItem::Text:
                        writeText( item );
                        break;
-               case InlineItem::Goto: case InlineItem::GotoExpr:
-               case InlineItem::Call: case InlineItem::CallExpr:
-               case InlineItem::Next: case InlineItem::NextExpr:
-               case InlineItem::Break: case InlineItem::Ret: 
-                       writeCtrlFlow( item, context );
+               case InlineItem::Goto:
+                       writeGoto( item );
+                       break;
+               case InlineItem::GotoExpr:
+                       writeGotoExpr( item );
+                       break;
+               case InlineItem::Call:
+                       writeCall( item );
+                       break;
+               case InlineItem::CallExpr:
+                       writeCallExpr( item );
+                       break;
+               case InlineItem::Next:
+                       writeNext( item );
+                       break;
+               case InlineItem::NextExpr:
+                       writeNextExpr( item );
+                       break;
+               case InlineItem::Break:
+                       out << "<break></break>";
+                       break;
+               case InlineItem::Ret: 
+                       out << "<ret></ret>";
                        break;
                case InlineItem::PChar:
                        out << "<pchar></pchar>";
@@ -428,13 +398,12 @@ void XMLCodeGen::writeInlineList( InlineList *inlineList, InlineItem *context )
                        break;
 
                case InlineItem::Hold:
+                       out << "<hold></hold>";
+                       break;
                case InlineItem::Exec:
-                       writePtrMod( item, context );
+                       writeActionExec( item );
                        break;
 
-               case InlineItem::LmSwitch: 
-                       writeLmSwitch( item );
-                       break;
                case InlineItem::LmSetActId:
                        out << "<set_act>" << 
                                        item->longestMatchPart->longestMatchId << 
@@ -443,6 +412,7 @@ void XMLCodeGen::writeInlineList( InlineList *inlineList, InlineItem *context )
                case InlineItem::LmSetTokEnd:
                        out << "<set_tokend>1</set_tokend>";
                        break;
+
                case InlineItem::LmOnLast:
                        writeLmOnLast( item );
                        break;
@@ -452,6 +422,10 @@ void XMLCodeGen::writeInlineList( InlineList *inlineList, InlineItem *context )
                case InlineItem::LmOnLagBehind:
                        writeLmOnLagBehind( item );
                        break;
+               case InlineItem::LmSwitch: 
+                       writeLmSwitch( item );
+                       break;
+
                case InlineItem::LmInitAct:
                        out << "<init_act></init_act>";
                        break;
@@ -471,11 +445,11 @@ void XMLCodeGen::writeAction( Action *action )
        if ( action->name != 0 ) 
                out << " name=\"" << action->name << "\"";
        out << " line=\"" << action->loc.line << "\" col=\"" << action->loc.col << "\">";
-       writeInlineList( action->inlineList, 0 );
+       writeInlineList( action->inlineList );
        out << "</action>\n";
 }
 
-void xmlEscapeHost( std::ostream &out, char *data, int len )
+void xmlEscapeHost( std::ostream &out, char *data, long len )
 {
        char *end = data + len;
        while ( data != end ) {
@@ -499,8 +473,10 @@ void XMLCodeGen::writeStateActions( StateAp *state )
        if ( state->fromStateActionTable.length() > 0 )
                fromStateActions = actionTableMap.find( state->fromStateActionTable );
 
+       /* EOF actions go out here only if the state has no eof target. If it has
+        * an eof target then an eof transition will be used instead. */
        RedActionTable *eofActions = 0;
-       if ( state->eofActionTable.length() > 0 )
+       if ( state->eofTarget == 0 && state->eofActionTable.length() > 0 )
                eofActions = actionTableMap.find( state->eofActionTable );
        
        if ( toStateActions != 0 || fromStateActions != 0 || eofActions != 0 ) {
@@ -518,7 +494,9 @@ void XMLCodeGen::writeStateActions( StateAp *state )
                if ( eofActions != 0 )
                        out << " " << eofActions->id;
                else
-                       out << " x"; out << "</state_actions>\n";
+                       out << " x";
+
+               out << "</state_actions>\n";
        }
 }
 
@@ -550,6 +528,7 @@ void XMLCodeGen::writeStateList()
                out << ">\n";
 
                writeStateActions( st );
+               writeEofTrans( st );
                writeStateConditions( st );
                writeTransList( st );
 
@@ -610,11 +589,8 @@ void XMLCodeGen::writeMachine()
        writeConditions();
 
        /* Start state. */
-       GraphDictEl *mainEl = pd->graphDict.find( mainMachine );
-       if ( mainEl != 0 ) {
-               out << "    <start_state>" << fsm->startState->alg.stateNum << 
+       out << "    <start_state>" << fsm->startState->alg.stateNum << 
                        "</start_state>\n";
-       }
        
        /* Error state. */
        if ( fsm->errState != 0 ) {
@@ -628,32 +604,6 @@ void XMLCodeGen::writeMachine()
        out << "  </machine>\n";
 }
 
-void XMLCodeGen::writeAlphType()
-{
-       out << "  <alphtype>" << 
-               (keyOps->alphType - hostLang->hostTypes) << "</alphtype>\n";
-}
-
-void XMLCodeGen::writeGetKeyExpr()
-{
-       out << "  <getkey>";
-       writeInlineList( pd->getKeyExpr, 0 );
-       out << "</getkey>\n";
-}
-
-void XMLCodeGen::writeAccessExpr()
-{
-       out << "  <access>";
-       writeInlineList( pd->accessExpr, 0 );
-       out << "</access>\n";
-}
-
-void XMLCodeGen::writeCurStateExpr()
-{
-       out << "  <curstate>";
-       writeInlineList( pd->curStateExpr, 0 );
-       out << "</curstate>\n";
-}
 
 void XMLCodeGen::writeConditions()
 {
@@ -692,16 +642,101 @@ void XMLCodeGen::writeXML()
 {
        /* Open the definition. */
        out << "<ragel_def name=\"" << fsmName << "\">\n";
-       writeAlphType();
+
+       /* Alphabet type. */
+       out << "  <alphtype>" << keyOps->alphType->internalName << "</alphtype>\n";
        
-       if ( pd->getKeyExpr != 0 )
-               writeGetKeyExpr();
+       /* Getkey expression. */
+       if ( pd->getKeyExpr != 0 ) {
+               out << "  <getkey>";
+               writeInlineList( pd->getKeyExpr );
+               out << "</getkey>\n";
+       }
 
-       if ( pd->accessExpr != 0 )
-               writeAccessExpr();
+       /* Access expression. */
+       if ( pd->accessExpr != 0 ) {
+               out << "  <access>";
+               writeInlineList( pd->accessExpr );
+               out << "</access>\n";
+       }
+
+       /* PrePush expression. */
+       if ( pd->prePushExpr != 0 ) {
+               out << "  <prepush>";
+               writeInlineList( pd->prePushExpr );
+               out << "</prepush>\n";
+       }
+
+       /* PostPop expression. */
+       if ( pd->postPopExpr != 0 ) {
+               out << "  <postpop>";
+               writeInlineList( pd->postPopExpr );
+               out << "</postpop>\n";
+       }
+
+       /*
+        * Variable expressions.
+        */
+
+       if ( pd->pExpr != 0 ) {
+               out << "  <p_expr>";
+               writeInlineList( pd->pExpr );
+               out << "</p_expr>\n";
+       }
+       
+       if ( pd->peExpr != 0 ) {
+               out << "  <pe_expr>";
+               writeInlineList( pd->peExpr );
+               out << "</pe_expr>\n";
+       }
 
-       if ( pd->curStateExpr != 0 )
-               writeCurStateExpr();
+       if ( pd->eofExpr != 0 ) {
+               out << "  <eof_expr>";
+               writeInlineList( pd->eofExpr );
+               out << "</eof_expr>\n";
+       }
+       
+       if ( pd->csExpr != 0 ) {
+               out << "  <cs_expr>";
+               writeInlineList( pd->csExpr );
+               out << "</cs_expr>\n";
+       }
+       
+       if ( pd->topExpr != 0 ) {
+               out << "  <top_expr>";
+               writeInlineList( pd->topExpr );
+               out << "</top_expr>\n";
+       }
+       
+       if ( pd->stackExpr != 0 ) {
+               out << "  <stack_expr>";
+               writeInlineList( pd->stackExpr );
+               out << "</stack_expr>\n";
+       }
+       
+       if ( pd->actExpr != 0 ) {
+               out << "  <act_expr>";
+               writeInlineList( pd->actExpr );
+               out << "</act_expr>\n";
+       }
+       
+       if ( pd->tokstartExpr != 0 ) {
+               out << "  <tokstart_expr>";
+               writeInlineList( pd->tokstartExpr );
+               out << "</tokstart_expr>\n";
+       }
+       
+       if ( pd->tokendExpr != 0 ) {
+               out << "  <tokend_expr>";
+               writeInlineList( pd->tokendExpr );
+               out << "</tokend_expr>\n";
+       }
+       
+       if ( pd->dataExpr != 0 ) {
+               out << "  <data_expr>";
+               writeInlineList( pd->dataExpr );
+               out << "</data_expr>\n";
+       }
        
        writeExports();