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