1d07ad9c2ee02e8474e9744512bcd1b2f921d0b2
[external/ragel.git] / rlcodegen / fsmcodegen.cpp
1 /*
2  *  Copyright 2001-2006 Adrian Thurston <thurston@cs.queensu.ca>
3  *            2004 Eric 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 "rlcodegen.h"
25 #include "fsmcodegen.h"
26 #include "redfsm.h"
27 #include "gendata.h"
28 #include <sstream>
29 #include <string>
30 #include <assert.h>
31
32 using std::ostream;
33 using std::ostringstream;
34 using std::string;
35 using std::cerr;
36 using std::endl;
37
38
39 /* Determine if a string is only whitespace. Code blocks that are only
40  * whitespace need not be output. */
41 bool onlyWhitespace( char *str )
42 {
43         while ( *str != 0 ) {
44                 if ( *str != ' ' && *str != '\t' && *str != '\n' &&
45                                 *str != '\v' && *str != '\f' && *str != '\r' )
46                         return false;
47                 str += 1;
48         }
49         return true;
50 }
51
52 /* Init code gen with in parameters. */
53 FsmCodeGen::FsmCodeGen( ostream &out )
54 :
55         fsmName(0), 
56         cgd(0), 
57         redFsm(0), 
58         out(out),
59         bAnyToStateActions(false),
60         bAnyFromStateActions(false),
61         bAnyRegActions(false),
62         bAnyEofActions(false),
63         bAnyActionGotos(false),
64         bAnyActionCalls(false),
65         bAnyActionRets(false),
66         bAnyRegActionRets(false),
67         bAnyRegActionByValControl(false),
68         bAnyRegNextStmt(false),
69         bAnyRegCurStateRef(false),
70         bAnyRegBreak(false),
71         bAnyLmSwitchError(false),
72         bAnyConditions(false)
73 {
74 }
75
76 /* Does the machine have any actions. */
77 bool FsmCodeGen::anyActions()
78 {
79         return redFsm->actionMap.length() > 0;
80 }
81
82 void FsmCodeGen::findFinalActionRefs()
83 {
84         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
85                 /* Rerence count out of single transitions. */
86                 for ( RedTransList::Iter rtel = st->outSingle; rtel.lte(); rtel++ ) {
87                         if ( rtel->value->action != 0 ) {
88                                 rtel->value->action->numTransRefs += 1;
89                                 for ( ActionTable::Iter item = rtel->value->action->key; item.lte(); item++ )
90                                         item->value->numTransRefs += 1;
91                         }
92                 }
93
94                 /* Reference count out of range transitions. */
95                 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
96                         if ( rtel->value->action != 0 ) {
97                                 rtel->value->action->numTransRefs += 1;
98                                 for ( ActionTable::Iter item = rtel->value->action->key; item.lte(); item++ )
99                                         item->value->numTransRefs += 1;
100                         }
101                 }
102
103                 /* Reference count default transition. */
104                 if ( st->defTrans != 0 && st->defTrans->action != 0 ) {
105                         st->defTrans->action->numTransRefs += 1;
106                         for ( ActionTable::Iter item = st->defTrans->action->key; item.lte(); item++ )
107                                 item->value->numTransRefs += 1;
108                 }
109
110                 /* Reference count to state actions. */
111                 if ( st->toStateAction != 0 ) {
112                         st->toStateAction->numToStateRefs += 1;
113                         for ( ActionTable::Iter item = st->toStateAction->key; item.lte(); item++ )
114                                 item->value->numToStateRefs += 1;
115                 }
116
117                 /* Reference count from state actions. */
118                 if ( st->fromStateAction != 0 ) {
119                         st->fromStateAction->numFromStateRefs += 1;
120                         for ( ActionTable::Iter item = st->fromStateAction->key; item.lte(); item++ )
121                                 item->value->numFromStateRefs += 1;
122                 }
123
124                 /* Reference count EOF actions. */
125                 if ( st->eofAction != 0 ) {
126                         st->eofAction->numEofRefs += 1;
127                         for ( ActionTable::Iter item = st->eofAction->key; item.lte(); item++ )
128                                 item->value->numEofRefs += 1;
129                 }
130         }
131 }
132
133 /* Assign ids to referenced actions. */
134 void FsmCodeGen::assignActionIds()
135 {
136         int nextActionId = 0;
137         for ( ActionList::Iter act = cgd->actionList; act.lte(); act++ ) {
138                 /* Only ever interested in referenced actions. */
139                 if ( act->numRefs() > 0 )
140                         act->actionId = nextActionId++;
141         }
142 }
143
144 void FsmCodeGen::setValueLimits()
145 {
146         maxSingleLen = 0;
147         maxRangeLen = 0;
148         maxKeyOffset = 0;
149         maxIndexOffset = 0;
150         maxActListId = 0;
151         maxActionLoc = 0;
152         maxActArrItem = 0;
153         maxSpan = 0;
154         maxCondSpan = 0;
155         maxFlatIndexOffset = 0;
156         maxCondOffset = 0;
157         maxCondLen = 0;
158         maxCondSpaceId = 0;
159         maxCondIndexOffset = 0;
160
161         /* In both of these cases the 0 index is reserved for no value, so the max
162          * is one more than it would be if they started at 0. */
163         maxIndex = redFsm->transSet.length();
164         maxCond = cgd->condSpaceList.length(); 
165
166         /* The nextStateId - 1 is the last state id assigned. */
167         maxState = redFsm->nextStateId - 1;
168
169         for ( CondSpaceList::Iter csi = cgd->condSpaceList; csi.lte(); csi++ ) {
170                 if ( csi->condSpaceId > maxCondSpaceId )
171                         maxCondSpaceId = csi->condSpaceId;
172         }
173
174         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
175                 /* Maximum cond length. */
176                 if ( st->stateCondList.length() > maxCondLen )
177                         maxCondLen = st->stateCondList.length();
178
179                 /* Maximum single length. */
180                 if ( st->outSingle.length() > maxSingleLen )
181                         maxSingleLen = st->outSingle.length();
182
183                 /* Maximum range length. */
184                 if ( st->outRange.length() > maxRangeLen )
185                         maxRangeLen = st->outRange.length();
186
187                 /* The key offset index offset for the state after last is not used, skip it.. */
188                 if ( ! st.last() ) {
189                         maxCondOffset += st->stateCondList.length();
190                         maxKeyOffset += st->outSingle.length() + st->outRange.length()*2;
191                         maxIndexOffset += st->outSingle.length() + st->outRange.length() + 1;
192                 }
193
194                 /* Max cond span. */
195                 if ( st->condList != 0 ) {
196                         unsigned long long span = keyOps->span( st->condLowKey, st->condHighKey );
197                         if ( span > maxCondSpan )
198                                 maxCondSpan = span;
199                 }
200
201                 /* Max key span. */
202                 if ( st->transList != 0 ) {
203                         unsigned long long span = keyOps->span( st->lowKey, st->highKey );
204                         if ( span > maxSpan )
205                                 maxSpan = span;
206                 }
207
208                 /* Max cond index offset. */
209                 if ( ! st.last() ) {
210                         if ( st->condList != 0 )
211                                 maxCondIndexOffset += keyOps->span( st->condLowKey, st->condHighKey );
212                 }
213
214                 /* Max flat index offset. */
215                 if ( ! st.last() ) {
216                         if ( st->transList != 0 )
217                                 maxFlatIndexOffset += keyOps->span( st->lowKey, st->highKey );
218                         maxFlatIndexOffset += 1;
219                 }
220         }
221
222         for ( ActionTableMap::Iter at = redFsm->actionMap; at.lte(); at++ ) {
223                 /* Maximum id of action lists. */
224                 if ( at->actListId+1 > maxActListId )
225                         maxActListId = at->actListId+1;
226
227                 /* Maximum location of items in action array. */
228                 if ( at->location+1 > maxActionLoc )
229                         maxActionLoc = at->location+1;
230
231                 /* Maximum values going into the action array. */
232                 if ( at->key.length() > maxActArrItem )
233                         maxActArrItem = at->key.length();
234                 for ( ActionTable::Iter item = at->key; item.lte(); item++ ) {
235                         if ( item->value->actionId > maxActArrItem )
236                                 maxActArrItem = item->value->actionId;
237                 }
238         }
239 }
240
241 void FsmCodeGen::analyzeAction( Action *act, InlineList *inlineList )
242 {
243         for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
244                 /* Only consider actions that are referenced. */
245                 if ( act->numRefs() > 0 ) {
246                         if ( item->type == InlineItem::Goto || item->type == InlineItem::GotoExpr )
247                                 bAnyActionGotos = true;
248                         else if ( item->type == InlineItem::Call || item->type == InlineItem::CallExpr )
249                                 bAnyActionCalls = true;
250                         else if ( item->type == InlineItem::Ret )
251                                 bAnyActionRets = true;
252                 }
253
254                 /* Check for various things in regular actions. */
255                 if ( act->numTransRefs > 0 || act->numToStateRefs > 0 || act->numFromStateRefs > 0 ) {
256                         /* Any returns in regular actions? */
257                         if ( item->type == InlineItem::Ret )
258                                 bAnyRegActionRets = true;
259
260                         /* Any next statements in the regular actions? */
261                         if ( item->type == InlineItem::Next || item->type == InlineItem::NextExpr )
262                                 bAnyRegNextStmt = true;
263
264                         /* Any by value control in regular actions? */
265                         if ( item->type == InlineItem::CallExpr || item->type == InlineItem::GotoExpr )
266                                 bAnyRegActionByValControl = true;
267
268                         /* Any references to the current state in regular actions? */
269                         if ( item->type == InlineItem::Curs )
270                                 bAnyRegCurStateRef = true;
271
272                         if ( item->type == InlineItem::Break )
273                                 bAnyRegBreak = true;
274
275                         if ( item->type == InlineItem::LmSwitch && item->handlesError )
276                                 bAnyLmSwitchError = true;
277                 }
278
279                 if ( item->children != 0 )
280                         analyzeAction( act, item->children );
281         }
282 }
283
284 void FsmCodeGen::analyzeActionList( RedAction *redAct, InlineList *inlineList )
285 {
286         for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
287                 /* Any next statements in the action table? */
288                 if ( item->type == InlineItem::Next || item->type == InlineItem::NextExpr )
289                         redAct->bAnyNextStmt = true;
290
291                 /* Any references to the current state. */
292                 if ( item->type == InlineItem::Curs )
293                         redAct->bAnyCurStateRef = true;
294
295                 if ( item->type == InlineItem::Break )
296                         redAct->bAnyBreakStmt = true;
297
298                 if ( item->children != 0 )
299                         analyzeActionList( redAct, item->children );
300         }
301 }
302
303 /* Gather various info on the machine. */
304 void FsmCodeGen::analyzeMachine()
305 {
306         /* Find the true count of action references.  */
307         findFinalActionRefs();
308
309         /* Check if there are any calls in action code. */
310         for ( ActionList::Iter act = cgd->actionList; act.lte(); act++ ) {
311                 /* Record the occurrence of various kinds of actions. */
312                 if ( act->numToStateRefs > 0 )
313                         bAnyToStateActions = true;
314                 if ( act->numFromStateRefs > 0 )
315                         bAnyFromStateActions = true;
316                 if ( act->numEofRefs > 0 )
317                         bAnyEofActions = true;
318                 if ( act->numTransRefs > 0 )
319                         bAnyRegActions = true;
320
321                 /* Recurse through the action's parse tree looking for various things. */
322                 analyzeAction( act, act->inlineList );
323         }
324
325         /* Analyze reduced action lists. */
326         for ( ActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
327                 for ( ActionTable::Iter act = redAct->key; act.lte(); act++ )
328                         analyzeActionList( redAct, act->value->inlineList );
329         }
330
331         /* Find states that have transitions with actions that have next
332          * statements. */
333         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
334                 /* Check any actions out of outSinge. */
335                 for ( RedTransList::Iter rtel = st->outSingle; rtel.lte(); rtel++ ) {
336                         if ( rtel->value->action != 0 && rtel->value->action->anyCurStateRef() )
337                                 st->bAnyRegCurStateRef = true;
338                 }
339
340                 /* Check any actions out of outRange. */
341                 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
342                         if ( rtel->value->action != 0 && rtel->value->action->anyCurStateRef() )
343                                 st->bAnyRegCurStateRef = true;
344                 }
345
346                 /* Check any action out of default. */
347                 if ( st->defTrans != 0 && st->defTrans->action != 0 && 
348                                 st->defTrans->action->anyCurStateRef() )
349                         st->bAnyRegCurStateRef = true;
350                 
351                 if ( st->stateCondList.length() > 0 )
352                         bAnyConditions = true;
353         }
354
355         /* Assign ids to actions that are referenced. */
356         assignActionIds();
357
358         /* Set the maximums of various values used for deciding types. */
359         setValueLimits();
360
361         /* Determine if we should use indicies. */
362         calcIndexSize();
363 }
364
365 unsigned int FsmCodeGen::arrayTypeSize( unsigned long maxVal )
366 {
367         long long maxValLL = (long long) maxVal;
368         HostType *arrayType = keyOps->typeSubsumes( maxValLL );
369         assert( arrayType != 0 );
370         return arrayType->size;
371 }
372
373 string FsmCodeGen::ARRAY_TYPE( unsigned long maxVal )
374 {
375         long long maxValLL = (long long) maxVal;
376         HostType *arrayType = keyOps->typeSubsumes( maxValLL );
377         assert( arrayType != 0 );
378
379         string ret = arrayType->data1;
380         if ( arrayType->data2 != 0 ) {
381                 ret += " ";
382                 ret += arrayType->data2;
383         }
384         return ret;
385 }
386
387
388 /* Write out the fsm name. */
389 string FsmCodeGen::FSM_NAME()
390 {
391         return fsmName;
392 }
393
394 /* Emit the offset of the start state as a decimal integer. */
395 string FsmCodeGen::START_STATE_ID()
396 {
397         ostringstream ret;
398         ret << redFsm->startState->id;
399         return ret.str();
400 };
401
402 /* Write out the array of actions. */
403 std::ostream &FsmCodeGen::ACTIONS_ARRAY()
404 {
405         out << "\t0, ";
406         int totalActions = 1;
407         for ( ActionTableMap::Iter act = redFsm->actionMap; act.lte(); act++ ) {
408                 /* Write out the length, which will never be the last character. */
409                 out << act->key.length() << ", ";
410                 /* Put in a line break every 8 */
411                 if ( totalActions++ % 8 == 7 )
412                         out << "\n\t";
413
414                 for ( ActionTable::Iter item = act->key; item.lte(); item++ ) {
415                         out << item->value->actionId;
416                         if ( ! (act.last() && item.last()) )
417                                 out << ", ";
418
419                         /* Put in a line break every 8 */
420                         if ( totalActions++ % 8 == 7 )
421                                 out << "\n\t";
422                 }
423         }
424         out << "\n";
425         return out;
426 }
427
428
429 string FsmCodeGen::CS()
430 {
431         ostringstream ret;
432         if ( cgd->curStateExpr != 0 ) { 
433                 /* Emit the user supplied method of retrieving the key. */
434                 ret << "(";
435                 INLINE_LIST( ret, cgd->curStateExpr, 0, false );
436                 ret << ")";
437         }
438         else {
439                 /* Expression for retrieving the key, use simple dereference. */
440                 ret << ACCESS() << "cs";
441         }
442         return ret.str();
443 }
444
445 string FsmCodeGen::ACCESS()
446 {
447         ostringstream ret;
448         if ( cgd->accessExpr != 0 )
449                 INLINE_LIST( ret, cgd->accessExpr, 0, false );
450         return ret.str();
451 }
452
453 string FsmCodeGen::GET_WIDE_KEY()
454 {
455         if ( anyConditions() ) 
456                 return "_widec";
457         else
458                 return GET_KEY();
459 }
460
461 string FsmCodeGen::GET_WIDE_KEY( RedStateAp *state )
462 {
463         if ( state->stateCondList.length() > 0 )
464                 return "_widec";
465         else
466                 return GET_KEY();
467 }
468
469 string FsmCodeGen::GET_KEY()
470 {
471         ostringstream ret;
472         if ( cgd->getKeyExpr != 0 ) { 
473                 /* Emit the user supplied method of retrieving the key. */
474                 ret << "(";
475                 INLINE_LIST( ret, cgd->getKeyExpr, 0, false );
476                 ret << ")";
477         }
478         else {
479                 /* Expression for retrieving the key, use simple dereference. */
480                 ret << "(*" << P() << ")";
481         }
482         return ret.str();
483 }
484
485 /* Write out level number of tabs. Makes the nested binary search nice
486  * looking. */
487 string FsmCodeGen::TABS( int level )
488 {
489         string result;
490         while ( level-- > 0 )
491                 result += "\t";
492         return result;
493 }
494
495 /* Write out a key from the fsm code gen. Depends on wether or not the key is
496  * signed. */
497 string FsmCodeGen::KEY( Key key )
498 {
499         ostringstream ret;
500         if ( keyOps->isSigned || !hostLang->explicitUnsigned )
501                 ret << key.getVal();
502         else
503                 ret << (unsigned long) key.getVal() << 'u';
504         return ret.str();
505 }
506
507 void FsmCodeGen::EXEC( ostream &ret, InlineItem *item, int targState, int inFinish )
508 {
509         /* The parser gives fexec two children. The double brackets are for D
510          * code. If the inline list is a single word it will get interpreted as a
511          * C-style cast by the D compiler. */
512         ret << "{" << P() << " = ((";
513         INLINE_LIST( ret, item->children, targState, inFinish );
514         ret << "))-1;}";
515 }
516
517 void FsmCodeGen::EXECTE( ostream &ret, InlineItem *item, int targState, int inFinish )
518 {
519         /* Tokend version of exec. */
520
521         /* The parser gives fexec two children. The double brackets are for D
522          * code. If the inline list is a single word it will get interpreted as a
523          * C-style cast by the D compiler. */
524         ret << "{" << TOKEND() << " = ((";
525         INLINE_LIST( ret, item->children, targState, inFinish );
526         ret << "));}";
527 }
528
529
530 void FsmCodeGen::LM_SWITCH( ostream &ret, InlineItem *item, 
531                 int targState, int inFinish )
532 {
533         ret << 
534                 "       switch( act ) {\n";
535
536         /* If the switch handles error then we also forced the error state. It
537          * will exist. */
538         if ( item->handlesError ) {
539                 ret << "        case 0: " << TOKEND() << " = " << TOKSTART() << "; ";
540                 GOTO( ret, redFsm->errState->id, inFinish );
541                 ret << "\n";
542         }
543
544         for ( InlineList::Iter lma = *item->children; lma.lte(); lma++ ) {
545                 /* Write the case label, the action and the case break. */
546                 ret << "        case " << lma->lmId << ":\n";
547
548                 /* Write the block and close it off. */
549                 ret << "        {";
550                 INLINE_LIST( ret, lma->children, targState, inFinish );
551                 ret << "}\n";
552
553                 ret << "        break;\n";
554         }
555         /* Default required for D code. */
556         ret << 
557                 "       default: break;\n"
558                 "       }\n"
559                 "\t";
560 }
561
562 void FsmCodeGen::SET_ACT( ostream &ret, InlineItem *item )
563 {
564         ret << ACT() << " = " << item->lmId << ";";
565 }
566
567 void FsmCodeGen::SET_TOKEND( ostream &ret, InlineItem *item )
568 {
569         /* The tokend action sets tokend. */
570         ret << TOKEND() << " = " << P();
571         if ( item->offset != 0 ) 
572                 out << "+" << item->offset;
573         out << ";";
574 }
575
576 void FsmCodeGen::GET_TOKEND( ostream &ret, InlineItem *item )
577 {
578         ret << TOKEND();
579 }
580
581 void FsmCodeGen::INIT_TOKSTART( ostream &ret, InlineItem *item )
582 {
583         ret << TOKSTART() << " = " << NULL_ITEM() << ";";
584 }
585
586 void FsmCodeGen::INIT_ACT( ostream &ret, InlineItem *item )
587 {
588         ret << ACT() << " = 0;";
589 }
590
591 void FsmCodeGen::SET_TOKSTART( ostream &ret, InlineItem *item )
592 {
593         ret << TOKSTART() << " = " << P() << ";";
594 }
595
596 void FsmCodeGen::SUB_ACTION( ostream &ret, InlineItem *item, 
597                 int targState, bool inFinish )
598 {
599         if ( item->children->length() > 0 ) {
600                 /* Write the block and close it off. */
601                 ret << "{";
602                 INLINE_LIST( ret, item->children, targState, inFinish );
603                 ret << "}";
604         }
605 }
606
607
608 /* Write out an inline tree structure. Walks the list and possibly calls out
609  * to virtual functions than handle language specific items in the tree. */
610 void FsmCodeGen::INLINE_LIST( ostream &ret, InlineList *inlineList, 
611                 int targState, bool inFinish )
612 {
613         for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
614                 switch ( item->type ) {
615                 case InlineItem::Text:
616                         ret << item->data;
617                         break;
618                 case InlineItem::Goto:
619                         GOTO( ret, item->targState->id, inFinish );
620                         break;
621                 case InlineItem::Call:
622                         CALL( ret, item->targState->id, targState, inFinish );
623                         break;
624                 case InlineItem::Next:
625                         NEXT( ret, item->targState->id, inFinish );
626                         break;
627                 case InlineItem::Ret:
628                         RET( ret, inFinish );
629                         break;
630                 case InlineItem::PChar:
631                         ret << P();
632                         break;
633                 case InlineItem::Char:
634                         ret << GET_KEY();
635                         break;
636                 case InlineItem::Hold:
637                         ret << P() << "--;";
638                         break;
639                 case InlineItem::Exec:
640                         EXEC( ret, item, targState, inFinish );
641                         break;
642                 case InlineItem::HoldTE:
643                         ret << TOKEND() << "--;";
644                         break;
645                 case InlineItem::ExecTE:
646                         EXECTE( ret, item, targState, inFinish );
647                         break;
648                 case InlineItem::Curs:
649                         CURS( ret, inFinish );
650                         break;
651                 case InlineItem::Targs:
652                         TARGS( ret, inFinish, targState );
653                         break;
654                 case InlineItem::Entry:
655                         ret << item->targState->id;
656                         break;
657                 case InlineItem::GotoExpr:
658                         GOTO_EXPR( ret, item, inFinish );
659                         break;
660                 case InlineItem::CallExpr:
661                         CALL_EXPR( ret, item, targState, inFinish );
662                         break;
663                 case InlineItem::NextExpr:
664                         NEXT_EXPR( ret, item, inFinish );
665                         break;
666                 case InlineItem::LmSwitch:
667                         LM_SWITCH( ret, item, targState, inFinish );
668                         break;
669                 case InlineItem::LmSetActId:
670                         SET_ACT( ret, item );
671                         break;
672                 case InlineItem::LmSetTokEnd:
673                         SET_TOKEND( ret, item );
674                         break;
675                 case InlineItem::LmGetTokEnd:
676                         GET_TOKEND( ret, item );
677                         break;
678                 case InlineItem::LmInitTokStart:
679                         INIT_TOKSTART( ret, item );
680                         break;
681                 case InlineItem::LmInitAct:
682                         INIT_ACT( ret, item );
683                         break;
684                 case InlineItem::LmSetTokStart:
685                         SET_TOKSTART( ret, item );
686                         break;
687                 case InlineItem::SubAction:
688                         SUB_ACTION( ret, item, targState, inFinish );
689                         break;
690                 case InlineItem::Break:
691                         BREAK( ret, targState );
692                         break;
693                 }
694         }
695 }
696 /* Write out paths in line directives. Escapes any special characters. */
697 string FsmCodeGen::LDIR_PATH( char *path )
698 {
699         ostringstream ret;
700         for ( char *pc = path; *pc != 0; pc++ ) {
701                 if ( *pc == '\\' )
702                         ret << "\\\\";
703                 else
704                         ret << *pc;
705         }
706         return ret.str();
707 }
708
709 void FsmCodeGen::ACTION( ostream &ret, Action *action, int targState, bool inFinish )
710 {
711         /* Write the preprocessor line info for going into the source file. */
712         lineDirective( ret, cgd->fileName, action->loc.line );
713
714         /* Write the block and close it off. */
715         ret << "\t{";
716         INLINE_LIST( ret, action->inlineList, targState, inFinish );
717         ret << "}\n";
718 }
719
720 void FsmCodeGen::CONDITION( ostream &ret, Action *condition )
721 {
722         ret << "\n";
723         lineDirective( ret, cgd->fileName, condition->loc.line );
724         INLINE_LIST( ret, condition->inlineList, 0, false );
725 }
726
727 string FsmCodeGen::ERROR_STATE()
728 {
729         ostringstream ret;
730         if ( redFsm->errState != 0 )
731                 ret << redFsm->errState->id;
732         else
733                 ret << "-1";
734         return ret.str();
735 }
736
737 string FsmCodeGen::FIRST_FINAL_STATE()
738 {
739         ostringstream ret;
740         if ( redFsm->firstFinState != 0 )
741                 ret << redFsm->firstFinState->id;
742         else
743                 ret << redFsm->nextStateId;
744         return ret.str();
745 }
746
747 void FsmCodeGen::writeOutInit()
748 {
749         out << "        {\n";
750         out << "\t" << CS() << " = " << START() << ";\n";
751         
752         /* If there are any calls, then the stack top needs initialization. */
753         if ( anyActionCalls() || anyActionRets() )
754                 out << "\t" << TOP() << " = 0;\n";
755
756         if ( cgd->hasLongestMatch ) {
757                 out << 
758                         "       " << TOKSTART() << " = " << NULL_ITEM() << ";\n"
759                         "       " << TOKEND() << " = " << NULL_ITEM() << ";\n"
760                         "       " << ACT() << " = 0;\n";
761         }
762         out << "        }\n";
763 }
764
765 string FsmCodeGen::DATA_PREFIX()
766 {
767         if ( cgd->dataPrefix )
768                 return FSM_NAME() + "_";
769         return "";
770 }
771
772 /* Emit the alphabet data type. */
773 string FsmCodeGen::ALPH_TYPE()
774 {
775         string ret = keyOps->alphType->data1;
776         if ( keyOps->alphType->data2 != 0 ) {
777                 ret += " ";
778                 ret += + keyOps->alphType->data2;
779         }
780         return ret;
781 }
782
783 /* Emit the alphabet data type. */
784 string FsmCodeGen::WIDE_ALPH_TYPE()
785 {
786         string ret;
787         if ( maxKey <= keyOps->maxKey )
788                 ret = ALPH_TYPE();
789         else {
790                 long long maxKeyVal = maxKey.getLongLong();
791                 HostType *wideType = keyOps->typeSubsumes( keyOps->isSigned, maxKeyVal );
792                 assert( wideType != 0 );
793
794                 ret = wideType->data1;
795                 if ( wideType->data2 != 0 ) {
796                         ret += " ";
797                         ret += wideType->data2;
798                 }
799         }
800         return ret;
801 }
802
803
804 /*
805  * Language specific, but style independent code generators functions.
806  */
807
808 string CCodeGen::PTR_CONST()
809 {
810         return "const ";
811 }
812
813 std::ostream &CCodeGen::OPEN_ARRAY( string type, string name )
814 {
815         out << "static const " << type << " " << name << "[] = {\n";
816         return out;
817 }
818
819 std::ostream &CCodeGen::CLOSE_ARRAY()
820 {
821         return out << "};\n";
822 }
823
824 std::ostream &CCodeGen::STATIC_VAR( string type, string name )
825 {
826         out << "static const " << type << " " << name;
827         return out;
828 }
829
830 string CCodeGen::UINT( )
831 {
832         return "unsigned int";
833 }
834
835 string CCodeGen::ARR_OFF( string ptr, string offset )
836 {
837         return ptr + " + " + offset;
838 }
839
840 string CCodeGen::CAST( string type )
841 {
842         return "(" + type + ")";
843 }
844
845 string CCodeGen::NULL_ITEM()
846 {
847         return "0";
848 }
849
850 string CCodeGen::POINTER()
851 {
852         return " *";
853 }
854
855 std::ostream &CCodeGen::SWITCH_DEFAULT()
856 {
857         return out;
858 }
859
860 string CCodeGen::CTRL_FLOW()
861 {
862         return "";
863 }
864
865 /*
866  * D Specific
867  */
868
869 string DCodeGen::NULL_ITEM()
870 {
871         return "null";
872 }
873
874 string DCodeGen::POINTER()
875 {
876         // multiple items seperated by commas can also be pointer types.
877         return "* ";
878 }
879
880 string DCodeGen::PTR_CONST()
881 {
882         return "";
883 }
884
885 std::ostream &DCodeGen::OPEN_ARRAY( string type, string name )
886 {
887         out << "static const " << type << "[] " << name << " = [\n";
888         return out;
889 }
890
891 std::ostream &DCodeGen::CLOSE_ARRAY()
892 {
893         return out << "];\n";
894 }
895
896 std::ostream &DCodeGen::STATIC_VAR( string type, string name )
897 {
898         out << "static const " << type << " " << name;
899         return out;
900 }
901
902 string DCodeGen::ARR_OFF( string ptr, string offset )
903 {
904         return "&" + ptr + "[" + offset + "]";
905 }
906
907 string DCodeGen::CAST( string type )
908 {
909         return "cast(" + type + ")";
910 }
911
912 string DCodeGen::UINT( )
913 {
914         return "uint";
915 }
916
917 std::ostream &DCodeGen::SWITCH_DEFAULT()
918 {
919         out << "                default: break;\n";
920         return out;
921 }
922
923 string DCodeGen::CTRL_FLOW()
924 {
925         return "if (true) ";
926 }
927
928
929 /* 
930  * Java Specific
931  */
932
933 string JavaCodeGen::PTR_CONST()
934 {
935         /* Not used in Java code. */
936         assert( false );
937         return "final";
938 }
939
940 std::ostream &JavaCodeGen::OPEN_ARRAY( string type, string name )
941 {
942         out << "static final " << type << "[] " << name << " = {\n";
943         return out;
944 }
945
946 std::ostream &JavaCodeGen::CLOSE_ARRAY()
947 {
948         return out << "};\n";
949 }
950
951 std::ostream &JavaCodeGen::STATIC_VAR( string type, string name )
952 {
953         out << "static final " << type << " " << name;
954         return out;
955 }
956
957 string JavaCodeGen::UINT( )
958 {
959         /* Not used. */
960         assert( false );
961         return "long";
962 }
963
964 string JavaCodeGen::ARR_OFF( string ptr, string offset )
965 {
966         return ptr + " + " + offset;
967 }
968
969 string JavaCodeGen::CAST( string type )
970 {
971         return "(" + type + ")";
972 }
973
974 string JavaCodeGen::NULL_ITEM()
975 {
976         /* In java we use integers instead of pointers. */
977         return "-1";
978 }
979
980 string JavaCodeGen::POINTER()
981 {
982         /* Not used. */
983         assert( false );
984         return " *";
985 }
986
987 std::ostream &JavaCodeGen::SWITCH_DEFAULT()
988 {
989         return out;
990 }
991
992 string JavaCodeGen::GET_KEY()
993 {
994         ostringstream ret;
995         if ( cgd->getKeyExpr != 0 ) { 
996                 /* Emit the user supplied method of retrieving the key. */
997                 ret << "(";
998                 INLINE_LIST( ret, cgd->getKeyExpr, 0, false );
999                 ret << ")";
1000         }
1001         else {
1002                 /* Expression for retrieving the key, use simple dereference. */
1003                 ret << "data[" << P() << "]";
1004         }
1005         return ret.str();
1006 }
1007
1008 string JavaCodeGen::CTRL_FLOW()
1009 {
1010         return "if (true) ";
1011 }
1012