4917c9051d98b2a4d81c3dd0af597f83daa27fef
[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 /* Assign ids to referenced actions. */
83 void FsmCodeGen::assignActionIds()
84 {
85         int nextActionId = 0;
86         for ( ActionList::Iter act = cgd->actionList; act.lte(); act++ ) {
87                 /* Only ever interested in referenced actions. */
88                 if ( act->numRefs() > 0 )
89                         act->actionId = nextActionId++;
90         }
91 }
92
93 void FsmCodeGen::setValueLimits()
94 {
95         maxSingleLen = 0;
96         maxRangeLen = 0;
97         maxKeyOffset = 0;
98         maxIndexOffset = 0;
99         maxActListId = 0;
100         maxActionLoc = 0;
101         maxActArrItem = 0;
102         maxSpan = 0;
103         maxCondSpan = 0;
104         maxFlatIndexOffset = 0;
105         maxCondOffset = 0;
106         maxCondLen = 0;
107         maxCondSpaceId = 0;
108         maxCondIndexOffset = 0;
109
110         /* In both of these cases the 0 index is reserved for no value, so the max
111          * is one more than it would be if they started at 0. */
112         maxIndex = redFsm->transSet.length();
113         maxCond = cgd->condSpaceList.length(); 
114
115         /* The nextStateId - 1 is the last state id assigned. */
116         maxState = redFsm->nextStateId - 1;
117
118         for ( CondSpaceList::Iter csi = cgd->condSpaceList; csi.lte(); csi++ ) {
119                 if ( csi->condSpaceId > maxCondSpaceId )
120                         maxCondSpaceId = csi->condSpaceId;
121         }
122
123         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
124                 /* Maximum cond length. */
125                 if ( st->stateCondList.length() > maxCondLen )
126                         maxCondLen = st->stateCondList.length();
127
128                 /* Maximum single length. */
129                 if ( st->outSingle.length() > maxSingleLen )
130                         maxSingleLen = st->outSingle.length();
131
132                 /* Maximum range length. */
133                 if ( st->outRange.length() > maxRangeLen )
134                         maxRangeLen = st->outRange.length();
135
136                 /* The key offset index offset for the state after last is not used, skip it.. */
137                 if ( ! st.last() ) {
138                         maxCondOffset += st->stateCondList.length();
139                         maxKeyOffset += st->outSingle.length() + st->outRange.length()*2;
140                         maxIndexOffset += st->outSingle.length() + st->outRange.length() + 1;
141                 }
142
143                 /* Max cond span. */
144                 if ( st->condList != 0 ) {
145                         unsigned long long span = keyOps->span( st->condLowKey, st->condHighKey );
146                         if ( span > maxCondSpan )
147                                 maxCondSpan = span;
148                 }
149
150                 /* Max key span. */
151                 if ( st->transList != 0 ) {
152                         unsigned long long span = keyOps->span( st->lowKey, st->highKey );
153                         if ( span > maxSpan )
154                                 maxSpan = span;
155                 }
156
157                 /* Max cond index offset. */
158                 if ( ! st.last() ) {
159                         if ( st->condList != 0 )
160                                 maxCondIndexOffset += keyOps->span( st->condLowKey, st->condHighKey );
161                 }
162
163                 /* Max flat index offset. */
164                 if ( ! st.last() ) {
165                         if ( st->transList != 0 )
166                                 maxFlatIndexOffset += keyOps->span( st->lowKey, st->highKey );
167                         maxFlatIndexOffset += 1;
168                 }
169         }
170
171         for ( ActionTableMap::Iter at = redFsm->actionMap; at.lte(); at++ ) {
172                 /* Maximum id of action lists. */
173                 if ( at->actListId+1 > maxActListId )
174                         maxActListId = at->actListId+1;
175
176                 /* Maximum location of items in action array. */
177                 if ( at->location+1 > maxActionLoc )
178                         maxActionLoc = at->location+1;
179
180                 /* Maximum values going into the action array. */
181                 if ( at->key.length() > maxActArrItem )
182                         maxActArrItem = at->key.length();
183                 for ( ActionTable::Iter item = at->key; item.lte(); item++ ) {
184                         if ( item->value->actionId > maxActArrItem )
185                                 maxActArrItem = item->value->actionId;
186                 }
187         }
188 }
189
190
191 unsigned int FsmCodeGen::arrayTypeSize( unsigned long maxVal )
192 {
193         long long maxValLL = (long long) maxVal;
194         HostType *arrayType = keyOps->typeSubsumes( maxValLL );
195         assert( arrayType != 0 );
196         return arrayType->size;
197 }
198
199 string FsmCodeGen::ARRAY_TYPE( unsigned long maxVal )
200 {
201         long long maxValLL = (long long) maxVal;
202         HostType *arrayType = keyOps->typeSubsumes( maxValLL );
203         assert( arrayType != 0 );
204
205         string ret = arrayType->data1;
206         if ( arrayType->data2 != 0 ) {
207                 ret += " ";
208                 ret += arrayType->data2;
209         }
210         return ret;
211 }
212
213
214 /* Write out the fsm name. */
215 string FsmCodeGen::FSM_NAME()
216 {
217         return fsmName;
218 }
219
220 /* Emit the offset of the start state as a decimal integer. */
221 string FsmCodeGen::START_STATE_ID()
222 {
223         ostringstream ret;
224         ret << redFsm->startState->id;
225         return ret.str();
226 };
227
228 /* Write out the array of actions. */
229 std::ostream &FsmCodeGen::ACTIONS_ARRAY()
230 {
231         out << "\t0, ";
232         int totalActions = 1;
233         for ( ActionTableMap::Iter act = redFsm->actionMap; act.lte(); act++ ) {
234                 /* Write out the length, which will never be the last character. */
235                 out << act->key.length() << ", ";
236                 /* Put in a line break every 8 */
237                 if ( totalActions++ % 8 == 7 )
238                         out << "\n\t";
239
240                 for ( ActionTable::Iter item = act->key; item.lte(); item++ ) {
241                         out << item->value->actionId;
242                         if ( ! (act.last() && item.last()) )
243                                 out << ", ";
244
245                         /* Put in a line break every 8 */
246                         if ( totalActions++ % 8 == 7 )
247                                 out << "\n\t";
248                 }
249         }
250         out << "\n";
251         return out;
252 }
253
254
255 string FsmCodeGen::CS()
256 {
257         ostringstream ret;
258         if ( cgd->curStateExpr != 0 ) { 
259                 /* Emit the user supplied method of retrieving the key. */
260                 ret << "(";
261                 INLINE_LIST( ret, cgd->curStateExpr, 0, false );
262                 ret << ")";
263         }
264         else {
265                 /* Expression for retrieving the key, use simple dereference. */
266                 ret << ACCESS() << "cs";
267         }
268         return ret.str();
269 }
270
271 string FsmCodeGen::ACCESS()
272 {
273         ostringstream ret;
274         if ( cgd->accessExpr != 0 )
275                 INLINE_LIST( ret, cgd->accessExpr, 0, false );
276         return ret.str();
277 }
278
279 string FsmCodeGen::GET_WIDE_KEY()
280 {
281         if ( anyConditions() ) 
282                 return "_widec";
283         else
284                 return GET_KEY();
285 }
286
287 string FsmCodeGen::GET_WIDE_KEY( RedStateAp *state )
288 {
289         if ( state->stateCondList.length() > 0 )
290                 return "_widec";
291         else
292                 return GET_KEY();
293 }
294
295 string FsmCodeGen::GET_KEY()
296 {
297         ostringstream ret;
298         if ( cgd->getKeyExpr != 0 ) { 
299                 /* Emit the user supplied method of retrieving the key. */
300                 ret << "(";
301                 INLINE_LIST( ret, cgd->getKeyExpr, 0, false );
302                 ret << ")";
303         }
304         else {
305                 /* Expression for retrieving the key, use simple dereference. */
306                 ret << "(*" << P() << ")";
307         }
308         return ret.str();
309 }
310
311 /* Write out level number of tabs. Makes the nested binary search nice
312  * looking. */
313 string FsmCodeGen::TABS( int level )
314 {
315         string result;
316         while ( level-- > 0 )
317                 result += "\t";
318         return result;
319 }
320
321 /* Write out a key from the fsm code gen. Depends on wether or not the key is
322  * signed. */
323 string FsmCodeGen::KEY( Key key )
324 {
325         ostringstream ret;
326         if ( keyOps->isSigned || !hostLang->explicitUnsigned )
327                 ret << key.getVal();
328         else
329                 ret << (unsigned long) key.getVal() << 'u';
330         return ret.str();
331 }
332
333 void FsmCodeGen::EXEC( ostream &ret, InlineItem *item, int targState, int inFinish )
334 {
335         /* The parser gives fexec two children. The double brackets are for D
336          * code. If the inline list is a single word it will get interpreted as a
337          * C-style cast by the D compiler. */
338         ret << "{" << P() << " = ((";
339         INLINE_LIST( ret, item->children, targState, inFinish );
340         ret << "))-1;}";
341 }
342
343 void FsmCodeGen::EXECTE( ostream &ret, InlineItem *item, int targState, int inFinish )
344 {
345         /* Tokend version of exec. */
346
347         /* The parser gives fexec two children. The double brackets are for D
348          * code. If the inline list is a single word it will get interpreted as a
349          * C-style cast by the D compiler. */
350         ret << "{" << TOKEND() << " = ((";
351         INLINE_LIST( ret, item->children, targState, inFinish );
352         ret << "));}";
353 }
354
355
356 void FsmCodeGen::LM_SWITCH( ostream &ret, InlineItem *item, 
357                 int targState, int inFinish )
358 {
359         ret << 
360                 "       switch( act ) {\n";
361
362         /* If the switch handles error then we also forced the error state. It
363          * will exist. */
364         if ( item->handlesError ) {
365                 ret << "        case 0: " << TOKEND() << " = " << TOKSTART() << "; ";
366                 GOTO( ret, redFsm->errState->id, inFinish );
367                 ret << "\n";
368         }
369
370         for ( InlineList::Iter lma = *item->children; lma.lte(); lma++ ) {
371                 /* Write the case label, the action and the case break. */
372                 ret << "        case " << lma->lmId << ":\n";
373
374                 /* Write the block and close it off. */
375                 ret << "        {";
376                 INLINE_LIST( ret, lma->children, targState, inFinish );
377                 ret << "}\n";
378
379                 ret << "        break;\n";
380         }
381         /* Default required for D code. */
382         ret << 
383                 "       default: break;\n"
384                 "       }\n"
385                 "\t";
386 }
387
388 void FsmCodeGen::SET_ACT( ostream &ret, InlineItem *item )
389 {
390         ret << ACT() << " = " << item->lmId << ";";
391 }
392
393 void FsmCodeGen::SET_TOKEND( ostream &ret, InlineItem *item )
394 {
395         /* The tokend action sets tokend. */
396         ret << TOKEND() << " = " << P();
397         if ( item->offset != 0 ) 
398                 out << "+" << item->offset;
399         out << ";";
400 }
401
402 void FsmCodeGen::GET_TOKEND( ostream &ret, InlineItem *item )
403 {
404         ret << TOKEND();
405 }
406
407 void FsmCodeGen::INIT_TOKSTART( ostream &ret, InlineItem *item )
408 {
409         ret << TOKSTART() << " = " << NULL_ITEM() << ";";
410 }
411
412 void FsmCodeGen::INIT_ACT( ostream &ret, InlineItem *item )
413 {
414         ret << ACT() << " = 0;";
415 }
416
417 void FsmCodeGen::SET_TOKSTART( ostream &ret, InlineItem *item )
418 {
419         ret << TOKSTART() << " = " << P() << ";";
420 }
421
422 void FsmCodeGen::SUB_ACTION( ostream &ret, InlineItem *item, 
423                 int targState, bool inFinish )
424 {
425         if ( item->children->length() > 0 ) {
426                 /* Write the block and close it off. */
427                 ret << "{";
428                 INLINE_LIST( ret, item->children, targState, inFinish );
429                 ret << "}";
430         }
431 }
432
433
434 /* Write out an inline tree structure. Walks the list and possibly calls out
435  * to virtual functions than handle language specific items in the tree. */
436 void FsmCodeGen::INLINE_LIST( ostream &ret, InlineList *inlineList, 
437                 int targState, bool inFinish )
438 {
439         for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
440                 switch ( item->type ) {
441                 case InlineItem::Text:
442                         ret << item->data;
443                         break;
444                 case InlineItem::Goto:
445                         GOTO( ret, item->targState->id, inFinish );
446                         break;
447                 case InlineItem::Call:
448                         CALL( ret, item->targState->id, targState, inFinish );
449                         break;
450                 case InlineItem::Next:
451                         NEXT( ret, item->targState->id, inFinish );
452                         break;
453                 case InlineItem::Ret:
454                         RET( ret, inFinish );
455                         break;
456                 case InlineItem::PChar:
457                         ret << P();
458                         break;
459                 case InlineItem::Char:
460                         ret << GET_KEY();
461                         break;
462                 case InlineItem::Hold:
463                         ret << P() << "--;";
464                         break;
465                 case InlineItem::Exec:
466                         EXEC( ret, item, targState, inFinish );
467                         break;
468                 case InlineItem::HoldTE:
469                         ret << TOKEND() << "--;";
470                         break;
471                 case InlineItem::ExecTE:
472                         EXECTE( ret, item, targState, inFinish );
473                         break;
474                 case InlineItem::Curs:
475                         CURS( ret, inFinish );
476                         break;
477                 case InlineItem::Targs:
478                         TARGS( ret, inFinish, targState );
479                         break;
480                 case InlineItem::Entry:
481                         ret << item->targState->id;
482                         break;
483                 case InlineItem::GotoExpr:
484                         GOTO_EXPR( ret, item, inFinish );
485                         break;
486                 case InlineItem::CallExpr:
487                         CALL_EXPR( ret, item, targState, inFinish );
488                         break;
489                 case InlineItem::NextExpr:
490                         NEXT_EXPR( ret, item, inFinish );
491                         break;
492                 case InlineItem::LmSwitch:
493                         LM_SWITCH( ret, item, targState, inFinish );
494                         break;
495                 case InlineItem::LmSetActId:
496                         SET_ACT( ret, item );
497                         break;
498                 case InlineItem::LmSetTokEnd:
499                         SET_TOKEND( ret, item );
500                         break;
501                 case InlineItem::LmGetTokEnd:
502                         GET_TOKEND( ret, item );
503                         break;
504                 case InlineItem::LmInitTokStart:
505                         INIT_TOKSTART( ret, item );
506                         break;
507                 case InlineItem::LmInitAct:
508                         INIT_ACT( ret, item );
509                         break;
510                 case InlineItem::LmSetTokStart:
511                         SET_TOKSTART( ret, item );
512                         break;
513                 case InlineItem::SubAction:
514                         SUB_ACTION( ret, item, targState, inFinish );
515                         break;
516                 case InlineItem::Break:
517                         BREAK( ret, targState );
518                         break;
519                 }
520         }
521 }
522 /* Write out paths in line directives. Escapes any special characters. */
523 string FsmCodeGen::LDIR_PATH( char *path )
524 {
525         ostringstream ret;
526         for ( char *pc = path; *pc != 0; pc++ ) {
527                 if ( *pc == '\\' )
528                         ret << "\\\\";
529                 else
530                         ret << *pc;
531         }
532         return ret.str();
533 }
534
535 void FsmCodeGen::ACTION( ostream &ret, Action *action, int targState, bool inFinish )
536 {
537         /* Write the preprocessor line info for going into the source file. */
538         lineDirective( ret, cgd->fileName, action->loc.line );
539
540         /* Write the block and close it off. */
541         ret << "\t{";
542         INLINE_LIST( ret, action->inlineList, targState, inFinish );
543         ret << "}\n";
544 }
545
546 void FsmCodeGen::CONDITION( ostream &ret, Action *condition )
547 {
548         ret << "\n";
549         lineDirective( ret, cgd->fileName, condition->loc.line );
550         INLINE_LIST( ret, condition->inlineList, 0, false );
551 }
552
553 string FsmCodeGen::ERROR_STATE()
554 {
555         ostringstream ret;
556         if ( redFsm->errState != 0 )
557                 ret << redFsm->errState->id;
558         else
559                 ret << "-1";
560         return ret.str();
561 }
562
563 string FsmCodeGen::FIRST_FINAL_STATE()
564 {
565         ostringstream ret;
566         if ( redFsm->firstFinState != 0 )
567                 ret << redFsm->firstFinState->id;
568         else
569                 ret << redFsm->nextStateId;
570         return ret.str();
571 }
572
573 void FsmCodeGen::writeOutInit()
574 {
575         out << "        {\n";
576         out << "\t" << CS() << " = " << START() << ";\n";
577         
578         /* If there are any calls, then the stack top needs initialization. */
579         if ( anyActionCalls() || anyActionRets() )
580                 out << "\t" << TOP() << " = 0;\n";
581
582         if ( cgd->hasLongestMatch ) {
583                 out << 
584                         "       " << TOKSTART() << " = " << NULL_ITEM() << ";\n"
585                         "       " << TOKEND() << " = " << NULL_ITEM() << ";\n"
586                         "       " << ACT() << " = 0;\n";
587         }
588         out << "        }\n";
589 }
590
591 string FsmCodeGen::DATA_PREFIX()
592 {
593         if ( cgd->dataPrefix )
594                 return FSM_NAME() + "_";
595         return "";
596 }
597
598 /* Emit the alphabet data type. */
599 string FsmCodeGen::ALPH_TYPE()
600 {
601         string ret = keyOps->alphType->data1;
602         if ( keyOps->alphType->data2 != 0 ) {
603                 ret += " ";
604                 ret += + keyOps->alphType->data2;
605         }
606         return ret;
607 }
608
609 /* Emit the alphabet data type. */
610 string FsmCodeGen::WIDE_ALPH_TYPE()
611 {
612         string ret;
613         if ( maxKey <= keyOps->maxKey )
614                 ret = ALPH_TYPE();
615         else {
616                 long long maxKeyVal = maxKey.getLongLong();
617                 HostType *wideType = keyOps->typeSubsumes( keyOps->isSigned, maxKeyVal );
618                 assert( wideType != 0 );
619
620                 ret = wideType->data1;
621                 if ( wideType->data2 != 0 ) {
622                         ret += " ";
623                         ret += wideType->data2;
624                 }
625         }
626         return ret;
627 }
628
629
630 /*
631  * Language specific, but style independent code generators functions.
632  */
633
634 string CCodeGen::PTR_CONST()
635 {
636         return "const ";
637 }
638
639 std::ostream &CCodeGen::OPEN_ARRAY( string type, string name )
640 {
641         out << "static const " << type << " " << name << "[] = {\n";
642         return out;
643 }
644
645 std::ostream &CCodeGen::CLOSE_ARRAY()
646 {
647         return out << "};\n";
648 }
649
650 std::ostream &CCodeGen::STATIC_VAR( string type, string name )
651 {
652         out << "static const " << type << " " << name;
653         return out;
654 }
655
656 string CCodeGen::UINT( )
657 {
658         return "unsigned int";
659 }
660
661 string CCodeGen::ARR_OFF( string ptr, string offset )
662 {
663         return ptr + " + " + offset;
664 }
665
666 string CCodeGen::CAST( string type )
667 {
668         return "(" + type + ")";
669 }
670
671 string CCodeGen::NULL_ITEM()
672 {
673         return "0";
674 }
675
676 string CCodeGen::POINTER()
677 {
678         return " *";
679 }
680
681 std::ostream &CCodeGen::SWITCH_DEFAULT()
682 {
683         return out;
684 }
685
686 string CCodeGen::CTRL_FLOW()
687 {
688         return "";
689 }
690
691 /*
692  * D Specific
693  */
694
695 string DCodeGen::NULL_ITEM()
696 {
697         return "null";
698 }
699
700 string DCodeGen::POINTER()
701 {
702         // multiple items seperated by commas can also be pointer types.
703         return "* ";
704 }
705
706 string DCodeGen::PTR_CONST()
707 {
708         return "";
709 }
710
711 std::ostream &DCodeGen::OPEN_ARRAY( string type, string name )
712 {
713         out << "static const " << type << "[] " << name << " = [\n";
714         return out;
715 }
716
717 std::ostream &DCodeGen::CLOSE_ARRAY()
718 {
719         return out << "];\n";
720 }
721
722 std::ostream &DCodeGen::STATIC_VAR( string type, string name )
723 {
724         out << "static const " << type << " " << name;
725         return out;
726 }
727
728 string DCodeGen::ARR_OFF( string ptr, string offset )
729 {
730         return "&" + ptr + "[" + offset + "]";
731 }
732
733 string DCodeGen::CAST( string type )
734 {
735         return "cast(" + type + ")";
736 }
737
738 string DCodeGen::UINT( )
739 {
740         return "uint";
741 }
742
743 std::ostream &DCodeGen::SWITCH_DEFAULT()
744 {
745         out << "                default: break;\n";
746         return out;
747 }
748
749 string DCodeGen::CTRL_FLOW()
750 {
751         return "if (true) ";
752 }
753
754
755 /* 
756  * Java Specific
757  */
758
759 string JavaCodeGen::PTR_CONST()
760 {
761         /* Not used in Java code. */
762         assert( false );
763         return "final";
764 }
765
766 std::ostream &JavaCodeGen::OPEN_ARRAY( string type, string name )
767 {
768         out << "static final " << type << "[] " << name << " = {\n";
769         return out;
770 }
771
772 std::ostream &JavaCodeGen::CLOSE_ARRAY()
773 {
774         return out << "};\n";
775 }
776
777 std::ostream &JavaCodeGen::STATIC_VAR( string type, string name )
778 {
779         out << "static final " << type << " " << name;
780         return out;
781 }
782
783 string JavaCodeGen::UINT( )
784 {
785         /* Not used. */
786         assert( false );
787         return "long";
788 }
789
790 string JavaCodeGen::ARR_OFF( string ptr, string offset )
791 {
792         return ptr + " + " + offset;
793 }
794
795 string JavaCodeGen::CAST( string type )
796 {
797         return "(" + type + ")";
798 }
799
800 string JavaCodeGen::NULL_ITEM()
801 {
802         /* In java we use integers instead of pointers. */
803         return "-1";
804 }
805
806 string JavaCodeGen::POINTER()
807 {
808         /* Not used. */
809         assert( false );
810         return " *";
811 }
812
813 std::ostream &JavaCodeGen::SWITCH_DEFAULT()
814 {
815         return out;
816 }
817
818 string JavaCodeGen::GET_KEY()
819 {
820         ostringstream ret;
821         if ( cgd->getKeyExpr != 0 ) { 
822                 /* Emit the user supplied method of retrieving the key. */
823                 ret << "(";
824                 INLINE_LIST( ret, cgd->getKeyExpr, 0, false );
825                 ret << ")";
826         }
827         else {
828                 /* Expression for retrieving the key, use simple dereference. */
829                 ret << "data[" << P() << "]";
830         }
831         return ret.str();
832 }
833
834 string JavaCodeGen::CTRL_FLOW()
835 {
836         return "if (true) ";
837 }
838