Get ragel working again while the direct-to-backend code is being written.
[external/ragel.git] / rlgen-java / javacodegen.cpp
1 /*
2  *  Copyright 2006-2007 Adrian Thurston <thurston@complang.org>
3  *            2007 Colin Fleming <colin.fleming@caverock.com>
4  */
5
6 /*  This file is part of Ragel.
7  *
8  *  Ragel is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  * 
13  *  Ragel is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  * 
18  *  You should have received a copy of the GNU General Public License
19  *  along with Ragel; if not, write to the Free Software
20  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
21  */
22
23 #include "rlgen-java.h"
24 #include "javacodegen.h"
25 #include "redfsm.h"
26 #include "gendata.h"
27 #include <iomanip>
28 #include <sstream>
29
30 /* Integer array line length. */
31 #define IALL 12
32
33 /* Static array initialization item count 
34  * (should be multiple of IALL). */
35 #define SAIIC 8184
36
37 #define _resume    1
38 #define _again     2
39 #define _eof_trans 3
40 #define _test_eof  4
41 #define _out       5
42
43 using std::setw;
44 using std::ios;
45 using std::ostringstream;
46 using std::string;
47 using std::cerr;
48
49 void javaLineDirective( ostream &out, const char *fileName, int line )
50 {
51         /* Write the preprocessor line info for to the input file. */
52         out << "// line " << line  << " \"";
53         for ( const char *pc = fileName; *pc != 0; pc++ ) {
54                 if ( *pc == '\\' )
55                         out << "\\\\";
56                 else
57                         out << *pc;
58         }
59         out << "\"\n";
60 }
61
62 void JavaTabCodeGen::genLineDirective( ostream &out )
63 {
64         std::streambuf *sbuf = out.rdbuf();
65         output_filter *filter = static_cast<output_filter*>(sbuf);
66         javaLineDirective( out, filter->fileName, filter->line + 1 );
67 }
68
69 void JavaTabCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
70 {
71         ret << "{" << CS() << " = " << gotoDest << "; _goto_targ = " << _again << "; " << 
72                         CTRL_FLOW() << "continue _goto;}";
73 }
74
75 void JavaTabCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
76 {
77         ret << "{" << CS() << " = (";
78         INLINE_LIST( ret, ilItem->children, 0, inFinish );
79         ret << "); _goto_targ = " << _again << "; " << CTRL_FLOW() << "continue _goto;}";
80 }
81
82 void JavaTabCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
83 {
84         if ( prePushExpr != 0 ) {
85                 ret << "{";
86                 INLINE_LIST( ret, prePushExpr, 0, false );
87         }
88
89         ret << "{" << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = " << 
90                         callDest << "; _goto_targ = " << _again << "; " << CTRL_FLOW() << "continue _goto;}";
91
92         if ( prePushExpr != 0 )
93                 ret << "}";
94 }
95
96 void JavaTabCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish )
97 {
98         if ( prePushExpr != 0 ) {
99                 ret << "{";
100                 INLINE_LIST( ret, prePushExpr, 0, false );
101         }
102
103         ret << "{" << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = (";
104         INLINE_LIST( ret, ilItem->children, targState, inFinish );
105         ret << "); _goto_targ = " << _again << "; " << CTRL_FLOW() << "continue _goto;}";
106
107         if ( prePushExpr != 0 )
108                 ret << "}";
109 }
110
111 void JavaTabCodeGen::RET( ostream &ret, bool inFinish )
112 {
113         ret << "{" << CS() << " = " << STACK() << "[--" << TOP() << "];";
114
115         if ( postPopExpr != 0 ) {
116                 ret << "{";
117                 INLINE_LIST( ret, postPopExpr, 0, false );
118                 ret << "}";
119         }
120
121         ret << "_goto_targ = " << _again << "; " << CTRL_FLOW() << "continue _goto;}";
122 }
123
124 void JavaTabCodeGen::BREAK( ostream &ret, int targState )
125 {
126         ret << "{ " << P() << " += 1; _goto_targ = " << _out << "; " << 
127                         CTRL_FLOW() << " continue _goto;}";
128 }
129
130 void JavaTabCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
131 {
132         ret << CS() << " = " << nextDest << ";";
133 }
134
135 void JavaTabCodeGen::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
136 {
137         ret << CS() << " = (";
138         INLINE_LIST( ret, ilItem->children, 0, inFinish );
139         ret << ");";
140 }
141
142 void JavaTabCodeGen::EXEC( ostream &ret, GenInlineItem *item, int targState, int inFinish )
143 {
144         /* The parser gives fexec two children. The double brackets are for D
145          * code. If the inline list is a single word it will get interpreted as a
146          * C-style cast by the D compiler. */
147         ret << "{" << P() << " = ((";
148         INLINE_LIST( ret, item->children, targState, inFinish );
149         ret << "))-1;}";
150 }
151
152 /* Write out an inline tree structure. Walks the list and possibly calls out
153  * to virtual functions than handle language specific items in the tree. */
154 void JavaTabCodeGen::INLINE_LIST( ostream &ret, GenInlineList *inlineList, 
155                 int targState, bool inFinish )
156 {
157         for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) {
158                 switch ( item->type ) {
159                 case GenInlineItem::Text:
160                         ret << item->data;
161                         break;
162                 case GenInlineItem::Goto:
163                         GOTO( ret, item->targState->id, inFinish );
164                         break;
165                 case GenInlineItem::Call:
166                         CALL( ret, item->targState->id, targState, inFinish );
167                         break;
168                 case GenInlineItem::Next:
169                         NEXT( ret, item->targState->id, inFinish );
170                         break;
171                 case GenInlineItem::Ret:
172                         RET( ret, inFinish );
173                         break;
174                 case GenInlineItem::PChar:
175                         ret << P();
176                         break;
177                 case GenInlineItem::Char:
178                         ret << GET_KEY();
179                         break;
180                 case GenInlineItem::Hold:
181                         ret << P() << "--;";
182                         break;
183                 case GenInlineItem::Exec:
184                         EXEC( ret, item, targState, inFinish );
185                         break;
186                 case GenInlineItem::Curs:
187                         ret << "(_ps)";
188                         break;
189                 case GenInlineItem::Targs:
190                         ret << "(" << CS() << ")";
191                         break;
192                 case GenInlineItem::Entry:
193                         ret << item->targState->id;
194                         break;
195                 case GenInlineItem::GotoExpr:
196                         GOTO_EXPR( ret, item, inFinish );
197                         break;
198                 case GenInlineItem::CallExpr:
199                         CALL_EXPR( ret, item, targState, inFinish );
200                         break;
201                 case GenInlineItem::NextExpr:
202                         NEXT_EXPR( ret, item, inFinish );
203                         break;
204                 case GenInlineItem::LmSwitch:
205                         LM_SWITCH( ret, item, targState, inFinish );
206                         break;
207                 case GenInlineItem::LmSetActId:
208                         SET_ACT( ret, item );
209                         break;
210                 case GenInlineItem::LmSetTokEnd:
211                         SET_TOKEND( ret, item );
212                         break;
213                 case GenInlineItem::LmGetTokEnd:
214                         GET_TOKEND( ret, item );
215                         break;
216                 case GenInlineItem::LmInitTokStart:
217                         INIT_TOKSTART( ret, item );
218                         break;
219                 case GenInlineItem::LmInitAct:
220                         INIT_ACT( ret, item );
221                         break;
222                 case GenInlineItem::LmSetTokStart:
223                         SET_TOKSTART( ret, item );
224                         break;
225                 case GenInlineItem::SubAction:
226                         SUB_ACTION( ret, item, targState, inFinish );
227                         break;
228                 case GenInlineItem::Break:
229                         BREAK( ret, targState );
230                         break;
231                 }
232         }
233 }
234
235 string JavaTabCodeGen::DATA_PREFIX()
236 {
237         if ( dataPrefix )
238                 return FSM_NAME() + "_";
239         return "";
240 }
241
242 /* Emit the alphabet data type. */
243 string JavaTabCodeGen::ALPH_TYPE()
244 {
245         string ret = keyOps->alphType->data1;
246         if ( keyOps->alphType->data2 != 0 ) {
247                 ret += " ";
248                 ret += + keyOps->alphType->data2;
249         }
250         return ret;
251 }
252
253 /* Emit the alphabet data type. */
254 string JavaTabCodeGen::WIDE_ALPH_TYPE()
255 {
256         string ret;
257         if ( redFsm->maxKey <= keyOps->maxKey )
258                 ret = ALPH_TYPE();
259         else {
260                 long long maxKeyVal = redFsm->maxKey.getLongLong();
261                 HostType *wideType = keyOps->typeSubsumes( keyOps->isSigned, maxKeyVal );
262                 assert( wideType != 0 );
263
264                 ret = wideType->data1;
265                 if ( wideType->data2 != 0 ) {
266                         ret += " ";
267                         ret += wideType->data2;
268                 }
269         }
270         return ret;
271 }
272
273
274
275 void JavaTabCodeGen::COND_TRANSLATE()
276 {
277         out << 
278                 "       _widec = " << GET_KEY() << ";\n"
279                 "       _keys = " << CO() << "[" << CS() << "]*2\n;"
280                 "       _klen = " << CL() << "[" << CS() << "];\n"
281                 "       if ( _klen > 0 ) {\n"
282                 "               int _lower = _keys\n;"
283                 "               int _mid;\n"
284                 "               int _upper = _keys + (_klen<<1) - 2;\n"
285                 "               while (true) {\n"
286                 "                       if ( _upper < _lower )\n"
287                 "                               break;\n"
288                 "\n"
289                 "                       _mid = _lower + (((_upper-_lower) >> 1) & ~1);\n"
290                 "                       if ( " << GET_WIDE_KEY() << " < " << CK() << "[_mid] )\n"
291                 "                               _upper = _mid - 2;\n"
292                 "                       else if ( " << GET_WIDE_KEY() << " > " << CK() << "[_mid+1] )\n"
293                 "                               _lower = _mid + 2;\n"
294                 "                       else {\n"
295                 "                               switch ( " << C() << "[" << CO() << "[" << CS() << "]"
296                                                         " + ((_mid - _keys)>>1)] ) {\n"
297                 ;
298
299         for ( CondSpaceList::Iter csi = condSpaceList; csi.lte(); csi++ ) {
300                 GenCondSpace *condSpace = csi;
301                 out << "        case " << condSpace->condSpaceId << ": {\n";
302                 out << TABS(2) << "_widec = " << KEY(condSpace->baseKey) << 
303                                 " + (" << GET_KEY() << " - " << KEY(keyOps->minKey) << ");\n";
304
305                 for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
306                         out << TABS(2) << "if ( ";
307                         CONDITION( out, *csi );
308                         Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize());
309                         out << " ) _widec += " << condValOffset << ";\n";
310                 }
311
312                 out << 
313                         "               break;\n"
314                         "       }\n";
315         }
316
317         out << 
318                 "                               }\n"
319                 "                               break;\n"
320                 "                       }\n"
321                 "               }\n"
322                 "       }\n"
323                 "\n";
324 }
325
326
327 void JavaTabCodeGen::LOCATE_TRANS()
328 {
329         out <<
330                 "       _match: do {\n"
331                 "       _keys = " << KO() << "[" << CS() << "]" << ";\n"
332                 "       _trans = " << IO() << "[" << CS() << "];\n"
333                 "       _klen = " << SL() << "[" << CS() << "];\n"
334                 "       if ( _klen > 0 ) {\n"
335                 "               int _lower = _keys;\n"
336                 "               int _mid;\n"
337                 "               int _upper = _keys + _klen - 1;\n"
338                 "               while (true) {\n"
339                 "                       if ( _upper < _lower )\n"
340                 "                               break;\n"
341                 "\n"
342                 "                       _mid = _lower + ((_upper-_lower) >> 1);\n"
343                 "                       if ( " << GET_WIDE_KEY() << " < " << K() << "[_mid] )\n"
344                 "                               _upper = _mid - 1;\n"
345                 "                       else if ( " << GET_WIDE_KEY() << " > " << K() << "[_mid] )\n"
346                 "                               _lower = _mid + 1;\n"
347                 "                       else {\n"
348                 "                               _trans += (_mid - _keys);\n"
349                 "                               break _match;\n"
350                 "                       }\n"
351                 "               }\n"
352                 "               _keys += _klen;\n"
353                 "               _trans += _klen;\n"
354                 "       }\n"
355                 "\n"
356                 "       _klen = " << RL() << "[" << CS() << "];\n"
357                 "       if ( _klen > 0 ) {\n"
358                 "               int _lower = _keys;\n"
359                 "               int _mid;\n"
360                 "               int _upper = _keys + (_klen<<1) - 2;\n"
361                 "               while (true) {\n"
362                 "                       if ( _upper < _lower )\n"
363                 "                               break;\n"
364                 "\n"
365                 "                       _mid = _lower + (((_upper-_lower) >> 1) & ~1);\n"
366                 "                       if ( " << GET_WIDE_KEY() << " < " << K() << "[_mid] )\n"
367                 "                               _upper = _mid - 2;\n"
368                 "                       else if ( " << GET_WIDE_KEY() << " > " << K() << "[_mid+1] )\n"
369                 "                               _lower = _mid + 2;\n"
370                 "                       else {\n"
371                 "                               _trans += ((_mid - _keys)>>1);\n"
372                 "                               break _match;\n"
373                 "                       }\n"
374                 "               }\n"
375                 "               _trans += _klen;\n"
376                 "       }\n"
377                 "       } while (false);\n"
378                 "\n";
379 }
380
381 /* Determine if we should use indicies or not. */
382 void JavaTabCodeGen::calcIndexSize()
383 {
384         int sizeWithInds = 0, sizeWithoutInds = 0;
385
386         /* Calculate cost of using with indicies. */
387         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
388                 int totalIndex = st->outSingle.length() + st->outRange.length() + 
389                                 (st->defTrans == 0 ? 0 : 1);
390                 sizeWithInds += arrayTypeSize(redFsm->maxIndex) * totalIndex;
391         }
392         sizeWithInds += arrayTypeSize(redFsm->maxState) * redFsm->transSet.length();
393         if ( redFsm->anyActions() )
394                 sizeWithInds += arrayTypeSize(redFsm->maxActionLoc) * redFsm->transSet.length();
395
396         /* Calculate the cost of not using indicies. */
397         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
398                 int totalIndex = st->outSingle.length() + st->outRange.length() + 
399                                 (st->defTrans == 0 ? 0 : 1);
400                 sizeWithoutInds += arrayTypeSize(redFsm->maxState) * totalIndex;
401                 if ( redFsm->anyActions() )
402                         sizeWithoutInds += arrayTypeSize(redFsm->maxActionLoc) * totalIndex;
403         }
404
405         /* If using indicies reduces the size, use them. */
406         useIndicies = sizeWithInds < sizeWithoutInds;
407 }
408
409 int JavaTabCodeGen::TO_STATE_ACTION( RedStateAp *state )
410 {
411         int act = 0;
412         if ( state->toStateAction != 0 )
413                 act = state->toStateAction->location+1;
414         return act;
415 }
416
417 int JavaTabCodeGen::FROM_STATE_ACTION( RedStateAp *state )
418 {
419         int act = 0;
420         if ( state->fromStateAction != 0 )
421                 act = state->fromStateAction->location+1;
422         return act;
423 }
424
425 int JavaTabCodeGen::EOF_ACTION( RedStateAp *state )
426 {
427         int act = 0;
428         if ( state->eofAction != 0 )
429                 act = state->eofAction->location+1;
430         return act;
431 }
432
433
434 int JavaTabCodeGen::TRANS_ACTION( RedTransAp *trans )
435 {
436         /* If there are actions, emit them. Otherwise emit zero. */
437         int act = 0;
438         if ( trans->action != 0 )
439                 act = trans->action->location+1;
440         return act;
441 }
442
443 std::ostream &JavaTabCodeGen::TO_STATE_ACTION_SWITCH()
444 {
445         /* Walk the list of functions, printing the cases. */
446         for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
447                 /* Write out referenced actions. */
448                 if ( act->numToStateRefs > 0 ) {
449                         /* Write the case label, the action and the case break. */
450                         out << "\tcase " << act->actionId << ":\n";
451                         ACTION( out, act, 0, false );
452                         out << "\tbreak;\n";
453                 }
454         }
455
456         genLineDirective( out );
457         return out;
458 }
459
460 std::ostream &JavaTabCodeGen::FROM_STATE_ACTION_SWITCH()
461 {
462         /* Walk the list of functions, printing the cases. */
463         for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
464                 /* Write out referenced actions. */
465                 if ( act->numFromStateRefs > 0 ) {
466                         /* Write the case label, the action and the case break. */
467                         out << "\tcase " << act->actionId << ":\n";
468                         ACTION( out, act, 0, false );
469                         out << "\tbreak;\n";
470                 }
471         }
472
473         genLineDirective( out );
474         return out;
475 }
476
477 std::ostream &JavaTabCodeGen::EOF_ACTION_SWITCH()
478 {
479         /* Walk the list of functions, printing the cases. */
480         for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
481                 /* Write out referenced actions. */
482                 if ( act->numEofRefs > 0 ) {
483                         /* Write the case label, the action and the case break. */
484                         out << "\tcase " << act->actionId << ":\n";
485                         ACTION( out, act, 0, true );
486                         out << "\tbreak;\n";
487                 }
488         }
489
490         genLineDirective( out );
491         return out;
492 }
493
494
495 std::ostream &JavaTabCodeGen::ACTION_SWITCH()
496 {
497         /* Walk the list of functions, printing the cases. */
498         for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
499                 /* Write out referenced actions. */
500                 if ( act->numTransRefs > 0 ) {
501                         /* Write the case label, the action and the case break. */
502                         out << "\tcase " << act->actionId << ":\n";
503                         ACTION( out, act, 0, false );
504                         out << "\tbreak;\n";
505                 }
506         }
507
508         genLineDirective( out );
509         return out;
510 }
511
512 std::ostream &JavaTabCodeGen::COND_OFFSETS()
513 {
514         int curKeyOffset = 0;
515         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
516                 /* Write the key offset. */
517                 ARRAY_ITEM( INT(curKeyOffset), st.last() );
518
519                 /* Move the key offset ahead. */
520                 curKeyOffset += st->stateCondList.length();
521         }
522         return out;
523 }
524
525 std::ostream &JavaTabCodeGen::KEY_OFFSETS()
526 {
527         int curKeyOffset = 0;
528         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
529                 /* Write the key offset. */
530                 ARRAY_ITEM( INT(curKeyOffset), st.last() );
531
532                 /* Move the key offset ahead. */
533                 curKeyOffset += st->outSingle.length() + st->outRange.length()*2;
534         }
535         return out;
536 }
537
538
539 std::ostream &JavaTabCodeGen::INDEX_OFFSETS()
540 {
541         int curIndOffset = 0;
542         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
543                 /* Write the index offset. */
544                 ARRAY_ITEM( INT(curIndOffset), st.last() );
545
546                 /* Move the index offset ahead. */
547                 curIndOffset += st->outSingle.length() + st->outRange.length();
548                 if ( st->defTrans != 0 )
549                         curIndOffset += 1;
550         }
551         return out;
552 }
553
554 std::ostream &JavaTabCodeGen::COND_LENS()
555 {
556         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
557                 /* Write singles length. */
558                 ARRAY_ITEM( INT(st->stateCondList.length()), st.last() );
559         }
560         return out;
561 }
562
563
564 std::ostream &JavaTabCodeGen::SINGLE_LENS()
565 {
566         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
567                 /* Write singles length. */
568                 ARRAY_ITEM( INT(st->outSingle.length()), st.last() );
569         }
570         return out;
571 }
572
573 std::ostream &JavaTabCodeGen::RANGE_LENS()
574 {
575         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
576                 /* Emit length of range index. */
577                 ARRAY_ITEM( INT(st->outRange.length()), st.last() );
578         }
579         return out;
580 }
581
582 std::ostream &JavaTabCodeGen::TO_STATE_ACTIONS()
583 {
584         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
585                 /* Write any eof action. */
586                 ARRAY_ITEM( INT(TO_STATE_ACTION(st)), st.last() );
587         }
588         return out;
589 }
590
591 std::ostream &JavaTabCodeGen::FROM_STATE_ACTIONS()
592 {
593         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
594                 /* Write any eof action. */
595                 ARRAY_ITEM( INT(FROM_STATE_ACTION(st)), st.last() );
596         }
597         return out;
598 }
599
600 std::ostream &JavaTabCodeGen::EOF_ACTIONS()
601 {
602         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
603                 /* Write any eof action. */
604                 ARRAY_ITEM( INT(EOF_ACTION(st)), st.last() );
605         }
606         return out;
607 }
608
609 std::ostream &JavaTabCodeGen::EOF_TRANS()
610 {
611         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
612                 /* Write any eof action. */
613                 long trans = 0;
614                 if ( st->eofTrans != 0 ) {
615                         assert( st->eofTrans->pos >= 0 );
616                         trans = st->eofTrans->pos+1;
617                 }
618
619                 /* Write any eof action. */
620                 ARRAY_ITEM( INT(trans), st.last() );
621         }
622         return out;
623 }
624
625
626 std::ostream &JavaTabCodeGen::COND_KEYS()
627 {
628         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
629                 /* Loop the state's transitions. */
630                 for ( GenStateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
631                         /* Lower key. */
632                         ARRAY_ITEM( KEY( sc->lowKey ), false );
633                         ARRAY_ITEM( KEY( sc->highKey ), false );
634                 }
635         }
636
637         /* Output one last number so we don't have to figure out when the last
638          * entry is and avoid writing a comma. */
639         ARRAY_ITEM( INT(0), true );
640         return out;
641 }
642
643 std::ostream &JavaTabCodeGen::COND_SPACES()
644 {
645         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
646                 /* Loop the state's transitions. */
647                 for ( GenStateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
648                         /* Cond Space id. */
649                         ARRAY_ITEM( KEY( sc->condSpace->condSpaceId ), false );
650                 }
651         }
652
653         /* Output one last number so we don't have to figure out when the last
654          * entry is and avoid writing a comma. */
655         ARRAY_ITEM( INT(0), true );
656         return out;
657 }
658
659 std::ostream &JavaTabCodeGen::KEYS()
660 {
661         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
662                 /* Loop the singles. */
663                 for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
664                         ARRAY_ITEM( KEY( stel->lowKey ), false );
665                 }
666
667                 /* Loop the state's transitions. */
668                 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
669                         /* Lower key. */
670                         ARRAY_ITEM( KEY( rtel->lowKey ), false );
671
672                         /* Upper key. */
673                         ARRAY_ITEM( KEY( rtel->highKey ), false );
674                 }
675         }
676
677         /* Output one last number so we don't have to figure out when the last
678          * entry is and avoid writing a comma. */
679         ARRAY_ITEM( INT(0), true );
680         return out;
681 }
682
683 std::ostream &JavaTabCodeGen::INDICIES()
684 {
685         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
686                 /* Walk the singles. */
687                 for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
688                         ARRAY_ITEM( KEY( stel->value->id ), false );
689                 }
690
691                 /* Walk the ranges. */
692                 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
693                         ARRAY_ITEM( KEY( rtel->value->id ), false );
694                 }
695
696                 /* The state's default index goes next. */
697                 if ( st->defTrans != 0 ) {
698                         ARRAY_ITEM( KEY( st->defTrans->id ), false );
699                 }
700         }
701
702         /* Output one last number so we don't have to figure out when the last
703          * entry is and avoid writing a comma. */
704         ARRAY_ITEM( INT(0), true );
705         return out;
706 }
707
708 std::ostream &JavaTabCodeGen::TRANS_TARGS()
709 {
710         int totalTrans = 0;
711         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
712                 /* Walk the singles. */
713                 for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
714                         RedTransAp *trans = stel->value;
715                         ARRAY_ITEM( KEY( trans->targ->id ), false );
716                         totalTrans++;
717                 }
718
719                 /* Walk the ranges. */
720                 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
721                         RedTransAp *trans = rtel->value;
722                         ARRAY_ITEM( KEY( trans->targ->id ), false );
723                         totalTrans++;
724                 }
725
726                 /* The state's default target state. */
727                 if ( st->defTrans != 0 ) {
728                         RedTransAp *trans = st->defTrans;
729                         ARRAY_ITEM( KEY( trans->targ->id ), false );
730                         totalTrans++;
731                 }
732         }
733
734         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
735                 if ( st->eofTrans != 0 ) {
736                         RedTransAp *trans = st->eofTrans;
737                         trans->pos = totalTrans++;
738                         ARRAY_ITEM( KEY( trans->targ->id ), false );
739                 }
740         }
741
742         /* Output one last number so we don't have to figure out when the last
743          * entry is and avoid writing a comma. */
744         ARRAY_ITEM( INT(0), true );
745         return out;
746 }
747
748
749 std::ostream &JavaTabCodeGen::TRANS_ACTIONS()
750 {
751         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
752                 /* Walk the singles. */
753                 for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
754                         RedTransAp *trans = stel->value;
755                         ARRAY_ITEM( INT(TRANS_ACTION( trans )), false );
756                 }
757
758                 /* Walk the ranges. */
759                 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
760                         RedTransAp *trans = rtel->value;
761                         ARRAY_ITEM( INT(TRANS_ACTION( trans )), false );
762                 }
763
764                 /* The state's default index goes next. */
765                 if ( st->defTrans != 0 ) {
766                         RedTransAp *trans = st->defTrans;
767                         ARRAY_ITEM( INT(TRANS_ACTION( trans )), false );
768                 }
769         }
770
771         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
772                 if ( st->eofTrans != 0 ) {
773                         RedTransAp *trans = st->eofTrans;
774                         ARRAY_ITEM( INT(TRANS_ACTION( trans )), false );
775                 }
776         }
777
778         /* Output one last number so we don't have to figure out when the last
779          * entry is and avoid writing a comma. */
780         ARRAY_ITEM( INT(0), true );
781         return out;
782 }
783
784 std::ostream &JavaTabCodeGen::TRANS_TARGS_WI()
785 {
786         /* Transitions must be written ordered by their id. */
787         RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
788         for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
789                 transPtrs[trans->id] = trans;
790
791         /* Keep a count of the num of items in the array written. */
792         for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
793                 /* Save the position. Needed for eofTargs. */
794                 RedTransAp *trans = transPtrs[t];
795                 trans->pos = t;
796
797                 /* Write out the target state. */
798                 ARRAY_ITEM( INT(trans->targ->id), ( t >= redFsm->transSet.length()-1 ) );
799         }
800         delete[] transPtrs;
801         return out;
802 }
803
804
805 std::ostream &JavaTabCodeGen::TRANS_ACTIONS_WI()
806 {
807         /* Transitions must be written ordered by their id. */
808         RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
809         for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
810                 transPtrs[trans->id] = trans;
811
812         /* Keep a count of the num of items in the array written. */
813         for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
814                 /* Write the function for the transition. */
815                 RedTransAp *trans = transPtrs[t];
816                 ARRAY_ITEM( INT(TRANS_ACTION( trans )), ( t >= redFsm->transSet.length()-1 ) );
817         }
818         delete[] transPtrs;
819         return out;
820 }
821
822 void JavaTabCodeGen::writeExports()
823 {
824         if ( exportList.length() > 0 ) {
825                 for ( ExportList::Iter ex = exportList; ex.lte(); ex++ ) {
826                         STATIC_VAR( ALPH_TYPE(), DATA_PREFIX() + "ex_" + ex->name ) 
827                                         << " = " << KEY(ex->key) << ";\n";
828                 }
829                 out << "\n";
830         }
831 }
832
833 void JavaTabCodeGen::writeData()
834 {
835         /* If there are any transtion functions then output the array. If there
836          * are none, don't bother emitting an empty array that won't be used. */
837         if ( redFsm->anyActions() ) {
838                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
839                 ACTIONS_ARRAY();
840                 CLOSE_ARRAY() <<
841                 "\n";
842         }
843
844         if ( redFsm->anyConditions() ) {
845                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondOffset), CO() );
846                 COND_OFFSETS();
847                 CLOSE_ARRAY() <<
848                 "\n";
849
850                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondLen), CL() );
851                 COND_LENS();
852                 CLOSE_ARRAY() <<
853                 "\n";
854
855                 OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
856                 COND_KEYS();
857                 CLOSE_ARRAY() <<
858                 "\n";
859
860                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpaceId), C() );
861                 COND_SPACES();
862                 CLOSE_ARRAY() <<
863                 "\n";
864         }
865
866         OPEN_ARRAY( ARRAY_TYPE(redFsm->maxKeyOffset), KO() );
867         KEY_OFFSETS();
868         CLOSE_ARRAY() <<
869         "\n";
870
871         OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
872         KEYS();
873         CLOSE_ARRAY() <<
874         "\n";
875
876         OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSingleLen), SL() );
877         SINGLE_LENS();
878         CLOSE_ARRAY() <<
879         "\n";
880
881         OPEN_ARRAY( ARRAY_TYPE(redFsm->maxRangeLen), RL() );
882         RANGE_LENS();
883         CLOSE_ARRAY() <<
884         "\n";
885
886         OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset), IO() );
887         INDEX_OFFSETS();
888         CLOSE_ARRAY() <<
889         "\n";
890
891         if ( useIndicies ) {
892                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
893                 INDICIES();
894                 CLOSE_ARRAY() <<
895                 "\n";
896
897                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
898                 TRANS_TARGS_WI();
899                 CLOSE_ARRAY() <<
900                 "\n";
901
902                 if ( redFsm->anyActions() ) {
903                         OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
904                         TRANS_ACTIONS_WI();
905                         CLOSE_ARRAY() <<
906                         "\n";
907                 }
908         }
909         else {
910                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
911                 TRANS_TARGS();
912                 CLOSE_ARRAY() <<
913                 "\n";
914
915                 if ( redFsm->anyActions() ) {
916                         OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
917                         TRANS_ACTIONS();
918                         CLOSE_ARRAY() <<
919                         "\n";
920                 }
921         }
922
923         if ( redFsm->anyToStateActions() ) {
924                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
925                 TO_STATE_ACTIONS();
926                 CLOSE_ARRAY() <<
927                 "\n";
928         }
929
930         if ( redFsm->anyFromStateActions() ) {
931                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
932                 FROM_STATE_ACTIONS();
933                 CLOSE_ARRAY() <<
934                 "\n";
935         }
936
937         if ( redFsm->anyEofActions() ) {
938                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
939                 EOF_ACTIONS();
940                 CLOSE_ARRAY() <<
941                 "\n";
942         }
943
944         if ( redFsm->anyEofTrans() ) {
945                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset+1), ET() );
946                 EOF_TRANS();
947                 CLOSE_ARRAY() <<
948                 "\n";
949         }
950
951         if ( redFsm->startState != 0 )
952                 STATIC_VAR( "int", START() ) << " = " << START_STATE_ID() << ";\n";
953
954         if ( writeFirstFinal )
955                 STATIC_VAR( "int" , FIRST_FINAL() ) << " = " << FIRST_FINAL_STATE() << ";\n";
956
957         if ( writeErr )
958                 STATIC_VAR( "int", ERROR() ) << " = " << ERROR_STATE() << ";\n";
959         
960         out << "\n";
961
962         if ( entryPointNames.length() > 0 ) {
963                 for ( EntryNameVect::Iter en = entryPointNames; en.lte(); en++ ) {
964                         STATIC_VAR( "int", DATA_PREFIX() + "en_" + *en ) << 
965                                         " = " << entryPointIds[en.pos()] << ";\n";
966                 }
967                 out << "\n";
968         }
969 }
970
971 void JavaTabCodeGen::writeExec()
972 {
973         out <<
974                 "       {\n"
975                 "       int _klen";
976
977         if ( redFsm->anyRegCurStateRef() )
978                 out << ", _ps";
979
980         out << 
981                 ";\n"
982                 "       int _trans = 0;\n";
983
984         if ( redFsm->anyConditions() )
985                 out << "        int _widec;\n";
986
987         if ( redFsm->anyToStateActions() || redFsm->anyRegActions() || 
988                         redFsm->anyFromStateActions() )
989         {
990                 out << 
991                         "       int _acts;\n"
992                         "       int _nacts;\n";
993         }
994
995         out <<
996                 "       int _keys;\n"
997                 "       int _goto_targ = 0;\n"
998                 "\n";
999         
1000         out <<
1001                 "       _goto: while (true) {\n"
1002                 "       switch ( _goto_targ ) {\n"
1003                 "       case 0:\n";
1004
1005         if ( hasEnd ) {
1006                 out << 
1007                         "       if ( " << P() << " == " << PE() << " ) {\n"
1008                         "               _goto_targ = " << _test_eof << ";\n"
1009                         "               continue _goto;\n"
1010                         "       }\n";
1011         }
1012
1013         if ( redFsm->errState != 0 ) {
1014                 out << 
1015                         "       if ( " << CS() << " == " << redFsm->errState->id << " ) {\n"
1016                         "               _goto_targ = " << _out << ";\n"
1017                         "               continue _goto;\n"
1018                         "       }\n";
1019         }
1020
1021         out << "case " << _resume << ":\n"; 
1022
1023         if ( redFsm->anyFromStateActions() ) {
1024                 out <<
1025                         "       _acts = " << FSA() << "[" << CS() << "]" << ";\n"
1026                         "       _nacts = " << CAST("int") << " " << A() << "[_acts++];\n"
1027                         "       while ( _nacts-- > 0 ) {\n"
1028                         "               switch ( " << A() << "[_acts++] ) {\n";
1029                         FROM_STATE_ACTION_SWITCH() <<
1030                         "               }\n"
1031                         "       }\n"
1032                         "\n";
1033         }
1034
1035         if ( redFsm->anyConditions() )
1036                 COND_TRANSLATE();
1037
1038         LOCATE_TRANS();
1039
1040         if ( useIndicies )
1041                 out << "        _trans = " << I() << "[_trans];\n";
1042         
1043         if ( redFsm->anyEofTrans() )
1044                 out << "case " << _eof_trans << ":\n";
1045
1046         if ( redFsm->anyRegCurStateRef() )
1047                 out << "        _ps = " << CS() << ";\n";
1048
1049         out <<
1050                 "       " << CS() << " = " << TT() << "[_trans];\n"
1051                 "\n";
1052
1053         if ( redFsm->anyRegActions() ) {
1054                 out <<
1055                         "       if ( " << TA() << "[_trans] != 0 ) {\n"
1056                         "               _acts = " <<  TA() << "[_trans]" << ";\n"
1057                         "               _nacts = " << CAST("int") << " " <<  A() << "[_acts++];\n"
1058                         "               while ( _nacts-- > 0 )\n        {\n"
1059                         "                       switch ( " << A() << "[_acts++] )\n"
1060                         "                       {\n";
1061                         ACTION_SWITCH() <<
1062                         "                       }\n"
1063                         "               }\n"
1064                         "       }\n"
1065                         "\n";
1066         }
1067
1068         out << "case " << _again << ":\n";
1069
1070         if ( redFsm->anyToStateActions() ) {
1071                 out <<
1072                         "       _acts = " << TSA() << "[" << CS() << "]" << ";\n"
1073                         "       _nacts = " << CAST("int") << " " << A() << "[_acts++];\n"
1074                         "       while ( _nacts-- > 0 ) {\n"
1075                         "               switch ( " << A() << "[_acts++] ) {\n";
1076                         TO_STATE_ACTION_SWITCH() <<
1077                         "               }\n"
1078                         "       }\n"
1079                         "\n";
1080         }
1081
1082         if ( redFsm->errState != 0 ) {
1083                 out << 
1084                         "       if ( " << CS() << " == " << redFsm->errState->id << " ) {\n"
1085                         "               _goto_targ = " << _out << ";\n"
1086                         "               continue _goto;\n"
1087                         "       }\n";
1088         }
1089
1090         if ( hasEnd ) {
1091                 out << 
1092                         "       if ( ++" << P() << " != " << PE() << " ) {\n"
1093                         "               _goto_targ = " << _resume << ";\n"
1094                         "               continue _goto;\n"
1095                         "       }\n";
1096         }
1097         else {
1098                 out << 
1099                         "       " << P() << " += 1;\n"
1100                         "       _goto_targ = " << _resume << ";\n"
1101                         "       continue _goto;\n";
1102         }
1103
1104         out << "case " << _test_eof << ":\n"; 
1105
1106         if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
1107                 out <<
1108                         "       if ( " << P() << " == " << EOFV() << " )\n"
1109                         "       {\n";
1110
1111                 if ( redFsm->anyEofTrans() ) {
1112                         out <<
1113                                 "       if ( " << ET() << "[" << CS() << "] > 0 ) {\n"
1114                                 "               _trans = " << ET() << "[" << CS() << "] - 1;\n"
1115                                 "               _goto_targ = " << _eof_trans << ";\n"
1116                                 "               continue _goto;\n"
1117                                 "       }\n";
1118                 }
1119
1120                 if ( redFsm->anyEofActions() ) {
1121                         out <<
1122                                 "       int __acts = " << EA() << "[" << CS() << "]" << ";\n"
1123                                 "       int __nacts = " << CAST("int") << " " << A() << "[__acts++];\n"
1124                                 "       while ( __nacts-- > 0 ) {\n"
1125                                 "               switch ( " << A() << "[__acts++] ) {\n";
1126                                 EOF_ACTION_SWITCH() <<
1127                                 "               }\n"
1128                                 "       }\n";
1129                 }
1130
1131                 out <<
1132                         "       }\n"
1133                         "\n";
1134         }
1135
1136         out << "case " << _out << ":\n"; 
1137
1138         /* The switch and goto loop. */
1139         out << "        }\n";
1140         out << "        break; }\n";
1141
1142         /* The execute block. */
1143         out << "        }\n";
1144 }
1145
1146 std::ostream &JavaTabCodeGen::OPEN_ARRAY( string type, string name )
1147 {
1148         array_type = type;
1149         array_name = name;
1150         item_count = 0;
1151         div_count = 1;
1152
1153         out <<  "private static " << type << "[] init_" << name << "_0()\n"
1154                 "{\n\t"
1155                 "return new " << type << " [] {\n\t";
1156         return out;
1157 }
1158
1159 std::ostream &JavaTabCodeGen::ARRAY_ITEM( string item, bool last )
1160 {
1161         item_count++;
1162
1163         out << setw(5) << setiosflags(ios::right) << item;
1164         
1165         if ( !last ) {
1166                 if ( item_count % SAIIC == 0 ) {
1167                         out << "\n\t};\n};\n"
1168                                 "private static "<< array_type << "[] init_" << 
1169                                 array_name << "_" << div_count << "()\n"
1170                                 "{\n\t"
1171                                 "return new " << array_type << " [] {\n\t";
1172                         div_count++;
1173                 } else if (item_count % IALL == 0) { 
1174                         out << ",\n\t";
1175                 } else {
1176                         out << ",";
1177                 }
1178         }
1179         return out;
1180 }
1181
1182 std::ostream &JavaTabCodeGen::CLOSE_ARRAY()
1183 {
1184         out << "\n\t};\n}\n\n";
1185
1186         if (item_count < SAIIC) {
1187                 out << "private static final " << array_type << " " << array_name << 
1188                         "[] = init_" << array_name << "_0();\n\n";
1189         } else {
1190                 out << "private static final " << array_type << " [] combine_" << array_name
1191                         << "() {\n\t"
1192                         << array_type << " [] combined = new " << array_type << 
1193                         " [ " << item_count << " ];\n\t";
1194                 int block = 0;
1195                 int full_blocks = item_count / SAIIC;
1196                 for (;block < full_blocks; ++block) {
1197                         out << "System.arraycopy ( init_" << array_name << "_" << block << 
1198                                 "(), 0, combined, " << SAIIC * block << ", " << SAIIC << " );\n\t";
1199                 }
1200                 if ( (item_count % SAIIC) > 0 ) {
1201                         out << "System.arraycopy ( init_" << array_name << "_" << block << 
1202                                 "(), 0, combined, " << SAIIC * block << ", " << 
1203                                 (item_count % SAIIC) << " );\n\t";
1204                 }
1205                 out << "return combined;\n}\n";
1206                 out << "private static final " << array_type << " [] " << array_name << 
1207                         " = combine_" << array_name << "();";
1208         }
1209         return out;
1210 }
1211
1212
1213 std::ostream &JavaTabCodeGen::STATIC_VAR( string type, string name )
1214 {
1215         out << "static final " << type << " " << name;
1216         return out;
1217 }
1218
1219 string JavaTabCodeGen::ARR_OFF( string ptr, string offset )
1220 {
1221         return ptr + " + " + offset;
1222 }
1223
1224 string JavaTabCodeGen::CAST( string type )
1225 {
1226         return "(" + type + ")";
1227 }
1228
1229 string JavaTabCodeGen::NULL_ITEM()
1230 {
1231         /* In java we use integers instead of pointers. */
1232         return "-1";
1233 }
1234
1235 string JavaTabCodeGen::GET_KEY()
1236 {
1237         ostringstream ret;
1238         if ( getKeyExpr != 0 ) { 
1239                 /* Emit the user supplied method of retrieving the key. */
1240                 ret << "(";
1241                 INLINE_LIST( ret, getKeyExpr, 0, false );
1242                 ret << ")";
1243         }
1244         else {
1245                 /* Expression for retrieving the key, use simple dereference. */
1246                 ret << DATA() << "[" << P() << "]";
1247         }
1248         return ret.str();
1249 }
1250
1251 string JavaTabCodeGen::CTRL_FLOW()
1252 {
1253         return "if (true) ";
1254 }
1255
1256 unsigned int JavaTabCodeGen::arrayTypeSize( unsigned long maxVal )
1257 {
1258         long long maxValLL = (long long) maxVal;
1259         HostType *arrayType = keyOps->typeSubsumes( maxValLL );
1260         assert( arrayType != 0 );
1261         return arrayType->size;
1262 }
1263
1264 string JavaTabCodeGen::ARRAY_TYPE( unsigned long maxVal )
1265 {
1266         long long maxValLL = (long long) maxVal;
1267         HostType *arrayType = keyOps->typeSubsumes( maxValLL );
1268         assert( arrayType != 0 );
1269
1270         string ret = arrayType->data1;
1271         if ( arrayType->data2 != 0 ) {
1272                 ret += " ";
1273                 ret += arrayType->data2;
1274         }
1275         return ret;
1276 }
1277
1278
1279 /* Write out the fsm name. */
1280 string JavaTabCodeGen::FSM_NAME()
1281 {
1282         return fsmName;
1283 }
1284
1285 /* Emit the offset of the start state as a decimal integer. */
1286 string JavaTabCodeGen::START_STATE_ID()
1287 {
1288         ostringstream ret;
1289         ret << redFsm->startState->id;
1290         return ret.str();
1291 };
1292
1293 /* Write out the array of actions. */
1294 std::ostream &JavaTabCodeGen::ACTIONS_ARRAY()
1295 {
1296         ARRAY_ITEM( INT(0), false );
1297         for ( GenActionTableMap::Iter act = redFsm->actionMap; act.lte(); act++ ) {
1298                 /* Write out the length, which will never be the last character. */
1299                 ARRAY_ITEM( INT(act->key.length()), false );
1300
1301                 for ( GenActionTable::Iter item = act->key; item.lte(); item++ )
1302                         ARRAY_ITEM( INT(item->value->actionId), (act.last() && item.last()) );
1303         }
1304         return out;
1305 }
1306
1307
1308 string JavaTabCodeGen::ACCESS()
1309 {
1310         ostringstream ret;
1311         if ( accessExpr != 0 )
1312                 INLINE_LIST( ret, accessExpr, 0, false );
1313         return ret.str();
1314 }
1315
1316 string JavaTabCodeGen::P()
1317
1318         ostringstream ret;
1319         if ( pExpr == 0 )
1320                 ret << "p";
1321         else {
1322                 ret << "(";
1323                 INLINE_LIST( ret, pExpr, 0, false );
1324                 ret << ")";
1325         }
1326         return ret.str();
1327 }
1328
1329 string JavaTabCodeGen::PE()
1330 {
1331         ostringstream ret;
1332         if ( peExpr == 0 )
1333                 ret << "pe";
1334         else {
1335                 ret << "(";
1336                 INLINE_LIST( ret, peExpr, 0, false );
1337                 ret << ")";
1338         }
1339         return ret.str();
1340 }
1341
1342 string JavaTabCodeGen::EOFV()
1343 {
1344         ostringstream ret;
1345         if ( eofExpr == 0 )
1346                 ret << "eof";
1347         else {
1348                 ret << "(";
1349                 INLINE_LIST( ret, eofExpr, 0, false );
1350                 ret << ")";
1351         }
1352         return ret.str();
1353 }
1354
1355 string JavaTabCodeGen::CS()
1356 {
1357         ostringstream ret;
1358         if ( csExpr == 0 )
1359                 ret << ACCESS() << "cs";
1360         else {
1361                 /* Emit the user supplied method of retrieving the key. */
1362                 ret << "(";
1363                 INLINE_LIST( ret, csExpr, 0, false );
1364                 ret << ")";
1365         }
1366         return ret.str();
1367 }
1368
1369 string JavaTabCodeGen::TOP()
1370 {
1371         ostringstream ret;
1372         if ( topExpr == 0 )
1373                 ret << ACCESS() + "top";
1374         else {
1375                 ret << "(";
1376                 INLINE_LIST( ret, topExpr, 0, false );
1377                 ret << ")";
1378         }
1379         return ret.str();
1380 }
1381
1382 string JavaTabCodeGen::STACK()
1383 {
1384         ostringstream ret;
1385         if ( stackExpr == 0 )
1386                 ret << ACCESS() + "stack";
1387         else {
1388                 ret << "(";
1389                 INLINE_LIST( ret, stackExpr, 0, false );
1390                 ret << ")";
1391         }
1392         return ret.str();
1393 }
1394
1395 string JavaTabCodeGen::ACT()
1396 {
1397         ostringstream ret;
1398         if ( actExpr == 0 )
1399                 ret << ACCESS() + "act";
1400         else {
1401                 ret << "(";
1402                 INLINE_LIST( ret, actExpr, 0, false );
1403                 ret << ")";
1404         }
1405         return ret.str();
1406 }
1407
1408 string JavaTabCodeGen::TOKSTART()
1409 {
1410         ostringstream ret;
1411         if ( tokstartExpr == 0 )
1412                 ret << ACCESS() + "ts";
1413         else {
1414                 ret << "(";
1415                 INLINE_LIST( ret, tokstartExpr, 0, false );
1416                 ret << ")";
1417         }
1418         return ret.str();
1419 }
1420
1421 string JavaTabCodeGen::TOKEND()
1422 {
1423         ostringstream ret;
1424         if ( tokendExpr == 0 )
1425                 ret << ACCESS() + "te";
1426         else {
1427                 ret << "(";
1428                 INLINE_LIST( ret, tokendExpr, 0, false );
1429                 ret << ")";
1430         }
1431         return ret.str();
1432 }
1433
1434 string JavaTabCodeGen::DATA()
1435 {
1436         ostringstream ret;
1437         if ( dataExpr == 0 )
1438                 ret << ACCESS() + "data";
1439         else {
1440                 ret << "(";
1441                 INLINE_LIST( ret, dataExpr, 0, false );
1442                 ret << ")";
1443         }
1444         return ret.str();
1445 }
1446
1447
1448 string JavaTabCodeGen::GET_WIDE_KEY()
1449 {
1450         if ( redFsm->anyConditions() ) 
1451                 return "_widec";
1452         else
1453                 return GET_KEY();
1454 }
1455
1456 string JavaTabCodeGen::GET_WIDE_KEY( RedStateAp *state )
1457 {
1458         if ( state->stateCondList.length() > 0 )
1459                 return "_widec";
1460         else
1461                 return GET_KEY();
1462 }
1463
1464 /* Write out level number of tabs. Makes the nested binary search nice
1465  * looking. */
1466 string JavaTabCodeGen::TABS( int level )
1467 {
1468         string result;
1469         while ( level-- > 0 )
1470                 result += "\t";
1471         return result;
1472 }
1473
1474 string JavaTabCodeGen::KEY( Key key )
1475 {
1476         ostringstream ret;
1477         if ( keyOps->isSigned || !hostLang->explicitUnsigned )
1478                 ret << key.getVal();
1479         else
1480                 ret << (unsigned long) key.getVal();
1481         return ret.str();
1482 }
1483
1484 string JavaTabCodeGen::INT( int i )
1485 {
1486         ostringstream ret;
1487         ret << i;
1488         return ret.str();
1489 }
1490
1491 void JavaTabCodeGen::LM_SWITCH( ostream &ret, GenInlineItem *item, 
1492                 int targState, int inFinish )
1493 {
1494         ret << 
1495                 "       switch( " << ACT() << " ) {\n";
1496
1497         for ( GenInlineList::Iter lma = *item->children; lma.lte(); lma++ ) {
1498                 /* Write the case label, the action and the case break. */
1499                 if ( lma->lmId < 0 )
1500                         ret << "        default:\n";
1501                 else
1502                         ret << "        case " << lma->lmId << ":\n";
1503
1504                 /* Write the block and close it off. */
1505                 ret << "        {";
1506                 INLINE_LIST( ret, lma->children, targState, inFinish );
1507                 ret << "}\n";
1508
1509                 ret << "        break;\n";
1510         }
1511
1512         ret << 
1513                 "       }\n"
1514                 "\t";
1515 }
1516
1517 void JavaTabCodeGen::SET_ACT( ostream &ret, GenInlineItem *item )
1518 {
1519         ret << ACT() << " = " << item->lmId << ";";
1520 }
1521
1522 void JavaTabCodeGen::SET_TOKEND( ostream &ret, GenInlineItem *item )
1523 {
1524         /* The tokend action sets tokend. */
1525         ret << TOKEND() << " = " << P();
1526         if ( item->offset != 0 ) 
1527                 out << "+" << item->offset;
1528         out << ";";
1529 }
1530
1531 void JavaTabCodeGen::GET_TOKEND( ostream &ret, GenInlineItem *item )
1532 {
1533         ret << TOKEND();
1534 }
1535
1536 void JavaTabCodeGen::INIT_TOKSTART( ostream &ret, GenInlineItem *item )
1537 {
1538         ret << TOKSTART() << " = " << NULL_ITEM() << ";";
1539 }
1540
1541 void JavaTabCodeGen::INIT_ACT( ostream &ret, GenInlineItem *item )
1542 {
1543         ret << ACT() << " = 0;";
1544 }
1545
1546 void JavaTabCodeGen::SET_TOKSTART( ostream &ret, GenInlineItem *item )
1547 {
1548         ret << TOKSTART() << " = " << P() << ";";
1549 }
1550
1551 void JavaTabCodeGen::SUB_ACTION( ostream &ret, GenInlineItem *item, 
1552                 int targState, bool inFinish )
1553 {
1554         if ( item->children->length() > 0 ) {
1555                 /* Write the block and close it off. */
1556                 ret << "{";
1557                 INLINE_LIST( ret, item->children, targState, inFinish );
1558                 ret << "}";
1559         }
1560 }
1561
1562 void JavaTabCodeGen::ACTION( ostream &ret, GenAction *action, int targState, bool inFinish )
1563 {
1564         /* Write the preprocessor line info for going into the source file. */
1565         javaLineDirective( ret, sourceFileName, action->loc.line );
1566
1567         /* Write the block and close it off. */
1568         ret << "\t{";
1569         INLINE_LIST( ret, action->inlineList, targState, inFinish );
1570         ret << "}\n";
1571 }
1572
1573 void JavaTabCodeGen::CONDITION( ostream &ret, GenAction *condition )
1574 {
1575         ret << "\n";
1576         javaLineDirective( ret, sourceFileName, condition->loc.line );
1577         INLINE_LIST( ret, condition->inlineList, 0, false );
1578 }
1579
1580 string JavaTabCodeGen::ERROR_STATE()
1581 {
1582         ostringstream ret;
1583         if ( redFsm->errState != 0 )
1584                 ret << redFsm->errState->id;
1585         else
1586                 ret << "-1";
1587         return ret.str();
1588 }
1589
1590 string JavaTabCodeGen::FIRST_FINAL_STATE()
1591 {
1592         ostringstream ret;
1593         if ( redFsm->firstFinState != 0 )
1594                 ret << redFsm->firstFinState->id;
1595         else
1596                 ret << redFsm->nextStateId;
1597         return ret.str();
1598 }
1599
1600 void JavaTabCodeGen::writeInit()
1601 {
1602         out << "        {\n";
1603
1604         if ( writeCS )
1605                 out << "\t" << CS() << " = " << START() << ";\n";
1606         
1607         /* If there are any calls, then the stack top needs initialization. */
1608         if ( redFsm->anyActionCalls() || redFsm->anyActionRets() )
1609                 out << "\t" << TOP() << " = 0;\n";
1610
1611         if ( hasLongestMatch ) {
1612                 out << 
1613                         "       " << TOKSTART() << " = " << NULL_ITEM() << ";\n"
1614                         "       " << TOKEND() << " = " << NULL_ITEM() << ";\n"
1615                         "       " << ACT() << " = 0;\n";
1616         }
1617         out << "        }\n";
1618 }
1619
1620 void JavaTabCodeGen::finishRagelDef()
1621 {
1622         /* The frontend will do this for us, but it may be a good idea to force it
1623          * if the intermediate file is edited. */
1624         redFsm->sortByStateId();
1625
1626         /* Choose default transitions and the single transition. */
1627         redFsm->chooseDefaultSpan();
1628                 
1629         /* Maybe do flat expand, otherwise choose single. */
1630         redFsm->chooseSingle();
1631
1632         /* If any errors have occured in the input file then don't write anything. */
1633         if ( gblErrorCount > 0 )
1634                 return;
1635         
1636         /* Anlayze Machine will find the final action reference counts, among
1637          * other things. We will use these in reporting the usage
1638          * of fsm directives in action code. */
1639         analyzeMachine();
1640
1641         /* Determine if we should use indicies. */
1642         calcIndexSize();
1643 }
1644
1645 ostream &JavaTabCodeGen::source_warning( const GenInputLoc &loc )
1646 {
1647         cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": warning: ";
1648         return cerr;
1649 }
1650
1651 ostream &JavaTabCodeGen::source_error( const GenInputLoc &loc )
1652 {
1653         gblErrorCount += 1;
1654         assert( sourceFileName != 0 );
1655         cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": ";
1656         return cerr;
1657 }
1658
1659