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