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