"Fossies" - the Fresh Open Source Software Archive

Member "ragel-6.10/ragel/rubycodegen.cpp" (24 Mar 2017, 18410 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 "rubycodegen.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  *  2007 Victor Hugo Borja <vic@rubyforge.org>
    3  *  Copyright 2001-2007 Adrian Thurston <thurston@complang.org>
    4  */
    5 
    6 /*  This file is part of Ragel.
    7  *
    8  *  Ragel is free software; you can redistribute it and/or modify
    9  *  it under the terms of the GNU General Public License as published by
   10  *  the Free Software Foundation; either version 2 of the License, or
   11  *  (at your option) any later version.
   12  * 
   13  *  Ragel is distributed in the hope that it will be useful,
   14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16  *  GNU General Public License for more details.
   17  * 
   18  *  You should have received a copy of the GNU General Public License
   19  *  along with Ragel; if not, write to the Free Software
   20  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
   21  */
   22 
   23 #include <iomanip>
   24 #include <sstream>
   25 #include "redfsm.h"
   26 #include "gendata.h"
   27 #include "ragel.h"
   28 #include "rubycodegen.h"
   29 #include "pcheck.h"
   30 #include "vector.h"
   31 #include "version.h"
   32 #include "common.h"
   33 
   34 #include "ragel.h"
   35 #include "rubytable.h"
   36 #include "rubyftable.h"
   37 #include "rubyflat.h"
   38 #include "rubyfflat.h"
   39 #include "rbxgoto.h"
   40 
   41 using std::ostream;
   42 using std::ostringstream;
   43 using std::string;
   44 using std::cerr;
   45 using std::endl;
   46 using std::istream;
   47 using std::ifstream;
   48 using std::ostream;
   49 using std::ios;
   50 using std::cin;
   51 using std::cout;
   52 using std::cerr;
   53 using std::endl;
   54 
   55 /* Target ruby impl */
   56 
   57 /* Target language and output style. */
   58 extern CodeStyle codeStyle;
   59 
   60 extern int numSplitPartitions;
   61 extern bool noLineDirectives;
   62 
   63 /*
   64  * Callbacks invoked by the XML data parser.
   65  */
   66 
   67 
   68 void rubyLineDirective( ostream &out, const char *fileName, int line )
   69 {
   70     if ( noLineDirectives )
   71         return;
   72 
   73     /* Write a comment containing line info. */
   74     out << "# line " << line  << " \"";
   75     for ( const char *pc = fileName; *pc != 0; pc++ ) {
   76         if ( *pc == '\\' )
   77             out << "\\\\";
   78         else
   79             out << *pc;
   80     }
   81     out << "\"\n";
   82 }
   83 
   84 void RubyCodeGen::genLineDirective( ostream &out )
   85 {
   86     std::streambuf *sbuf = out.rdbuf();
   87     output_filter *filter = static_cast<output_filter*>(sbuf);
   88     rubyLineDirective( out, filter->fileName, filter->line + 1 );
   89 }
   90 
   91 string RubyCodeGen::DATA_PREFIX()
   92 {
   93     if ( !noPrefix )
   94         return FSM_NAME() + "_";
   95     return "";
   96 }
   97 
   98 std::ostream &RubyCodeGen::STATIC_VAR( string type, string name )
   99 {
  100     out << 
  101         "class << self\n"
  102         "   attr_accessor :" << name << "\n"
  103         "end\n"
  104         "self." << name;
  105     return out;
  106 }
  107 
  108 
  109 std::ostream &RubyCodeGen::OPEN_ARRAY( string type, string name )
  110 {
  111     out << 
  112         "class << self\n"
  113         "   attr_accessor :" << name << "\n"
  114         "   private :" << name << ", :" << name << "=\n"
  115         "end\n"
  116         "self." << name << " = [\n";
  117     return out;
  118 }
  119 
  120 std::ostream &RubyCodeGen::CLOSE_ARRAY()
  121 {
  122     out << "]\n";
  123     return out;
  124 }
  125 
  126 
  127 string RubyCodeGen::ARR_OFF( string ptr, string offset )
  128 {
  129     return ptr + "[" + offset + "]";
  130 }
  131 
  132 string RubyCodeGen::NULL_ITEM()
  133 {
  134     return "nil";
  135 }
  136 
  137 
  138 string RubyCodeGen::P()
  139 { 
  140     ostringstream ret;
  141     if ( pExpr == 0 )
  142         ret << "p";
  143     else {
  144         //ret << "(";
  145         INLINE_LIST( ret, pExpr, 0, false );
  146         //ret << ")";
  147     }
  148     return ret.str();
  149 }
  150 
  151 string RubyCodeGen::PE()
  152 {
  153     ostringstream ret;
  154     if ( peExpr == 0 )
  155         ret << "pe";
  156     else {
  157         //ret << "(";
  158         INLINE_LIST( ret, peExpr, 0, false );
  159         //ret << ")";
  160     }
  161     return ret.str();
  162 }
  163 
  164 string RubyCodeGen::vEOF()
  165 {
  166     ostringstream ret;
  167     if ( eofExpr == 0 )
  168         ret << "eof";
  169     else {
  170         //ret << "(";
  171         INLINE_LIST( ret, eofExpr, 0, false );
  172         //ret << ")";
  173     }
  174     return ret.str();
  175 }
  176 
  177 string RubyCodeGen::vCS()
  178 {
  179     ostringstream ret;
  180     if ( csExpr == 0 )
  181         ret << ACCESS() << "cs";
  182     else {
  183         //ret << "(";
  184         INLINE_LIST( ret, csExpr, 0, false );
  185         //ret << ")";
  186     }
  187     return ret.str();
  188 }
  189 
  190 string RubyCodeGen::TOP()
  191 {
  192     ostringstream ret;
  193     if ( topExpr == 0 )
  194         ret << ACCESS() + "top";
  195     else {
  196         //ret << "(";
  197         INLINE_LIST( ret, topExpr, 0, false );
  198         //ret << ")";
  199     }
  200     return ret.str();
  201 }
  202 
  203 string RubyCodeGen::STACK()
  204 {
  205     ostringstream ret;
  206     if ( stackExpr == 0 )
  207         ret << ACCESS() + "stack";
  208     else {
  209         //ret << "(";
  210         INLINE_LIST( ret, stackExpr, 0, false );
  211         //ret << ")";
  212     }
  213     return ret.str();
  214 }
  215 
  216 string RubyCodeGen::ACT()
  217 {
  218     ostringstream ret;
  219     if ( actExpr == 0 )
  220         ret << ACCESS() + "act";
  221     else {
  222         //ret << "(";
  223         INLINE_LIST( ret, actExpr, 0, false );
  224         //ret << ")";
  225     }
  226     return ret.str();
  227 }
  228 
  229 string RubyCodeGen::TOKSTART()
  230 {
  231     ostringstream ret;
  232     if ( tokstartExpr == 0 )
  233         ret << ACCESS() + "ts";
  234     else {
  235         //ret << "(";
  236         INLINE_LIST( ret, tokstartExpr, 0, false );
  237         //ret << ")";
  238     }
  239     return ret.str();
  240 }
  241 
  242 string RubyCodeGen::TOKEND()
  243 {
  244     ostringstream ret;
  245     if ( tokendExpr == 0 )
  246         ret << ACCESS() + "te";
  247     else {
  248         //ret << "(";
  249         INLINE_LIST( ret, tokendExpr, 0, false );
  250         //ret << ")";
  251     }
  252     return ret.str();
  253 }
  254 
  255 string RubyCodeGen::DATA()
  256 {
  257     ostringstream ret;
  258     if ( dataExpr == 0 )
  259         ret << ACCESS() + "data";
  260     else {
  261         //ret << "(";
  262         INLINE_LIST( ret, dataExpr, 0, false );
  263         //ret << ")";
  264     }
  265     return ret.str();
  266 }
  267 
  268 /* Write out the fsm name. */
  269 string RubyCodeGen::FSM_NAME()
  270 {
  271     return fsmName;
  272 }
  273 
  274 
  275 void RubyCodeGen::ACTION( ostream &ret, GenAction *action, int targState, bool inFinish )
  276 {
  277     /* Write the preprocessor line info for going into the source file. */
  278     rubyLineDirective( ret, action->loc.fileName, action->loc.line );
  279 
  280     /* Write the block and close it off. */
  281     ret << "        begin\n";
  282     INLINE_LIST( ret, action->inlineList, targState, inFinish );
  283     ret << "        end\n";
  284 }
  285 
  286 
  287 
  288 string RubyCodeGen::GET_WIDE_KEY()
  289 {
  290     if ( redFsm->anyConditions() ) 
  291         return "_widec";
  292     else
  293         return GET_KEY();
  294 }
  295 
  296 string RubyCodeGen::GET_WIDE_KEY( RedStateAp *state )
  297 {
  298     if ( state->stateCondList.length() > 0 )
  299         return "_widec";
  300     else
  301         return GET_KEY();
  302 }
  303 
  304 string RubyCodeGen::GET_KEY()
  305 {
  306     ostringstream ret;
  307     if ( getKeyExpr != 0 ) { 
  308         /* Emit the user supplied method of retrieving the key. */
  309         ret << "(";
  310         INLINE_LIST( ret, getKeyExpr, 0, false );
  311         ret << ")";
  312     }
  313     else {
  314         /* Expression for retrieving the key, use dereference and read ordinal,
  315          * for compatibility with Ruby 1.9. */
  316         ret << DATA() << "[" << P() << "].ord";
  317     }
  318     return ret.str();
  319 }
  320 
  321 string RubyCodeGen::KEY( Key key )
  322 {
  323     ostringstream ret;
  324     if ( keyOps->isSigned || !hostLang->explicitUnsigned )
  325         ret << key.getVal();
  326     else
  327         ret << (unsigned long) key.getVal();
  328     return ret.str();
  329 }
  330 
  331 
  332 /* Write out level number of tabs. Makes the nested binary search nice
  333  * looking. */
  334 string RubyCodeGen::TABS( int level )
  335 {
  336     string result;
  337     while ( level-- > 0 )
  338         result += "\t";
  339     return result;
  340 }
  341 
  342 string RubyCodeGen::INT( int i )
  343 {
  344     ostringstream ret;
  345     ret << i;
  346     return ret.str();
  347 }
  348 
  349 void RubyCodeGen::CONDITION( ostream &ret, GenAction *condition )
  350 {
  351     ret << "\n";
  352     rubyLineDirective( ret, condition->loc.fileName, condition->loc.line );
  353     INLINE_LIST( ret, condition->inlineList, 0, false );
  354 }
  355 
  356 /* Emit the alphabet data type. */
  357 string RubyCodeGen::ALPH_TYPE()
  358 {
  359     string ret = keyOps->alphType->data1;
  360     if ( keyOps->alphType->data2 != 0 ) {
  361         ret += " ";
  362         ret += + keyOps->alphType->data2;
  363     }
  364     return ret;
  365 }
  366 
  367 /* Emit the alphabet data type. */
  368 string RubyCodeGen::WIDE_ALPH_TYPE()
  369 {
  370     string ret;
  371     if ( redFsm->maxKey <= keyOps->maxKey )
  372         ret = ALPH_TYPE();
  373     else {
  374         long long maxKeyVal = redFsm->maxKey.getLongLong();
  375         HostType *wideType = keyOps->typeSubsumes( keyOps->isSigned, maxKeyVal );
  376         assert( wideType != 0 );
  377 
  378         ret = wideType->data1;
  379         if ( wideType->data2 != 0 ) {
  380             ret += " ";
  381             ret += wideType->data2;
  382         }
  383     }
  384     return ret;
  385 }
  386 
  387 
  388 string RubyCodeGen::ARRAY_TYPE( unsigned long maxVal )
  389 {
  390     long long maxValLL = (long long) maxVal;
  391     HostType *arrayType = keyOps->typeSubsumes( maxValLL );
  392     assert( arrayType != 0 );
  393 
  394     string ret = arrayType->data1;
  395     if ( arrayType->data2 != 0 ) {
  396         ret += " ";
  397         ret += arrayType->data2;
  398     }
  399     return ret;
  400 }
  401 
  402 /* Write out the array of actions. */
  403 std::ostream &RubyCodeGen::ACTIONS_ARRAY()
  404 {
  405     START_ARRAY_LINE();
  406     int totalActions = 0;
  407     ARRAY_ITEM( INT(0), ++totalActions, false );
  408     for ( GenActionTableMap::Iter act = redFsm->actionMap; act.lte(); act++ ) {
  409         /* Write out the length, which will never be the last character. */
  410         ARRAY_ITEM( INT(act->key.length()), ++totalActions, false );
  411 
  412         for ( GenActionTable::Iter item = act->key; item.lte(); item++ ) {
  413             ARRAY_ITEM( INT(item->value->actionId), ++totalActions, (act.last() && item.last()) );
  414         }
  415     }
  416     END_ARRAY_LINE();
  417     return out;
  418 }
  419 
  420 void RubyCodeGen::STATE_IDS()
  421 {
  422     if ( redFsm->startState != 0 )
  423         STATIC_VAR( "int", START() ) << " = " << START_STATE_ID() << ";\n";
  424 
  425     if ( !noFinal )
  426         STATIC_VAR( "int" , FIRST_FINAL() ) << " = " << FIRST_FINAL_STATE() << ";\n";
  427 
  428     if ( !noError )
  429         STATIC_VAR( "int", ERROR() ) << " = " << ERROR_STATE() << ";\n";
  430 
  431     out << "\n";
  432 
  433     if ( !noEntry && entryPointNames.length() > 0 ) {
  434         for ( EntryNameVect::Iter en = entryPointNames; en.lte(); en++ ) {
  435             STATIC_VAR( "int", DATA_PREFIX() + "en_" + *en ) << 
  436                     " = " << entryPointIds[en.pos()] << ";\n";
  437         }
  438         out << "\n";
  439     }
  440 }
  441 
  442 std::ostream &RubyCodeGen::START_ARRAY_LINE()
  443 {
  444     out << "\t";
  445     return out;
  446 }
  447 
  448 std::ostream &RubyCodeGen::ARRAY_ITEM( string item, int count, bool last )
  449 {
  450     out << item;
  451     if ( !last )
  452     {
  453         out << ", ";
  454         if ( count % IALL == 0 )
  455         {
  456             END_ARRAY_LINE();
  457             START_ARRAY_LINE();
  458         }
  459     }
  460     return out;
  461 }
  462 
  463 std::ostream &RubyCodeGen::END_ARRAY_LINE()
  464 {
  465     out << "\n";
  466     return out;
  467 }
  468 
  469 /* Emit the offset of the start state as a decimal integer. */
  470 string RubyCodeGen::START_STATE_ID()
  471 {
  472     ostringstream ret;
  473     ret << redFsm->startState->id;
  474     return ret.str();
  475 };
  476 
  477 string RubyCodeGen::ERROR_STATE()
  478 {
  479     ostringstream ret;
  480     if ( redFsm->errState != 0 )
  481         ret << redFsm->errState->id;
  482     else
  483         ret << "-1";
  484     return ret.str();
  485 }
  486 
  487 string RubyCodeGen::FIRST_FINAL_STATE()
  488 {
  489     ostringstream ret;
  490     if ( redFsm->firstFinState != 0 )
  491         ret << redFsm->firstFinState->id;
  492     else
  493         ret << redFsm->nextStateId;
  494     return ret.str();
  495 }
  496 
  497 string RubyCodeGen::ACCESS()
  498 {
  499     ostringstream ret;
  500     if ( accessExpr != 0 )
  501         INLINE_LIST( ret, accessExpr, 0, false );
  502     return ret.str();
  503 }
  504 
  505 /* Write out an inline tree structure. Walks the list and possibly calls out
  506  * to virtual functions than handle language specific items in the tree. */
  507 void RubyCodeGen::INLINE_LIST( ostream &ret, GenInlineList *inlineList, 
  508         int targState, bool inFinish )
  509 {
  510     for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) {
  511         switch ( item->type ) {
  512         case GenInlineItem::Text:
  513             ret << item->data;
  514             break;
  515         case GenInlineItem::Goto:
  516             GOTO( ret, item->targState->id, inFinish );
  517             break;
  518         case GenInlineItem::Call:
  519             CALL( ret, item->targState->id, targState, inFinish );
  520             break;
  521         case GenInlineItem::Next:
  522             NEXT( ret, item->targState->id, inFinish );
  523             break;
  524         case GenInlineItem::Ret:
  525             RET( ret, inFinish );
  526             break;
  527         case GenInlineItem::PChar:
  528             ret << P();
  529             break;
  530         case GenInlineItem::Char:
  531             ret << GET_KEY();
  532             break;
  533         case GenInlineItem::Hold:
  534             ret << P() << " = " << P() << " - 1;";
  535             break;
  536         case GenInlineItem::Exec:
  537             EXEC( ret, item, targState, inFinish );
  538             break;
  539         case GenInlineItem::Curs:
  540             ret << "(_ps)";
  541             break;
  542         case GenInlineItem::Targs:
  543             ret << "(" << vCS() << ")";
  544             break;
  545         case GenInlineItem::Entry:
  546             ret << item->targState->id;
  547             break;
  548         case GenInlineItem::GotoExpr:
  549             GOTO_EXPR( ret, item, inFinish );
  550             break;
  551         case GenInlineItem::CallExpr:
  552             CALL_EXPR( ret, item, targState, inFinish );
  553             break;
  554         case GenInlineItem::NextExpr:
  555             NEXT_EXPR( ret, item, inFinish );
  556             break;
  557         case GenInlineItem::LmSwitch:
  558             LM_SWITCH( ret, item, targState, inFinish );
  559             break;
  560         case GenInlineItem::LmSetActId:
  561             SET_ACT( ret, item );
  562             break;
  563         case GenInlineItem::LmSetTokEnd:
  564             SET_TOKEND( ret, item );
  565             break;
  566         case GenInlineItem::LmGetTokEnd:
  567             GET_TOKEND( ret, item );
  568             break;
  569         case GenInlineItem::LmInitTokStart:
  570             INIT_TOKSTART( ret, item );
  571             break;
  572         case GenInlineItem::LmInitAct:
  573             INIT_ACT( ret, item );
  574             break;
  575         case GenInlineItem::LmSetTokStart:
  576             SET_TOKSTART( ret, item );
  577             break;
  578         case GenInlineItem::SubAction:
  579             SUB_ACTION( ret, item, targState, inFinish );
  580             break;
  581         case GenInlineItem::Break:
  582             BREAK( ret, targState );
  583             break;
  584         }
  585     }
  586 }
  587 
  588 
  589 void RubyCodeGen::EXEC( ostream &ret, GenInlineItem *item, int targState, int inFinish )
  590 {
  591     /* The parser gives fexec two children. The double brackets are for D
  592      * code. If the inline list is a single word it will get interpreted as a
  593      * C-style cast by the D compiler. */
  594     ret << " begin " << P() << " = ((";
  595     INLINE_LIST( ret, item->children, targState, inFinish );
  596     ret << "))-1; end\n";
  597 }
  598 
  599 void RubyCodeGen::LM_SWITCH( ostream &ret, GenInlineItem *item, 
  600         int targState, int inFinish )
  601 {
  602     ret << 
  603         "   case " << ACT() << "\n";
  604 
  605     for ( GenInlineList::Iter lma = *item->children; lma.lte(); lma++ ) {
  606         /* Write the case label, the action and the case break. */
  607         if ( lma->lmId < 0 )
  608             ret << "    else\n";
  609         else
  610             ret << "    when " << lma->lmId << " then\n";
  611 
  612 
  613         /* Write the block and close it off. */
  614         ret << "    begin";
  615         INLINE_LIST( ret, lma->children, targState, inFinish );
  616         ret << "end\n";
  617     }
  618 
  619     ret << "end \n\t";
  620 }
  621 
  622 void RubyCodeGen::SET_ACT( ostream &ret, GenInlineItem *item )
  623 {
  624     ret << ACT() << " = " << item->lmId << ";";
  625 }
  626 
  627 void RubyCodeGen::INIT_TOKSTART( ostream &ret, GenInlineItem *item )
  628 {
  629     ret << TOKSTART() << " = " << NULL_ITEM() << ";";
  630 }
  631 
  632 void RubyCodeGen::INIT_ACT( ostream &ret, GenInlineItem *item )
  633 {
  634     ret << ACT() << " = 0\n";
  635 }
  636 
  637 void RubyCodeGen::SET_TOKSTART( ostream &ret, GenInlineItem *item )
  638 {
  639     ret << TOKSTART() << " = " << P() << "\n";
  640 }
  641 
  642 void RubyCodeGen::SET_TOKEND( ostream &ret, GenInlineItem *item )
  643 {
  644     /* The tokend action sets tokend. */
  645     ret << TOKEND() << " = " << P();
  646     if ( item->offset != 0 ) 
  647         out << "+" << item->offset;
  648     out << "\n";
  649 }
  650 
  651 void RubyCodeGen::GET_TOKEND( ostream &ret, GenInlineItem *item )
  652 {
  653     ret << TOKEND();
  654 }
  655 
  656 void RubyCodeGen::SUB_ACTION( ostream &ret, GenInlineItem *item, 
  657         int targState, bool inFinish )
  658 {
  659     if ( item->children->length() > 0 ) {
  660         /* Write the block and close it off. */
  661         ret << " begin ";
  662         INLINE_LIST( ret, item->children, targState, inFinish );
  663         ret << " end\n";
  664     }
  665 }
  666 
  667 int RubyCodeGen::TRANS_ACTION( RedTransAp *trans )
  668 {
  669     /* If there are actions, emit them. Otherwise emit zero. */
  670     int act = 0;
  671     if ( trans->action != 0 )
  672         act = trans->action->location+1;
  673     return act;
  674 }
  675 
  676 ostream &RubyCodeGen::source_warning( const InputLoc &loc )
  677 {
  678     cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": warning: ";
  679     return cerr;
  680 }
  681 
  682 ostream &RubyCodeGen::source_error( const InputLoc &loc )
  683 {
  684     gblErrorCount += 1;
  685     assert( sourceFileName != 0 );
  686     cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": ";
  687     return cerr;
  688 }
  689 
  690 void RubyCodeGen::finishRagelDef()
  691 {
  692     if ( codeStyle == GenGoto || codeStyle == GenFGoto || 
  693             codeStyle == GenIpGoto || codeStyle == GenSplit )
  694     {
  695         /* For directly executable machines there is no required state
  696          * ordering. Choose a depth-first ordering to increase the
  697          * potential for fall-throughs. */
  698         redFsm->depthFirstOrdering();
  699     }
  700     else {
  701         /* The frontend will do this for us, but it may be a good idea to
  702          * force it if the intermediate file is edited. */
  703         redFsm->sortByStateId();
  704     }
  705 
  706     /* Choose default transitions and the single transition. */
  707     redFsm->chooseDefaultSpan();
  708         
  709     /* Maybe do flat expand, otherwise choose single. */
  710     if ( codeStyle == GenFlat || codeStyle == GenFFlat )
  711         redFsm->makeFlat();
  712     else
  713         redFsm->chooseSingle();
  714 
  715     /* If any errors have occured in the input file then don't write anything. */
  716     if ( gblErrorCount > 0 )
  717         return;
  718     
  719     if ( codeStyle == GenSplit )
  720         redFsm->partitionFsm( numSplitPartitions );
  721 
  722     if ( codeStyle == GenIpGoto || codeStyle == GenSplit )
  723         redFsm->setInTrans();
  724 
  725     /* Anlayze Machine will find the final action reference counts, among
  726      * other things. We will use these in reporting the usage
  727      * of fsm directives in action code. */
  728     analyzeMachine();
  729 
  730     /* Determine if we should use indicies. */
  731     calcIndexSize();
  732 }
  733 
  734 
  735 /* Determine if we should use indicies or not. */
  736 void RubyCodeGen::calcIndexSize()
  737 {
  738     int sizeWithInds = 0, sizeWithoutInds = 0;
  739 
  740     /* Calculate cost of using with indicies. */
  741     for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
  742         int totalIndex = st->outSingle.length() + st->outRange.length() + 
  743                 (st->defTrans == 0 ? 0 : 1);
  744         sizeWithInds += arrayTypeSize(redFsm->maxIndex) * totalIndex;
  745     }
  746     sizeWithInds += arrayTypeSize(redFsm->maxState) * redFsm->transSet.length();
  747     if ( redFsm->anyActions() )
  748         sizeWithInds += arrayTypeSize(redFsm->maxActionLoc) * redFsm->transSet.length();
  749 
  750     /* Calculate the cost of not using indicies. */
  751     for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
  752         int totalIndex = st->outSingle.length() + st->outRange.length() + 
  753                 (st->defTrans == 0 ? 0 : 1);
  754         sizeWithoutInds += arrayTypeSize(redFsm->maxState) * totalIndex;
  755         if ( redFsm->anyActions() )
  756             sizeWithoutInds += arrayTypeSize(redFsm->maxActionLoc) * totalIndex;
  757     }
  758 
  759     /* If using indicies reduces the size, use them. */
  760     useIndicies = sizeWithInds < sizeWithoutInds;
  761 }
  762 
  763 unsigned int RubyCodeGen::arrayTypeSize( unsigned long maxVal )
  764 {
  765     long long maxValLL = (long long) maxVal;
  766     HostType *arrayType = keyOps->typeSubsumes( maxValLL );
  767     assert( arrayType != 0 );
  768     return arrayType->size;
  769 }
  770 
  771 
  772 void RubyCodeGen::writeInit()
  773 {
  774     out << "begin\n";
  775     
  776     out << "    " << P() << " ||= 0\n";
  777 
  778     if ( !noEnd ) 
  779         out << "    " << PE() << " ||= " << DATA() << ".length\n";
  780 
  781     if ( !noCS )
  782         out << "    " << vCS() << " = " << START() << "\n";
  783 
  784     /* If there are any calls, then the stack top needs initialization. */
  785     if ( redFsm->anyActionCalls() || redFsm->anyActionRets() )
  786         out << "    " << TOP() << " = 0\n";
  787 
  788     if ( hasLongestMatch ) {
  789         out <<
  790             "   " << TOKSTART() << " = " << NULL_ITEM() << "\n"
  791             "   " << TOKEND() << " = " << NULL_ITEM() << "\n"
  792             "   " << ACT() << " = 0\n";
  793     }
  794 
  795     out << "end\n";
  796 }
  797 
  798 void RubyCodeGen::writeExports()
  799 {
  800     if ( exportList.length() > 0 ) {
  801         for ( ExportList::Iter ex = exportList; ex.lte(); ex++ ) {
  802             STATIC_VAR( ALPH_TYPE(), DATA_PREFIX() + "ex_" + ex->name ) 
  803                     << " = " << KEY(ex->key) << "\n";
  804         }
  805         out << "\n";
  806     }
  807 }
  808 
  809 void RubyCodeGen::writeStart()
  810 {
  811     out << START_STATE_ID();
  812 }
  813 
  814 void RubyCodeGen::writeFirstFinal()
  815 {
  816     out << FIRST_FINAL_STATE();
  817 }
  818 
  819 void RubyCodeGen::writeError()
  820 {
  821     out << ERROR_STATE();
  822 }
  823 
  824 
  825 /*
  826  * Local Variables:
  827  * mode: c++
  828  * indent-tabs-mode: 1
  829  * c-file-style: "bsd"
  830  * End:
  831  */