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