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