"Fossies" - the Fresh Open Source Software Archive

Member "ragel-6.10/ragel/cdipgoto.cpp" (24 Mar 2017, 12537 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 "cdipgoto.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 "cdipgoto.h"
   26 #include "redfsm.h"
   27 #include "gendata.h"
   28 #include "bstmap.h"
   29 
   30 bool IpGotoCodeGen::useAgainLabel()
   31 {
   32     return redFsm->anyActionRets() || 
   33             redFsm->anyActionByValControl() || 
   34             redFsm->anyRegNextStmt();
   35 }
   36 
   37 void IpGotoCodeGen::EOF_CHECK( ostream &ret, int gotoDest )
   38 {
   39     ret << 
   40         "       if ( " << P() << " == " << PE() << " )\n"
   41         "               goto _test_eof" << gotoDest << ";\n";
   42 
   43     testEofUsed = true;
   44 }
   45 
   46 void IpGotoCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
   47 {
   48     ret << "{";
   49 
   50     if ( inFinish && !noEnd )
   51         EOF_CHECK( ret, gotoDest );
   52 
   53     ret << CTRL_FLOW() << "goto st" << gotoDest << ";";
   54 
   55     ret << "}";
   56 }
   57 
   58 void IpGotoCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
   59 {
   60     if ( prePushExpr != 0 ) {
   61         ret << "{";
   62         INLINE_LIST( ret, prePushExpr, 0, false, false );
   63     }
   64 
   65     ret << "{" << STACK() << "[" << TOP() << "++] = " << targState << ";";
   66 
   67     if ( inFinish && !noEnd )
   68         EOF_CHECK( ret, callDest );
   69 
   70     ret << CTRL_FLOW() << "goto st" << callDest << ";";
   71 
   72     ret << "}";
   73 
   74     if ( prePushExpr != 0 )
   75         ret << "}";
   76 }
   77 
   78 void IpGotoCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish )
   79 {
   80     if ( prePushExpr != 0 ) {
   81         ret << "{";
   82         INLINE_LIST( ret, prePushExpr, 0, false, false );
   83     }
   84 
   85     ret << "{";
   86 
   87     ret << STACK() << "[" << TOP() << "++] = " << targState << "; " << vCS() << " = (";
   88     INLINE_LIST( ret, ilItem->children, 0, inFinish, false );
   89     ret << ");";
   90     
   91     if ( inFinish && !noEnd )
   92         FsmCodeGen::EOF_CHECK( ret );
   93 
   94     ret << CTRL_FLOW() << "goto _again;";
   95 
   96     ret << "}";
   97 
   98     if ( prePushExpr != 0 )
   99         ret << "}";
  100 }
  101 
  102 void IpGotoCodeGen::RET( ostream &ret, bool inFinish )
  103 {
  104     ret << "{" << vCS() << " = " << STACK() << "[--" << TOP() << "];";
  105 
  106     if ( postPopExpr != 0 ) {
  107         ret << "{";
  108         INLINE_LIST( ret, postPopExpr, 0, false, false );
  109         ret << "}";
  110     }
  111 
  112     if ( inFinish && !noEnd )
  113         FsmCodeGen::EOF_CHECK( ret );
  114 
  115     ret << CTRL_FLOW() << "goto _again;";
  116 
  117     ret << "}";
  118 }
  119 
  120 void IpGotoCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
  121 {
  122     ret << "{";
  123 
  124     ret << vCS() << " = (";
  125     INLINE_LIST( ret, ilItem->children, 0, inFinish, false );
  126     ret << ");";
  127 
  128     if ( inFinish && !noEnd )
  129         FsmCodeGen::EOF_CHECK( ret );
  130 
  131     ret << CTRL_FLOW() << "goto _again;";
  132     ret << "}";
  133 }
  134 
  135 void IpGotoCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
  136 {
  137     ret << vCS() << " = " << nextDest << ";";
  138 }
  139 
  140 void IpGotoCodeGen::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
  141 {
  142     ret << vCS() << " = (";
  143     INLINE_LIST( ret, ilItem->children, 0, inFinish, false );
  144     ret << ");";
  145 }
  146 
  147 void IpGotoCodeGen::CURS( ostream &ret, bool inFinish )
  148 {
  149     ret << "(_ps)";
  150 }
  151 
  152 void IpGotoCodeGen::TARGS( ostream &ret, bool inFinish, int targState )
  153 {
  154     ret << targState;
  155 }
  156 
  157 void IpGotoCodeGen::BREAK( ostream &ret, int targState, bool csForced )
  158 {
  159     outLabelUsed = true;
  160     ret << "{" << P() << "++; ";
  161     if ( !csForced ) 
  162         ret << vCS() << " = " << targState << "; ";
  163     ret << CTRL_FLOW() << "goto _out;}";
  164 }
  165 
  166 bool IpGotoCodeGen::IN_TRANS_ACTIONS( RedStateAp *state )
  167 {
  168     bool anyWritten = false;
  169 
  170     /* Emit any transitions that have actions and that go to this state. */
  171     for ( int it = 0; it < state->numInTrans; it++ ) {
  172         RedTransAp *trans = state->inTrans[it];
  173         if ( trans->action != 0 && trans->labelNeeded ) {
  174             /* Remember that we wrote an action so we know to write the
  175              * line directive for going back to the output. */
  176             anyWritten = true;
  177 
  178             /* Write the label for the transition so it can be jumped to. */
  179             out << "tr" << trans->id << ":\n";
  180 
  181             /* If the action contains a next, then we must preload the current
  182              * state since the action may or may not set it. */
  183             if ( trans->action->anyNextStmt() )
  184                 out << "    " << vCS() << " = " << trans->targ->id << ";\n";
  185 
  186             /* Write each action in the list. */
  187             for ( GenActionTable::Iter item = trans->action->key; item.lte(); item++ ) {
  188                 ACTION( out, item->value, trans->targ->id, false, 
  189                         trans->action->anyNextStmt() );
  190             }
  191 
  192             /* If the action contains a next then we need to reload, otherwise
  193              * jump directly to the target state. */
  194             if ( trans->action->anyNextStmt() )
  195                 out << "\tgoto _again;\n";
  196             else
  197                 out << "\tgoto st" << trans->targ->id << ";\n";
  198         }
  199     }
  200 
  201     return anyWritten;
  202 }
  203 
  204 /* Called from GotoCodeGen::STATE_GOTOS just before writing the gotos for each
  205  * state. */
  206 void IpGotoCodeGen::GOTO_HEADER( RedStateAp *state )
  207 {
  208     bool anyWritten = IN_TRANS_ACTIONS( state );
  209 
  210     if ( state->labelNeeded ) 
  211         out << "st" << state->id << ":\n";
  212 
  213     if ( state->toStateAction != 0 ) {
  214         /* Remember that we wrote an action. Write every action in the list. */
  215         anyWritten = true;
  216         for ( GenActionTable::Iter item = state->toStateAction->key; item.lte(); item++ ) {
  217             ACTION( out, item->value, state->id, false, 
  218                     state->toStateAction->anyNextStmt() );
  219         }
  220     }
  221 
  222     /* Advance and test buffer pos. */
  223     if ( state->labelNeeded ) {
  224         if ( !noEnd ) {
  225             out <<
  226                 "   if ( ++" << P() << " == " << PE() << " )\n"
  227                 "       goto _test_eof" << state->id << ";\n";
  228         }
  229         else {
  230             out << 
  231                 "   " << P() << " += 1;\n";
  232         }
  233     }
  234 
  235     /* Give the state a switch case. */
  236     out << "case " << state->id << ":\n";
  237 
  238     if ( state->fromStateAction != 0 ) {
  239         /* Remember that we wrote an action. Write every action in the list. */
  240         anyWritten = true;
  241         for ( GenActionTable::Iter item = state->fromStateAction->key; item.lte(); item++ ) {
  242             ACTION( out, item->value, state->id, false,
  243                     state->fromStateAction->anyNextStmt() );
  244         }
  245     }
  246 
  247     if ( anyWritten )
  248         genLineDirective( out );
  249 
  250     /* Record the prev state if necessary. */
  251     if ( state->anyRegCurStateRef() )
  252         out << "    _ps = " << state->id << ";\n";
  253 }
  254 
  255 void IpGotoCodeGen::STATE_GOTO_ERROR()
  256 {
  257     /* In the error state we need to emit some stuff that usually goes into
  258      * the header. */
  259     RedStateAp *state = redFsm->errState;
  260     bool anyWritten = IN_TRANS_ACTIONS( state );
  261 
  262     /* No case label needed since we don't switch on the error state. */
  263     if ( anyWritten )
  264         genLineDirective( out );
  265 
  266     if ( state->labelNeeded ) 
  267         out << "st" << state->id << ":\n";
  268 
  269     /* Break out here. */
  270     outLabelUsed = true;
  271     out << vCS() << " = " << state->id << ";\n";
  272     out << "    goto _out;\n";
  273 }
  274 
  275 
  276 /* Emit the goto to take for a given transition. */
  277 std::ostream &IpGotoCodeGen::TRANS_GOTO( RedTransAp *trans, int level )
  278 {
  279     if ( trans->action != 0 ) {
  280         /* Go to the transition which will go to the state. */
  281         out << TABS(level) << "goto tr" << trans->id << ";";
  282     }
  283     else {
  284         /* Go directly to the target state. */
  285         out << TABS(level) << "goto st" << trans->targ->id << ";";
  286     }
  287     return out;
  288 }
  289 
  290 std::ostream &IpGotoCodeGen::EXIT_STATES()
  291 {
  292     for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
  293         if ( st->outNeeded ) {
  294             testEofUsed = true;
  295             out << "    _test_eof" << st->id << ": " << vCS() << " = " << 
  296                     st->id << "; goto _test_eof; \n";
  297         }
  298     }
  299     return out;
  300 }
  301 
  302 std::ostream &IpGotoCodeGen::AGAIN_CASES()
  303 {
  304     for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
  305         out << 
  306             "       case " << st->id << ": goto st" << st->id << ";\n";
  307     }
  308     return out;
  309 }
  310 
  311 std::ostream &IpGotoCodeGen::FINISH_CASES()
  312 {
  313     bool anyWritten = false;
  314 
  315     for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
  316         if ( st->eofAction != 0 ) {
  317             if ( st->eofAction->eofRefs == 0 )
  318                 st->eofAction->eofRefs = new IntSet;
  319             st->eofAction->eofRefs->insert( st->id );
  320         }
  321     }
  322 
  323     for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
  324         if ( st->eofTrans != 0 )
  325             out << "    case " << st->id << ": goto tr" << st->eofTrans->id << ";\n";
  326     }
  327 
  328     for ( GenActionTableMap::Iter act = redFsm->actionMap; act.lte(); act++ ) {
  329         if ( act->eofRefs != 0 ) {
  330             for ( IntSet::Iter pst = *act->eofRefs; pst.lte(); pst++ )
  331                 out << "    case " << *pst << ": \n";
  332 
  333             /* Remember that we wrote a trans so we know to write the
  334              * line directive for going back to the output. */
  335             anyWritten = true;
  336 
  337             /* Write each action in the eof action list. */
  338             for ( GenActionTable::Iter item = act->key; item.lte(); item++ )
  339                 ACTION( out, item->value, STATE_ERR_STATE, true, false );
  340             out << "\tbreak;\n";
  341         }
  342     }
  343 
  344     if ( anyWritten )
  345         genLineDirective( out );
  346     return out;
  347 }
  348 
  349 void IpGotoCodeGen::setLabelsNeeded( GenInlineList *inlineList )
  350 {
  351     for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) {
  352         switch ( item->type ) {
  353         case GenInlineItem::Goto: case GenInlineItem::Call: {
  354             /* Mark the target as needing a label. */
  355             item->targState->labelNeeded = true;
  356             break;
  357         }
  358         default: break;
  359         }
  360 
  361         if ( item->children != 0 )
  362             setLabelsNeeded( item->children );
  363     }
  364 }
  365 
  366 /* Set up labelNeeded flag for each state. */
  367 void IpGotoCodeGen::setLabelsNeeded()
  368 {
  369     /* If we use the _again label, then we the _again switch, which uses all
  370      * labels. */
  371     if ( useAgainLabel() ) {
  372         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
  373             st->labelNeeded = true;
  374     }
  375     else {
  376         /* Do not use all labels by default, init all labelNeeded vars to false. */
  377         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
  378             st->labelNeeded = false;
  379 
  380         /* Walk all transitions and set only those that have targs. */
  381         for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) {
  382             /* If there is no action with a next statement, then the label will be
  383              * needed. */
  384             if ( trans->action == 0 || !trans->action->anyNextStmt() )
  385                 trans->targ->labelNeeded = true;
  386 
  387             /* Need labels for states that have goto or calls in action code
  388              * invoked on characters (ie, not from out action code). */
  389             if ( trans->action != 0 ) {
  390                 /* Loop the actions. */
  391                 for ( GenActionTable::Iter act = trans->action->key; act.lte(); act++ ) {
  392                     /* Get the action and walk it's tree. */
  393                     setLabelsNeeded( act->value->inlineList );
  394                 }
  395             }
  396         }
  397 
  398         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
  399             if ( st->eofAction != 0 ) {
  400                 for ( GenActionTable::Iter item = st->eofAction->key; item.lte(); item++ )
  401                     setLabelsNeeded( item->value->inlineList );
  402             }
  403         }
  404     }
  405 
  406     if ( !noEnd ) {
  407         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
  408             if ( st != redFsm->errState )
  409                 st->outNeeded = st->labelNeeded;
  410         }
  411     }
  412 }
  413 
  414 void IpGotoCodeGen::writeData()
  415 {
  416     STATE_IDS();
  417 }
  418 
  419 void IpGotoCodeGen::writeExec()
  420 {
  421     /* Must set labels immediately before writing because we may depend on the
  422      * noend write option. */
  423     setLabelsNeeded();
  424     testEofUsed = false;
  425     outLabelUsed = false;
  426 
  427     out << "    {\n";
  428 
  429     if ( redFsm->anyRegCurStateRef() )
  430         out << "    int _ps = 0;\n";
  431 
  432     if ( redFsm->anyConditions() )
  433         out << "    " << WIDE_ALPH_TYPE() << " _widec;\n";
  434 
  435     if ( !noEnd ) {
  436         testEofUsed = true;
  437         out << 
  438             "   if ( " << P() << " == " << PE() << " )\n"
  439             "       goto _test_eof;\n";
  440     }
  441 
  442     if ( useAgainLabel() ) {
  443         out << 
  444             "   goto _resume;\n"
  445             "\n"
  446             "_again:\n"
  447             "   switch ( " << vCS() << " ) {\n";
  448             AGAIN_CASES() <<
  449             "   default: break;\n"
  450             "   }\n"
  451             "\n";
  452 
  453         if ( !noEnd ) {
  454             testEofUsed = true;
  455             out << 
  456                 "   if ( ++" << P() << " == " << PE() << " )\n"
  457                 "       goto _test_eof;\n";
  458         }
  459         else {
  460             out << 
  461                 "   " << P() << " += 1;\n";
  462         }
  463 
  464         out << "_resume:\n";
  465     }
  466 
  467     out << 
  468         "   switch ( " << vCS() << " )\n    {\n";
  469         STATE_GOTOS();
  470         SWITCH_DEFAULT() <<
  471         "   }\n";
  472         EXIT_STATES() << 
  473         "\n";
  474 
  475     if ( testEofUsed ) 
  476         out << "    _test_eof: {}\n";
  477 
  478     if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
  479         out <<
  480             "   if ( " << P() << " == " << vEOF() << " )\n"
  481             "   {\n"
  482             "   switch ( " << vCS() << " ) {\n";
  483             FINISH_CASES();
  484             SWITCH_DEFAULT() <<
  485             "   }\n"
  486             "   }\n"
  487             "\n";
  488     }
  489 
  490     if ( outLabelUsed ) 
  491         out << "    _out: {}\n";
  492 
  493     out <<
  494         "   }\n";
  495 }