"eof" is no longer a write command.
[external/ragel.git] / ragel / xmlcodegen.cpp
index a12c56b..8cbe738 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2005-2007 Adrian Thurston <thurston@cs.queensu.ca>
+ *  Copyright 2005-2007 Adrian Thurston <thurston@complang.org>
  */
 
 /*  This file is part of Ragel.
@@ -175,6 +175,26 @@ void XMLCodeGen::writeTransList( StateAp *state )
        out << "      </trans_list>\n";
 }
 
+void XMLCodeGen::writeEofTrans( StateAp *state )
+{
+       RedActionTable *eofActions = 0;
+       if ( state->eofActionTable.length() > 0 )
+               eofActions = actionTableMap.find( state->eofActionTable );
+       
+       /* 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;
+
+               if ( eofActions != 0 )
+                       out << " " << eofActions->id;
+               else
+                       out << " x"; 
+
+               out << "</eof_t>" << endl;
+       }
+}
+
 void XMLCodeGen::writeText( InlineItem *item )
 {
        if ( item->prev == 0 || item->prev->type != InlineItem::Text )
@@ -184,82 +204,7 @@ void XMLCodeGen::writeText( InlineItem *item )
                out << "</text>";
 }
 
-bool isLmItem( InlineItem *context )
-{
-       return context != 0 && (
-               context->type == InlineItem::LmOnLast ||
-               context->type == InlineItem::LmOnNext ||
-               context->type == InlineItem::LmOnLagBehind ||
-               context->type == InlineItem::LmSwitch );
-}
-
-void XMLCodeGen::writeCtrlFlow( InlineItem *item, InlineItem *context )
-{
-       if ( isLmItem( context ) ) {
-               out << "<sub_action>";
-               out << "<exec><get_tokend></get_tokend></exec>";
-       }
-
-       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 ( isLmItem( context ) )
-               out << "</sub_action>";
-}
-
-void XMLCodeGen::writePtrMod( InlineItem *item, InlineItem *context )
-{
-       if ( isLmItem( context ) ) {
-               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>";
@@ -269,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>";
@@ -279,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>";
@@ -289,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>";
@@ -323,83 +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. */
 
-       out << "<lm_switch";
-       if ( longestMatch->lmSwitchHandlesError )
-               out << " handles_error=\"t\"";
-       out << ">\n";
+       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 && 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";
+               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";
+                       }
                }
        }
 
-       out << "    </lm_switch><exec><get_tokend></get_tokend></exec>";
+       if ( needDefault ) {
+               out << "        <sub_action id=\"-1\"><exec><get_tokend>"
+                               "</get_tokend></exec></sub_action>\n";
+       }
+
+       out << "    </lm_switch>";
 }
 
-void XMLCodeGen::writeInlineList( InlineList *inlineList, InlineItem *context )
+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>";
@@ -418,8 +398,10 @@ 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::LmSetActId:
@@ -463,7 +445,7 @@ 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";
 }
 
@@ -491,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 ) {
@@ -510,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";
        }
 }
 
@@ -542,6 +528,7 @@ void XMLCodeGen::writeStateList()
                out << ">\n";
 
                writeStateActions( st );
+               writeEofTrans( st );
                writeStateConditions( st );
                writeTransList( st );
 
@@ -662,69 +649,95 @@ void XMLCodeGen::writeXML()
        /* Getkey expression. */
        if ( pd->getKeyExpr != 0 ) {
                out << "  <getkey>";
-               writeInlineList( pd->getKeyExpr, 0 );
+               writeInlineList( pd->getKeyExpr );
                out << "</getkey>\n";
        }
 
        /* Access expression. */
        if ( pd->accessExpr != 0 ) {
                out << "  <access>";
-               writeInlineList( pd->accessExpr, 0 );
+               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, 0 );
+               writeInlineList( pd->pExpr );
                out << "</p_expr>\n";
        }
        
        if ( pd->peExpr != 0 ) {
                out << "  <pe_expr>";
-               writeInlineList( pd->peExpr, 0 );
+               writeInlineList( pd->peExpr );
                out << "</pe_expr>\n";
        }
+
+       if ( pd->eofExpr != 0 ) {
+               out << "  <eof_expr>";
+               writeInlineList( pd->eofExpr );
+               out << "</eof_expr>\n";
+       }
        
        if ( pd->csExpr != 0 ) {
                out << "  <cs_expr>";
-               writeInlineList( pd->csExpr, 0 );
+               writeInlineList( pd->csExpr );
                out << "</cs_expr>\n";
        }
        
        if ( pd->topExpr != 0 ) {
                out << "  <top_expr>";
-               writeInlineList( pd->topExpr, 0 );
+               writeInlineList( pd->topExpr );
                out << "</top_expr>\n";
        }
        
        if ( pd->stackExpr != 0 ) {
                out << "  <stack_expr>";
-               writeInlineList( pd->stackExpr, 0 );
+               writeInlineList( pd->stackExpr );
                out << "</stack_expr>\n";
        }
        
        if ( pd->actExpr != 0 ) {
                out << "  <act_expr>";
-               writeInlineList( pd->actExpr, 0 );
+               writeInlineList( pd->actExpr );
                out << "</act_expr>\n";
        }
        
        if ( pd->tokstartExpr != 0 ) {
                out << "  <tokstart_expr>";
-               writeInlineList( pd->tokstartExpr, 0 );
+               writeInlineList( pd->tokstartExpr );
                out << "</tokstart_expr>\n";
        }
        
        if ( pd->tokendExpr != 0 ) {
                out << "  <tokend_expr>";
-               writeInlineList( pd->tokendExpr, 0 );
+               writeInlineList( pd->tokendExpr );
                out << "</tokend_expr>\n";
        }
        
+       if ( pd->dataExpr != 0 ) {
+               out << "  <data_expr>";
+               writeInlineList( pd->dataExpr );
+               out << "</data_expr>\n";
+       }
+       
        writeExports();
        
        writeMachine();