"Fossies" - the Fresh Open Source Software Archive

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