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