"Fossies" - the Fresh Open Source Software Archive

Member "ragel-6.10/ragel/cdgoto.cpp" (24 Mar 2017, 22436 Bytes) of package /linux/misc/ragel-6.10.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "cdgoto.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 6.9_vs_6.10.

    1 /*
    2  *  Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
    3  *            2004 Erich Ocean <eric.ocean@ampede.com>
    4  *            2005 Alan West <alan@alanz.com>
    5  */
    6 
    7 /*  This file is part of Ragel.
    8  *
    9  *  Ragel is free software; you can redistribute it and/or modify
   10  *  it under the terms of the GNU General Public License as published by
   11  *  the Free Software Foundation; either version 2 of the License, or
   12  *  (at your option) any later version.
   13  * 
   14  *  Ragel is distributed in the hope that it will be useful,
   15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   17  *  GNU General Public License for more details.
   18  * 
   19  *  You should have received a copy of the GNU General Public License
   20  *  along with Ragel; if not, write to the Free Software
   21  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
   22  */
   23 
   24 #include "ragel.h"
   25 #include "cdgoto.h"
   26 #include "redfsm.h"
   27 #include "bstmap.h"
   28 #include "gendata.h"
   29 
   30 /* Emit the goto to take for a given transition. */
   31 std::ostream &GotoCodeGen::TRANS_GOTO( RedTransAp *trans, int level )
   32 {
   33     out << TABS(level) << "goto tr" << trans->id << ";";
   34     return out;
   35 }
   36 
   37 std::ostream &GotoCodeGen::TO_STATE_ACTION_SWITCH()
   38 {
   39     /* Walk the list of functions, printing the cases. */
   40     for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
   41         /* Write out referenced actions. */
   42         if ( act->numToStateRefs > 0 ) {
   43             /* Write the case label, the action and the case break. */
   44             out << "\tcase " << act->actionId << ":\n";
   45             ACTION( out, act, 0, false, false );
   46             out << "\tbreak;\n";
   47         }
   48     }
   49 
   50     genLineDirective( out );
   51     return out;
   52 }
   53 
   54 std::ostream &GotoCodeGen::FROM_STATE_ACTION_SWITCH()
   55 {
   56     /* Walk the list of functions, printing the cases. */
   57     for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
   58         /* Write out referenced actions. */
   59         if ( act->numFromStateRefs > 0 ) {
   60             /* Write the case label, the action and the case break. */
   61             out << "\tcase " << act->actionId << ":\n";
   62             ACTION( out, act, 0, false, false );
   63             out << "\tbreak;\n";
   64         }
   65     }
   66 
   67     genLineDirective( out );
   68     return out;
   69 }
   70 
   71 std::ostream &GotoCodeGen::EOF_ACTION_SWITCH()
   72 {
   73     /* Walk the list of functions, printing the cases. */
   74     for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
   75         /* Write out referenced actions. */
   76         if ( act->numEofRefs > 0 ) {
   77             /* Write the case label, the action and the case break. */
   78             out << "\tcase " << act->actionId << ":\n";
   79             ACTION( out, act, 0, true, false );
   80             out << "\tbreak;\n";
   81         }
   82     }
   83 
   84     genLineDirective( out );
   85     return out;
   86 }
   87 
   88 std::ostream &GotoCodeGen::ACTION_SWITCH()
   89 {
   90     /* Walk the list of functions, printing the cases. */
   91     for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
   92         /* Write out referenced actions. */
   93         if ( act->numTransRefs > 0 ) {
   94             /* Write the case label, the action and the case break. */
   95             out << "\tcase " << act->actionId << ":\n";
   96             ACTION( out, act, 0, false, false );
   97             out << "\tbreak;\n";
   98         }
   99     }
  100 
  101     genLineDirective( out );
  102     return out;
  103 }
  104 
  105 void GotoCodeGen::GOTO_HEADER( RedStateAp *state )
  106 {
  107     /* Label the state. */
  108     out << "case " << state->id << ":\n";
  109 }
  110 
  111 
  112 void GotoCodeGen::emitSingleSwitch( RedStateAp *state )
  113 {
  114     /* Load up the singles. */
  115     int numSingles = state->outSingle.length();
  116     RedTransEl *data = state->outSingle.data;
  117 
  118     if ( numSingles == 1 ) {
  119         /* If there is a single single key then write it out as an if. */
  120         out << "\tif ( " << GET_WIDE_KEY(state) << " == " << 
  121                 WIDE_KEY(state, data[0].lowKey) << " )\n\t\t"; 
  122 
  123         /* Virtual function for writing the target of the transition. */
  124         TRANS_GOTO(data[0].value, 0) << "\n";
  125     }
  126     else if ( numSingles > 1 ) {
  127         /* Write out single keys in a switch if there is more than one. */
  128         out << "\tswitch( " << GET_WIDE_KEY(state) << " ) {\n";
  129 
  130         /* Write out the single indicies. */
  131         for ( int j = 0; j < numSingles; j++ ) {
  132             out << "\t\tcase " << WIDE_KEY(state, data[j].lowKey) << ": ";
  133             TRANS_GOTO(data[j].value, 0) << "\n";
  134         }
  135         
  136         /* Emits a default case for D code. */
  137         SWITCH_DEFAULT();
  138 
  139         /* Close off the transition switch. */
  140         out << "\t}\n";
  141     }
  142 }
  143 
  144 void GotoCodeGen::emitRangeBSearch( RedStateAp *state, int level, int low, int high )
  145 {
  146     /* Get the mid position, staying on the lower end of the range. */
  147     int mid = (low + high) >> 1;
  148     RedTransEl *data = state->outRange.data;
  149 
  150     /* Determine if we need to look higher or lower. */
  151     bool anyLower = mid > low;
  152     bool anyHigher = mid < high;
  153 
  154     /* Determine if the keys at mid are the limits of the alphabet. */
  155     bool limitLow = data[mid].lowKey == keyOps->minKey;
  156     bool limitHigh = data[mid].highKey == keyOps->maxKey;
  157 
  158     if ( anyLower && anyHigher ) {
  159         /* Can go lower and higher than mid. */
  160         out << TABS(level) << "if ( " << GET_WIDE_KEY(state) << " < " << 
  161                 WIDE_KEY(state, data[mid].lowKey) << " ) {\n";
  162         emitRangeBSearch( state, level+1, low, mid-1 );
  163         out << TABS(level) << "} else if ( " << GET_WIDE_KEY(state) << " > " << 
  164                 WIDE_KEY(state, data[mid].highKey) << " ) {\n";
  165         emitRangeBSearch( state, level+1, mid+1, high );
  166         out << TABS(level) << "} else\n";
  167         TRANS_GOTO(data[mid].value, level+1) << "\n";
  168     }
  169     else if ( anyLower && !anyHigher ) {
  170         /* Can go lower than mid but not higher. */
  171         out << TABS(level) << "if ( " << GET_WIDE_KEY(state) << " < " << 
  172                 WIDE_KEY(state, data[mid].lowKey) << " ) {\n";
  173         emitRangeBSearch( state, level+1, low, mid-1 );
  174 
  175         /* if the higher is the highest in the alphabet then there is no
  176          * sense testing it. */
  177         if ( limitHigh ) {
  178             out << TABS(level) << "} else\n";
  179             TRANS_GOTO(data[mid].value, level+1) << "\n";
  180         }
  181         else {
  182             out << TABS(level) << "} else if ( " << GET_WIDE_KEY(state) << " <= " << 
  183                     WIDE_KEY(state, data[mid].highKey) << " )\n";
  184             TRANS_GOTO(data[mid].value, level+1) << "\n";
  185         }
  186     }
  187     else if ( !anyLower && anyHigher ) {
  188         /* Can go higher than mid but not lower. */
  189         out << TABS(level) << "if ( " << GET_WIDE_KEY(state) << " > " << 
  190                 WIDE_KEY(state, data[mid].highKey) << " ) {\n";
  191         emitRangeBSearch( state, level+1, mid+1, high );
  192 
  193         /* If the lower end is the lowest in the alphabet then there is no
  194          * sense testing it. */
  195         if ( limitLow ) {
  196             out << TABS(level) << "} else\n";
  197             TRANS_GOTO(data[mid].value, level+1) << "\n";
  198         }
  199         else {
  200             out << TABS(level) << "} else if ( " << GET_WIDE_KEY(state) << " >= " << 
  201                     WIDE_KEY(state, data[mid].lowKey) << " )\n";
  202             TRANS_GOTO(data[mid].value, level+1) << "\n";
  203         }
  204     }
  205     else {
  206         /* Cannot go higher or lower than mid. It's mid or bust. What
  207          * tests to do depends on limits of alphabet. */
  208         if ( !limitLow && !limitHigh ) {
  209             out << TABS(level) << "if ( " << WIDE_KEY(state, data[mid].lowKey) << " <= " << 
  210                     GET_WIDE_KEY(state) << " && " << GET_WIDE_KEY(state) << " <= " << 
  211                     WIDE_KEY(state, data[mid].highKey) << " )\n";
  212             TRANS_GOTO(data[mid].value, level+1) << "\n";
  213         }
  214         else if ( limitLow && !limitHigh ) {
  215             out << TABS(level) << "if ( " << GET_WIDE_KEY(state) << " <= " << 
  216                     WIDE_KEY(state, data[mid].highKey) << " )\n";
  217             TRANS_GOTO(data[mid].value, level+1) << "\n";
  218         }
  219         else if ( !limitLow && limitHigh ) {
  220             out << TABS(level) << "if ( " << WIDE_KEY(state, data[mid].lowKey) << " <= " << 
  221                     GET_WIDE_KEY(state) << " )\n";
  222             TRANS_GOTO(data[mid].value, level+1) << "\n";
  223         }
  224         else {
  225             /* Both high and low are at the limit. No tests to do. */
  226             TRANS_GOTO(data[mid].value, level+1) << "\n";
  227         }
  228     }
  229 }
  230 
  231 void GotoCodeGen::STATE_GOTO_ERROR()
  232 {
  233     /* Label the state and bail immediately. */
  234     outLabelUsed = true;
  235     RedStateAp *state = redFsm->errState;
  236     out << "case " << state->id << ":\n";
  237     out << "    goto _out;\n";
  238 }
  239 
  240 void GotoCodeGen::COND_TRANSLATE( GenStateCond *stateCond, int level )
  241 {
  242     GenCondSpace *condSpace = stateCond->condSpace;
  243     out << TABS(level) << "_widec = " << CAST(WIDE_ALPH_TYPE()) << "(" <<
  244             KEY(condSpace->baseKey) << " + (" << GET_KEY() << 
  245             " - " << KEY(keyOps->minKey) << "));\n";
  246 
  247     for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
  248         out << TABS(level) << "if ( ";
  249         CONDITION( out, *csi );
  250         Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize());
  251         out << " ) _widec += " << condValOffset << ";\n";
  252     }
  253 }
  254 
  255 void GotoCodeGen::emitCondBSearch( RedStateAp *state, int level, int low, int high )
  256 {
  257     /* Get the mid position, staying on the lower end of the range. */
  258     int mid = (low + high) >> 1;
  259     GenStateCond **data = state->stateCondVect.data;
  260 
  261     /* Determine if we need to look higher or lower. */
  262     bool anyLower = mid > low;
  263     bool anyHigher = mid < high;
  264 
  265     /* Determine if the keys at mid are the limits of the alphabet. */
  266     bool limitLow = data[mid]->lowKey == keyOps->minKey;
  267     bool limitHigh = data[mid]->highKey == keyOps->maxKey;
  268 
  269     if ( anyLower && anyHigher ) {
  270         /* Can go lower and higher than mid. */
  271         out << TABS(level) << "if ( " << GET_KEY() << " < " << 
  272                 KEY(data[mid]->lowKey) << " ) {\n";
  273         emitCondBSearch( state, level+1, low, mid-1 );
  274         out << TABS(level) << "} else if ( " << GET_KEY() << " > " << 
  275                 KEY(data[mid]->highKey) << " ) {\n";
  276         emitCondBSearch( state, level+1, mid+1, high );
  277         out << TABS(level) << "} else {\n";
  278         COND_TRANSLATE(data[mid], level+1);
  279         out << TABS(level) << "}\n";
  280     }
  281     else if ( anyLower && !anyHigher ) {
  282         /* Can go lower than mid but not higher. */
  283         out << TABS(level) << "if ( " << GET_KEY() << " < " << 
  284                 KEY(data[mid]->lowKey) << " ) {\n";
  285         emitCondBSearch( state, level+1, low, mid-1 );
  286 
  287         /* if the higher is the highest in the alphabet then there is no
  288          * sense testing it. */
  289         if ( limitHigh ) {
  290             out << TABS(level) << "} else {\n";
  291             COND_TRANSLATE(data[mid], level+1);
  292             out << TABS(level) << "}\n";
  293         }
  294         else {
  295             out << TABS(level) << "} else if ( " << GET_KEY() << " <= " << 
  296                     KEY(data[mid]->highKey) << " ) {\n";
  297             COND_TRANSLATE(data[mid], level+1);
  298             out << TABS(level) << "}\n";
  299         }
  300     }
  301     else if ( !anyLower && anyHigher ) {
  302         /* Can go higher than mid but not lower. */
  303         out << TABS(level) << "if ( " << GET_KEY() << " > " << 
  304                 KEY(data[mid]->highKey) << " ) {\n";
  305         emitCondBSearch( state, level+1, mid+1, high );
  306 
  307         /* If the lower end is the lowest in the alphabet then there is no
  308          * sense testing it. */
  309         if ( limitLow ) {
  310             out << TABS(level) << "} else {\n";
  311             COND_TRANSLATE(data[mid], level+1);
  312             out << TABS(level) << "}\n";
  313         }
  314         else {
  315             out << TABS(level) << "} else if ( " << GET_KEY() << " >= " << 
  316                     KEY(data[mid]->lowKey) << " ) {\n";
  317             COND_TRANSLATE(data[mid], level+1);
  318             out << TABS(level) << "}\n";
  319         }
  320     }
  321     else {
  322         /* Cannot go higher or lower than mid. It's mid or bust. What
  323          * tests to do depends on limits of alphabet. */
  324         if ( !limitLow && !limitHigh ) {
  325             out << TABS(level) << "if ( " << KEY(data[mid]->lowKey) << " <= " << 
  326                     GET_KEY() << " && " << GET_KEY() << " <= " << 
  327                     KEY(data[mid]->highKey) << " ) {\n";
  328             COND_TRANSLATE(data[mid], level+1);
  329             out << TABS(level) << "}\n";
  330         }
  331         else if ( limitLow && !limitHigh ) {
  332             out << TABS(level) << "if ( " << GET_KEY() << " <= " << 
  333                     KEY(data[mid]->highKey) << " ) {\n";
  334             COND_TRANSLATE(data[mid], level+1);
  335             out << TABS(level) << "}\n";
  336         }
  337         else if ( !limitLow && limitHigh ) {
  338             out << TABS(level) << "if ( " << KEY(data[mid]->lowKey) << " <= " << 
  339                     GET_KEY() << " )\n {";
  340             COND_TRANSLATE(data[mid], level+1);
  341             out << TABS(level) << "}\n";
  342         }
  343         else {
  344             /* Both high and low are at the limit. No tests to do. */
  345             COND_TRANSLATE(data[mid], level);
  346         }
  347     }
  348 }
  349 
  350 std::ostream &GotoCodeGen::STATE_GOTOS()
  351 {
  352     for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
  353         if ( st == redFsm->errState )
  354             STATE_GOTO_ERROR();
  355         else {
  356             /* Writing code above state gotos. */
  357             GOTO_HEADER( st );
  358 
  359             if ( st->stateCondVect.length() > 0 ) {
  360                 out << "    _widec = " << GET_KEY() << ";\n";
  361                 emitCondBSearch( st, 1, 0, st->stateCondVect.length() - 1 );
  362             }
  363 
  364             /* Try singles. */
  365             if ( st->outSingle.length() > 0 )
  366                 emitSingleSwitch( st );
  367 
  368             /* Default case is to binary search for the ranges, if that fails then */
  369             if ( st->outRange.length() > 0 )
  370                 emitRangeBSearch( st, 1, 0, st->outRange.length() - 1 );
  371 
  372             /* Write the default transition. */
  373             TRANS_GOTO( st->defTrans, 1 ) << "\n";
  374         }
  375     }
  376     return out;
  377 }
  378 
  379 std::ostream &GotoCodeGen::TRANSITIONS()
  380 {
  381     /* Emit any transitions that have functions and that go to 
  382      * this state. */
  383     for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) {
  384         /* Write the label for the transition so it can be jumped to. */
  385         out << "    tr" << trans->id << ": ";
  386 
  387         /* Destination state. */
  388         if ( trans->action != 0 && trans->action->anyCurStateRef() )
  389             out << "_ps = " << vCS() << ";";
  390         out << vCS() << " = " << trans->targ->id << "; ";
  391 
  392         if ( trans->action != 0 ) {
  393             /* Write out the transition func. */
  394             out << "goto f" << trans->action->actListId << ";\n";
  395         }
  396         else {
  397             /* No code to execute, just loop around. */
  398             out << "goto _again;\n";
  399         }
  400     }
  401     return out;
  402 }
  403 
  404 std::ostream &GotoCodeGen::EXEC_FUNCS()
  405 {
  406     /* Make labels that set acts and jump to execFuncs. Loop func indicies. */
  407     for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
  408         if ( redAct->numTransRefs > 0 ) {
  409             out << "    f" << redAct->actListId << ": " <<
  410                 "_acts = " << ARR_OFF(A(), itoa( redAct->location+1 ) ) << ";"
  411                 " goto execFuncs;\n";
  412         }
  413     }
  414 
  415     out <<
  416         "\n"
  417         "execFuncs:\n"
  418         "   _nacts = *_acts++;\n"
  419         "   while ( _nacts-- > 0 ) {\n"
  420         "       switch ( *_acts++ ) {\n";
  421         ACTION_SWITCH();
  422         SWITCH_DEFAULT() <<
  423         "       }\n"
  424         "   }\n"
  425         "   goto _again;\n";
  426     return out;
  427 }
  428 
  429 unsigned int GotoCodeGen::TO_STATE_ACTION( RedStateAp *state )
  430 {
  431     int act = 0;
  432     if ( state->toStateAction != 0 )
  433         act = state->toStateAction->location+1;
  434     return act;
  435 }
  436 
  437 unsigned int GotoCodeGen::FROM_STATE_ACTION( RedStateAp *state )
  438 {
  439     int act = 0;
  440     if ( state->fromStateAction != 0 )
  441         act = state->fromStateAction->location+1;
  442     return act;
  443 }
  444 
  445 unsigned int GotoCodeGen::EOF_ACTION( RedStateAp *state )
  446 {
  447     int act = 0;
  448     if ( state->eofAction != 0 )
  449         act = state->eofAction->location+1;
  450     return act;
  451 }
  452 
  453 std::ostream &GotoCodeGen::TO_STATE_ACTIONS()
  454 {
  455     /* Take one off for the psuedo start state. */
  456     int numStates = redFsm->stateList.length();
  457     unsigned int *vals = new unsigned int[numStates];
  458     memset( vals, 0, sizeof(unsigned int)*numStates );
  459 
  460     for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
  461         vals[st->id] = TO_STATE_ACTION(st);
  462 
  463     out << "\t";
  464     for ( int st = 0; st < redFsm->nextStateId; st++ ) {
  465         /* Write any eof action. */
  466         out << vals[st];
  467         if ( st < numStates-1 ) {
  468             out << ", ";
  469             if ( (st+1) % IALL == 0 )
  470                 out << "\n\t";
  471         }
  472     }
  473     out << "\n";
  474     delete[] vals;
  475     return out;
  476 }
  477 
  478 std::ostream &GotoCodeGen::FROM_STATE_ACTIONS()
  479 {
  480     /* Take one off for the psuedo start state. */
  481     int numStates = redFsm->stateList.length();
  482     unsigned int *vals = new unsigned int[numStates];
  483     memset( vals, 0, sizeof(unsigned int)*numStates );
  484 
  485     for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
  486         vals[st->id] = FROM_STATE_ACTION(st);
  487 
  488     out << "\t";
  489     for ( int st = 0; st < redFsm->nextStateId; st++ ) {
  490         /* Write any eof action. */
  491         out << vals[st];
  492         if ( st < numStates-1 ) {
  493             out << ", ";
  494             if ( (st+1) % IALL == 0 )
  495                 out << "\n\t";
  496         }
  497     }
  498     out << "\n";
  499     delete[] vals;
  500     return out;
  501 }
  502 
  503 std::ostream &GotoCodeGen::EOF_ACTIONS()
  504 {
  505     /* Take one off for the psuedo start state. */
  506     int numStates = redFsm->stateList.length();
  507     unsigned int *vals = new unsigned int[numStates];
  508     memset( vals, 0, sizeof(unsigned int)*numStates );
  509 
  510     for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
  511         vals[st->id] = EOF_ACTION(st);
  512 
  513     out << "\t";
  514     for ( int st = 0; st < redFsm->nextStateId; st++ ) {
  515         /* Write any eof action. */
  516         out << vals[st];
  517         if ( st < numStates-1 ) {
  518             out << ", ";
  519             if ( (st+1) % IALL == 0 )
  520                 out << "\n\t";
  521         }
  522     }
  523     out << "\n";
  524     delete[] vals;
  525     return out;
  526 }
  527 
  528 std::ostream &GotoCodeGen::FINISH_CASES()
  529 {
  530     for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
  531         /* States that are final and have an out action need a case. */
  532         if ( st->eofAction != 0 ) {
  533             /* Write the case label. */
  534             out << "\t\tcase " << st->id << ": ";
  535 
  536             /* Write the goto func. */
  537             out << "goto f" << st->eofAction->actListId << ";\n";
  538         }
  539     }
  540     
  541     return out;
  542 }
  543 
  544 void GotoCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
  545 {
  546     ret << "{";
  547 
  548     ret << vCS() << " = " << gotoDest << ";";
  549 
  550     if ( inFinish && !noEnd )
  551         EOF_CHECK( ret );
  552 
  553     ret << CTRL_FLOW() << "goto _again;";
  554 
  555     ret << "}";
  556 }
  557 
  558 void GotoCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
  559 {
  560     ret << "{";
  561 
  562     ret << vCS() << " = (";
  563     INLINE_LIST( ret, ilItem->children, 0, inFinish, false );
  564     ret << ");";
  565 
  566     if ( inFinish && !noEnd )
  567         EOF_CHECK( ret );
  568 
  569     ret << CTRL_FLOW() << "goto _again;";
  570 
  571     ret << "}";
  572 }
  573 
  574 void GotoCodeGen::CURS( ostream &ret, bool inFinish )
  575 {
  576     ret << "(_ps)";
  577 }
  578 
  579 void GotoCodeGen::TARGS( ostream &ret, bool inFinish, int targState )
  580 {
  581     ret << "(" << vCS() << ")";
  582 }
  583 
  584 void GotoCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
  585 {
  586     ret << vCS() << " = " << nextDest << ";";
  587 }
  588 
  589 void GotoCodeGen::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
  590 {
  591     ret << vCS() << " = (";
  592     INLINE_LIST( ret, ilItem->children, 0, inFinish, false );
  593     ret << ");";
  594 }
  595 
  596 void GotoCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
  597 {
  598     if ( prePushExpr != 0 ) {
  599         ret << "{";
  600         INLINE_LIST( ret, prePushExpr, 0, false, false );
  601     }
  602 
  603     ret << "{";
  604 
  605     ret << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = " << callDest << ";";
  606 
  607     if ( inFinish && !noEnd )
  608         EOF_CHECK( ret );
  609 
  610     ret << CTRL_FLOW() << "goto _again;";
  611 
  612     ret << "}";
  613 
  614     if ( prePushExpr != 0 )
  615         ret << "}";
  616 }
  617 
  618 void GotoCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish )
  619 {
  620     if ( prePushExpr != 0 ) {
  621         ret << "{";
  622         INLINE_LIST( ret, prePushExpr, 0, false, false );
  623     }
  624 
  625     ret << "{";
  626 
  627     ret << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = (";
  628     INLINE_LIST( ret, ilItem->children, targState, inFinish, false );
  629     ret << ");";
  630 
  631     if ( inFinish && !noEnd )
  632         EOF_CHECK( ret );
  633 
  634     ret << CTRL_FLOW() << "goto _again;";
  635 
  636     ret << "}";
  637 
  638     if ( prePushExpr != 0 )
  639         ret << "}";
  640 }
  641 
  642 void GotoCodeGen::RET( ostream &ret, bool inFinish )
  643 {
  644     ret << "{" << vCS() << " = " << STACK() << "[--" << TOP() << "];";
  645 
  646     if ( postPopExpr != 0 ) {
  647         ret << "{";
  648         INLINE_LIST( ret, postPopExpr, 0, false, false );
  649         ret << "}";
  650     }
  651 
  652     if ( inFinish && !noEnd )
  653         EOF_CHECK( ret );
  654 
  655     ret << CTRL_FLOW() << "goto _again;";
  656     ret << "}";
  657 }
  658 
  659 void GotoCodeGen::BREAK( ostream &ret, int targState, bool csForced )
  660 {
  661     outLabelUsed = true;
  662     ret << "{" << P() << "++; " << CTRL_FLOW() << "goto _out; }";
  663 }
  664 
  665 void GotoCodeGen::writeData()
  666 {
  667     if ( redFsm->anyActions() ) {
  668         OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
  669         ACTIONS_ARRAY();
  670         CLOSE_ARRAY() <<
  671         "\n";
  672     }
  673 
  674     if ( redFsm->anyToStateActions() ) {
  675         OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
  676         TO_STATE_ACTIONS();
  677         CLOSE_ARRAY() <<
  678         "\n";
  679     }
  680 
  681     if ( redFsm->anyFromStateActions() ) {
  682         OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
  683         FROM_STATE_ACTIONS();
  684         CLOSE_ARRAY() <<
  685         "\n";
  686     }
  687 
  688     if ( redFsm->anyEofActions() ) {
  689         OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
  690         EOF_ACTIONS();
  691         CLOSE_ARRAY() <<
  692         "\n";
  693     }
  694 
  695     STATE_IDS();
  696 }
  697 
  698 void GotoCodeGen::writeExec()
  699 {
  700     testEofUsed = false;
  701     outLabelUsed = false;
  702 
  703     out << "    {\n";
  704 
  705     if ( redFsm->anyRegCurStateRef() )
  706         out << "    int _ps = 0;\n";
  707 
  708     if ( redFsm->anyToStateActions() || redFsm->anyRegActions() 
  709             || redFsm->anyFromStateActions() )
  710     {
  711         out << 
  712             "   " << PTR_CONST() << ARRAY_TYPE(redFsm->maxActArrItem) << PTR_CONST_END() << POINTER() << "_acts;\n"
  713             "   " << UINT() << " _nacts;\n";
  714     }
  715 
  716     if ( redFsm->anyConditions() )
  717         out << "    " << WIDE_ALPH_TYPE() << " _widec;\n";
  718 
  719     out << "\n";
  720 
  721     if ( !noEnd ) {
  722         testEofUsed = true;
  723         out << 
  724             "   if ( " << P() << " == " << PE() << " )\n"
  725             "       goto _test_eof;\n";
  726     }
  727 
  728     if ( redFsm->errState != 0 ) {
  729         outLabelUsed = true;
  730         out << 
  731             "   if ( " << vCS() << " == " << redFsm->errState->id << " )\n"
  732             "       goto _out;\n";
  733     }
  734 
  735     out << "_resume:\n";
  736 
  737     if ( redFsm->anyFromStateActions() ) {
  738         out <<
  739             "   _acts = " << ARR_OFF( A(), FSA() + "[" + vCS() + "]" ) << ";\n"
  740             "   _nacts = " << CAST(UINT()) << " *_acts++;\n"
  741             "   while ( _nacts-- > 0 ) {\n"
  742             "       switch ( *_acts++ ) {\n";
  743             FROM_STATE_ACTION_SWITCH();
  744             SWITCH_DEFAULT() <<
  745             "       }\n"
  746             "   }\n"
  747             "\n";
  748     }
  749 
  750     out <<
  751         "   switch ( " << vCS() << " ) {\n";
  752         STATE_GOTOS();
  753         SWITCH_DEFAULT() <<
  754         "   }\n"
  755         "\n";
  756         TRANSITIONS() <<
  757         "\n";
  758 
  759     if ( redFsm->anyRegActions() )
  760         EXEC_FUNCS() << "\n";
  761 
  762     out << "_again:\n";
  763 
  764     if ( redFsm->anyToStateActions() ) {
  765         out <<
  766             "   _acts = " << ARR_OFF( A(), TSA() + "[" + vCS() + "]" ) << ";\n"
  767             "   _nacts = " << CAST(UINT()) << " *_acts++;\n"
  768             "   while ( _nacts-- > 0 ) {\n"
  769             "       switch ( *_acts++ ) {\n";
  770             TO_STATE_ACTION_SWITCH();
  771             SWITCH_DEFAULT() <<
  772             "       }\n"
  773             "   }\n"
  774             "\n";
  775     }
  776 
  777     if ( redFsm->errState != 0 ) {
  778         outLabelUsed = true;
  779         out << 
  780             "   if ( " << vCS() << " == " << redFsm->errState->id << " )\n"
  781             "       goto _out;\n";
  782     }
  783 
  784     if ( !noEnd ) {
  785         out << 
  786             "   if ( ++" << P() << " != " << PE() << " )\n"
  787             "       goto _resume;\n";
  788     }
  789     else {
  790         out << 
  791             "   " << P() << " += 1;\n"
  792             "   goto _resume;\n";
  793     }
  794 
  795     if ( testEofUsed )
  796         out << "    _test_eof: {}\n";
  797 
  798     if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
  799         out << 
  800             "   if ( " << P() << " == " << vEOF() << " )\n"
  801             "   {\n";
  802 
  803         if ( redFsm->anyEofTrans() ) {
  804             out <<
  805                 "   switch ( " << vCS() << " ) {\n";
  806 
  807             for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
  808                 if ( st->eofTrans != 0 )
  809                     out << "    case " << st->id << ": goto tr" << st->eofTrans->id << ";\n";
  810             }
  811 
  812             SWITCH_DEFAULT() <<
  813                 "   }\n";
  814         }
  815 
  816         if ( redFsm->anyEofActions() ) {
  817             out <<
  818                 "   " << PTR_CONST() << ARRAY_TYPE(redFsm->maxActArrItem) << PTR_CONST_END() << 
  819                         POINTER() << "__acts = " << 
  820                         ARR_OFF( A(), EA() + "[" + vCS() + "]" ) << ";\n"
  821                 "   " << UINT() << " __nacts = " << CAST(UINT()) << " *__acts++;\n"
  822                 "   while ( __nacts-- > 0 ) {\n"
  823                 "       switch ( *__acts++ ) {\n";
  824                 EOF_ACTION_SWITCH();
  825                 SWITCH_DEFAULT() <<
  826                 "       }\n"
  827                 "   }\n";
  828         }
  829 
  830         out <<
  831             "   }\n"
  832             "\n";
  833     }
  834 
  835     if ( outLabelUsed )
  836         out << "    _out: {}\n";
  837 
  838     out << "    }\n";
  839 }