2 * Copyright 2006-2007 Adrian Thurston <thurston@complang.org>
3 * 2007 Colin Fleming <colin.fleming@caverock.com>
6 /* This file is part of Ragel.
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.
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.
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
24 #include "javacodegen.h"
30 /* Integer array line length. */
33 /* Static array initialization item count
34 * (should be multiple of IALL). */
45 using std::ostringstream;
58 /* Invoked by the parser when the root element is opened. */
59 ostream *javaOpenOutput( const char *inputFile )
61 if ( hostLang->lang != HostLang::Java ) {
62 error() << "this code generator is for Java only" << endl;
66 /* If the output format is code and no output file name is given, then
68 if ( outputFileName == 0 ) {
69 const char *ext = findFileExtension( inputFile );
70 if ( ext != 0 && strcmp( ext, ".rh" ) == 0 )
71 outputFileName = fileNameFromStem( inputFile, ".h" );
73 outputFileName = fileNameFromStem( inputFile, ".java" );
76 /* Make sure we are not writing to the same file as the input file. */
77 if ( outputFileName != 0 && strcmp( inputFile, outputFileName ) == 0 ) {
78 error() << "output file \"" << outputFileName <<
79 "\" is the same as the input file" << endl;
82 if ( outputFileName != 0 ) {
83 /* Create the filter on the output and open it. */
84 outFilter = new output_filter( outputFileName );
85 outFilter->open( outputFileName, ios::out|ios::trunc );
86 if ( !outFilter->is_open() ) {
87 error() << "error opening " << outputFileName << " for writing" << endl;
91 /* Open the output stream, attaching it to the filter. */
92 outStream = new ostream( outFilter );
95 /* Writing out ot std out. */
101 /* Invoked by the parser when a ragel definition is opened. */
102 CodeGenData *javaMakeCodeGen( const char *sourceFileName, const char *fsmName,
103 ostream &out, bool wantComplete )
105 CodeGenData *codeGen = new JavaTabCodeGen(out);
107 codeGen->sourceFileName = sourceFileName;
108 codeGen->fsmName = fsmName;
109 codeGen->wantComplete = wantComplete;
114 void javaLineDirective( ostream &out, const char *fileName, int line )
116 /* Write the preprocessor line info for to the input file. */
117 out << "// line " << line << " \"";
118 for ( const char *pc = fileName; *pc != 0; pc++ ) {
127 void JavaTabCodeGen::genLineDirective( ostream &out )
129 std::streambuf *sbuf = out.rdbuf();
130 output_filter *filter = static_cast<output_filter*>(sbuf);
131 javaLineDirective( out, filter->fileName, filter->line + 1 );
134 void JavaTabCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
136 ret << "{" << CS() << " = " << gotoDest << "; _goto_targ = " << _again << "; " <<
137 CTRL_FLOW() << "continue _goto;}";
140 void JavaTabCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
142 ret << "{" << CS() << " = (";
143 INLINE_LIST( ret, ilItem->children, 0, inFinish );
144 ret << "); _goto_targ = " << _again << "; " << CTRL_FLOW() << "continue _goto;}";
147 void JavaTabCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
149 if ( prePushExpr != 0 ) {
151 INLINE_LIST( ret, prePushExpr, 0, false );
154 ret << "{" << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = " <<
155 callDest << "; _goto_targ = " << _again << "; " << CTRL_FLOW() << "continue _goto;}";
157 if ( prePushExpr != 0 )
161 void JavaTabCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish )
163 if ( prePushExpr != 0 ) {
165 INLINE_LIST( ret, prePushExpr, 0, false );
168 ret << "{" << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = (";
169 INLINE_LIST( ret, ilItem->children, targState, inFinish );
170 ret << "); _goto_targ = " << _again << "; " << CTRL_FLOW() << "continue _goto;}";
172 if ( prePushExpr != 0 )
176 void JavaTabCodeGen::RET( ostream &ret, bool inFinish )
178 ret << "{" << CS() << " = " << STACK() << "[--" << TOP() << "];";
180 if ( postPopExpr != 0 ) {
182 INLINE_LIST( ret, postPopExpr, 0, false );
186 ret << "_goto_targ = " << _again << "; " << CTRL_FLOW() << "continue _goto;}";
189 void JavaTabCodeGen::BREAK( ostream &ret, int targState )
191 ret << "{ " << P() << " += 1; _goto_targ = " << _out << "; " <<
192 CTRL_FLOW() << " continue _goto;}";
195 void JavaTabCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
197 ret << CS() << " = " << nextDest << ";";
200 void JavaTabCodeGen::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
202 ret << CS() << " = (";
203 INLINE_LIST( ret, ilItem->children, 0, inFinish );
207 void JavaTabCodeGen::EXEC( ostream &ret, GenInlineItem *item, int targState, int inFinish )
209 /* The parser gives fexec two children. The double brackets are for D
210 * code. If the inline list is a single word it will get interpreted as a
211 * C-style cast by the D compiler. */
212 ret << "{" << P() << " = ((";
213 INLINE_LIST( ret, item->children, targState, inFinish );
217 /* Write out an inline tree structure. Walks the list and possibly calls out
218 * to virtual functions than handle language specific items in the tree. */
219 void JavaTabCodeGen::INLINE_LIST( ostream &ret, GenInlineList *inlineList,
220 int targState, bool inFinish )
222 for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) {
223 switch ( item->type ) {
224 case GenInlineItem::Text:
227 case GenInlineItem::Goto:
228 GOTO( ret, item->targState->id, inFinish );
230 case GenInlineItem::Call:
231 CALL( ret, item->targState->id, targState, inFinish );
233 case GenInlineItem::Next:
234 NEXT( ret, item->targState->id, inFinish );
236 case GenInlineItem::Ret:
237 RET( ret, inFinish );
239 case GenInlineItem::PChar:
242 case GenInlineItem::Char:
245 case GenInlineItem::Hold:
248 case GenInlineItem::Exec:
249 EXEC( ret, item, targState, inFinish );
251 case GenInlineItem::Curs:
254 case GenInlineItem::Targs:
255 ret << "(" << CS() << ")";
257 case GenInlineItem::Entry:
258 ret << item->targState->id;
260 case GenInlineItem::GotoExpr:
261 GOTO_EXPR( ret, item, inFinish );
263 case GenInlineItem::CallExpr:
264 CALL_EXPR( ret, item, targState, inFinish );
266 case GenInlineItem::NextExpr:
267 NEXT_EXPR( ret, item, inFinish );
269 case GenInlineItem::LmSwitch:
270 LM_SWITCH( ret, item, targState, inFinish );
272 case GenInlineItem::LmSetActId:
273 SET_ACT( ret, item );
275 case GenInlineItem::LmSetTokEnd:
276 SET_TOKEND( ret, item );
278 case GenInlineItem::LmGetTokEnd:
279 GET_TOKEND( ret, item );
281 case GenInlineItem::LmInitTokStart:
282 INIT_TOKSTART( ret, item );
284 case GenInlineItem::LmInitAct:
285 INIT_ACT( ret, item );
287 case GenInlineItem::LmSetTokStart:
288 SET_TOKSTART( ret, item );
290 case GenInlineItem::SubAction:
291 SUB_ACTION( ret, item, targState, inFinish );
293 case GenInlineItem::Break:
294 BREAK( ret, targState );
300 string JavaTabCodeGen::DATA_PREFIX()
303 return FSM_NAME() + "_";
307 /* Emit the alphabet data type. */
308 string JavaTabCodeGen::ALPH_TYPE()
310 string ret = keyOps->alphType->data1;
311 if ( keyOps->alphType->data2 != 0 ) {
313 ret += + keyOps->alphType->data2;
318 /* Emit the alphabet data type. */
319 string JavaTabCodeGen::WIDE_ALPH_TYPE()
322 if ( redFsm->maxKey <= keyOps->maxKey )
325 long long maxKeyVal = redFsm->maxKey.getLongLong();
326 HostType *wideType = keyOps->typeSubsumes( keyOps->isSigned, maxKeyVal );
327 assert( wideType != 0 );
329 ret = wideType->data1;
330 if ( wideType->data2 != 0 ) {
332 ret += wideType->data2;
340 void JavaTabCodeGen::COND_TRANSLATE()
343 " _widec = " << GET_KEY() << ";\n"
344 " _keys = " << CO() << "[" << CS() << "]*2\n;"
345 " _klen = " << CL() << "[" << CS() << "];\n"
346 " if ( _klen > 0 ) {\n"
347 " int _lower = _keys\n;"
349 " int _upper = _keys + (_klen<<1) - 2;\n"
351 " if ( _upper < _lower )\n"
354 " _mid = _lower + (((_upper-_lower) >> 1) & ~1);\n"
355 " if ( " << GET_WIDE_KEY() << " < " << CK() << "[_mid] )\n"
356 " _upper = _mid - 2;\n"
357 " else if ( " << GET_WIDE_KEY() << " > " << CK() << "[_mid+1] )\n"
358 " _lower = _mid + 2;\n"
360 " switch ( " << C() << "[" << CO() << "[" << CS() << "]"
361 " + ((_mid - _keys)>>1)] ) {\n"
364 for ( CondSpaceList::Iter csi = condSpaceList; csi.lte(); csi++ ) {
365 GenCondSpace *condSpace = csi;
366 out << " case " << condSpace->condSpaceId << ": {\n";
367 out << TABS(2) << "_widec = " << KEY(condSpace->baseKey) <<
368 " + (" << GET_KEY() << " - " << KEY(keyOps->minKey) << ");\n";
370 for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
371 out << TABS(2) << "if ( ";
372 CONDITION( out, *csi );
373 Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize());
374 out << " ) _widec += " << condValOffset << ";\n";
392 void JavaTabCodeGen::LOCATE_TRANS()
396 " _keys = " << KO() << "[" << CS() << "]" << ";\n"
397 " _trans = " << IO() << "[" << CS() << "];\n"
398 " _klen = " << SL() << "[" << CS() << "];\n"
399 " if ( _klen > 0 ) {\n"
400 " int _lower = _keys;\n"
402 " int _upper = _keys + _klen - 1;\n"
404 " if ( _upper < _lower )\n"
407 " _mid = _lower + ((_upper-_lower) >> 1);\n"
408 " if ( " << GET_WIDE_KEY() << " < " << K() << "[_mid] )\n"
409 " _upper = _mid - 1;\n"
410 " else if ( " << GET_WIDE_KEY() << " > " << K() << "[_mid] )\n"
411 " _lower = _mid + 1;\n"
413 " _trans += (_mid - _keys);\n"
418 " _trans += _klen;\n"
421 " _klen = " << RL() << "[" << CS() << "];\n"
422 " if ( _klen > 0 ) {\n"
423 " int _lower = _keys;\n"
425 " int _upper = _keys + (_klen<<1) - 2;\n"
427 " if ( _upper < _lower )\n"
430 " _mid = _lower + (((_upper-_lower) >> 1) & ~1);\n"
431 " if ( " << GET_WIDE_KEY() << " < " << K() << "[_mid] )\n"
432 " _upper = _mid - 2;\n"
433 " else if ( " << GET_WIDE_KEY() << " > " << K() << "[_mid+1] )\n"
434 " _lower = _mid + 2;\n"
436 " _trans += ((_mid - _keys)>>1);\n"
440 " _trans += _klen;\n"
442 " } while (false);\n"
446 /* Determine if we should use indicies or not. */
447 void JavaTabCodeGen::calcIndexSize()
449 int sizeWithInds = 0, sizeWithoutInds = 0;
451 /* Calculate cost of using with indicies. */
452 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
453 int totalIndex = st->outSingle.length() + st->outRange.length() +
454 (st->defTrans == 0 ? 0 : 1);
455 sizeWithInds += arrayTypeSize(redFsm->maxIndex) * totalIndex;
457 sizeWithInds += arrayTypeSize(redFsm->maxState) * redFsm->transSet.length();
458 if ( redFsm->anyActions() )
459 sizeWithInds += arrayTypeSize(redFsm->maxActionLoc) * redFsm->transSet.length();
461 /* Calculate the cost of not using indicies. */
462 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
463 int totalIndex = st->outSingle.length() + st->outRange.length() +
464 (st->defTrans == 0 ? 0 : 1);
465 sizeWithoutInds += arrayTypeSize(redFsm->maxState) * totalIndex;
466 if ( redFsm->anyActions() )
467 sizeWithoutInds += arrayTypeSize(redFsm->maxActionLoc) * totalIndex;
470 /* If using indicies reduces the size, use them. */
471 useIndicies = sizeWithInds < sizeWithoutInds;
474 int JavaTabCodeGen::TO_STATE_ACTION( RedStateAp *state )
477 if ( state->toStateAction != 0 )
478 act = state->toStateAction->location+1;
482 int JavaTabCodeGen::FROM_STATE_ACTION( RedStateAp *state )
485 if ( state->fromStateAction != 0 )
486 act = state->fromStateAction->location+1;
490 int JavaTabCodeGen::EOF_ACTION( RedStateAp *state )
493 if ( state->eofAction != 0 )
494 act = state->eofAction->location+1;
499 int JavaTabCodeGen::TRANS_ACTION( RedTransAp *trans )
501 /* If there are actions, emit them. Otherwise emit zero. */
503 if ( trans->action != 0 )
504 act = trans->action->location+1;
508 std::ostream &JavaTabCodeGen::TO_STATE_ACTION_SWITCH()
510 /* Walk the list of functions, printing the cases. */
511 for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
512 /* Write out referenced actions. */
513 if ( act->numToStateRefs > 0 ) {
514 /* Write the case label, the action and the case break. */
515 out << "\tcase " << act->actionId << ":\n";
516 ACTION( out, act, 0, false );
521 genLineDirective( out );
525 std::ostream &JavaTabCodeGen::FROM_STATE_ACTION_SWITCH()
527 /* Walk the list of functions, printing the cases. */
528 for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
529 /* Write out referenced actions. */
530 if ( act->numFromStateRefs > 0 ) {
531 /* Write the case label, the action and the case break. */
532 out << "\tcase " << act->actionId << ":\n";
533 ACTION( out, act, 0, false );
538 genLineDirective( out );
542 std::ostream &JavaTabCodeGen::EOF_ACTION_SWITCH()
544 /* Walk the list of functions, printing the cases. */
545 for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
546 /* Write out referenced actions. */
547 if ( act->numEofRefs > 0 ) {
548 /* Write the case label, the action and the case break. */
549 out << "\tcase " << act->actionId << ":\n";
550 ACTION( out, act, 0, true );
555 genLineDirective( out );
560 std::ostream &JavaTabCodeGen::ACTION_SWITCH()
562 /* Walk the list of functions, printing the cases. */
563 for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
564 /* Write out referenced actions. */
565 if ( act->numTransRefs > 0 ) {
566 /* Write the case label, the action and the case break. */
567 out << "\tcase " << act->actionId << ":\n";
568 ACTION( out, act, 0, false );
573 genLineDirective( out );
577 std::ostream &JavaTabCodeGen::COND_OFFSETS()
579 int curKeyOffset = 0;
580 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
581 /* Write the key offset. */
582 ARRAY_ITEM( INT(curKeyOffset), st.last() );
584 /* Move the key offset ahead. */
585 curKeyOffset += st->stateCondList.length();
590 std::ostream &JavaTabCodeGen::KEY_OFFSETS()
592 int curKeyOffset = 0;
593 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
594 /* Write the key offset. */
595 ARRAY_ITEM( INT(curKeyOffset), st.last() );
597 /* Move the key offset ahead. */
598 curKeyOffset += st->outSingle.length() + st->outRange.length()*2;
604 std::ostream &JavaTabCodeGen::INDEX_OFFSETS()
606 int curIndOffset = 0;
607 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
608 /* Write the index offset. */
609 ARRAY_ITEM( INT(curIndOffset), st.last() );
611 /* Move the index offset ahead. */
612 curIndOffset += st->outSingle.length() + st->outRange.length();
613 if ( st->defTrans != 0 )
619 std::ostream &JavaTabCodeGen::COND_LENS()
621 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
622 /* Write singles length. */
623 ARRAY_ITEM( INT(st->stateCondList.length()), st.last() );
629 std::ostream &JavaTabCodeGen::SINGLE_LENS()
631 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
632 /* Write singles length. */
633 ARRAY_ITEM( INT(st->outSingle.length()), st.last() );
638 std::ostream &JavaTabCodeGen::RANGE_LENS()
640 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
641 /* Emit length of range index. */
642 ARRAY_ITEM( INT(st->outRange.length()), st.last() );
647 std::ostream &JavaTabCodeGen::TO_STATE_ACTIONS()
649 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
650 /* Write any eof action. */
651 ARRAY_ITEM( INT(TO_STATE_ACTION(st)), st.last() );
656 std::ostream &JavaTabCodeGen::FROM_STATE_ACTIONS()
658 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
659 /* Write any eof action. */
660 ARRAY_ITEM( INT(FROM_STATE_ACTION(st)), st.last() );
665 std::ostream &JavaTabCodeGen::EOF_ACTIONS()
667 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
668 /* Write any eof action. */
669 ARRAY_ITEM( INT(EOF_ACTION(st)), st.last() );
674 std::ostream &JavaTabCodeGen::EOF_TRANS()
676 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
677 /* Write any eof action. */
679 if ( st->eofTrans != 0 ) {
680 assert( st->eofTrans->pos >= 0 );
681 trans = st->eofTrans->pos+1;
684 /* Write any eof action. */
685 ARRAY_ITEM( INT(trans), st.last() );
691 std::ostream &JavaTabCodeGen::COND_KEYS()
693 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
694 /* Loop the state's transitions. */
695 for ( GenStateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
697 ARRAY_ITEM( KEY( sc->lowKey ), false );
698 ARRAY_ITEM( KEY( sc->highKey ), false );
702 /* Output one last number so we don't have to figure out when the last
703 * entry is and avoid writing a comma. */
704 ARRAY_ITEM( INT(0), true );
708 std::ostream &JavaTabCodeGen::COND_SPACES()
710 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
711 /* Loop the state's transitions. */
712 for ( GenStateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
714 ARRAY_ITEM( KEY( sc->condSpace->condSpaceId ), false );
718 /* Output one last number so we don't have to figure out when the last
719 * entry is and avoid writing a comma. */
720 ARRAY_ITEM( INT(0), true );
724 std::ostream &JavaTabCodeGen::KEYS()
726 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
727 /* Loop the singles. */
728 for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
729 ARRAY_ITEM( KEY( stel->lowKey ), false );
732 /* Loop the state's transitions. */
733 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
735 ARRAY_ITEM( KEY( rtel->lowKey ), false );
738 ARRAY_ITEM( KEY( rtel->highKey ), false );
742 /* Output one last number so we don't have to figure out when the last
743 * entry is and avoid writing a comma. */
744 ARRAY_ITEM( INT(0), true );
748 std::ostream &JavaTabCodeGen::INDICIES()
750 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
751 /* Walk the singles. */
752 for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
753 ARRAY_ITEM( KEY( stel->value->id ), false );
756 /* Walk the ranges. */
757 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
758 ARRAY_ITEM( KEY( rtel->value->id ), false );
761 /* The state's default index goes next. */
762 if ( st->defTrans != 0 ) {
763 ARRAY_ITEM( KEY( st->defTrans->id ), false );
767 /* Output one last number so we don't have to figure out when the last
768 * entry is and avoid writing a comma. */
769 ARRAY_ITEM( INT(0), true );
773 std::ostream &JavaTabCodeGen::TRANS_TARGS()
776 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
777 /* Walk the singles. */
778 for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
779 RedTransAp *trans = stel->value;
780 ARRAY_ITEM( KEY( trans->targ->id ), false );
784 /* Walk the ranges. */
785 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
786 RedTransAp *trans = rtel->value;
787 ARRAY_ITEM( KEY( trans->targ->id ), false );
791 /* The state's default target state. */
792 if ( st->defTrans != 0 ) {
793 RedTransAp *trans = st->defTrans;
794 ARRAY_ITEM( KEY( trans->targ->id ), false );
799 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
800 if ( st->eofTrans != 0 ) {
801 RedTransAp *trans = st->eofTrans;
802 trans->pos = totalTrans++;
803 ARRAY_ITEM( KEY( trans->targ->id ), false );
807 /* Output one last number so we don't have to figure out when the last
808 * entry is and avoid writing a comma. */
809 ARRAY_ITEM( INT(0), true );
814 std::ostream &JavaTabCodeGen::TRANS_ACTIONS()
816 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
817 /* Walk the singles. */
818 for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
819 RedTransAp *trans = stel->value;
820 ARRAY_ITEM( INT(TRANS_ACTION( trans )), false );
823 /* Walk the ranges. */
824 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
825 RedTransAp *trans = rtel->value;
826 ARRAY_ITEM( INT(TRANS_ACTION( trans )), false );
829 /* The state's default index goes next. */
830 if ( st->defTrans != 0 ) {
831 RedTransAp *trans = st->defTrans;
832 ARRAY_ITEM( INT(TRANS_ACTION( trans )), false );
836 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
837 if ( st->eofTrans != 0 ) {
838 RedTransAp *trans = st->eofTrans;
839 ARRAY_ITEM( INT(TRANS_ACTION( trans )), false );
843 /* Output one last number so we don't have to figure out when the last
844 * entry is and avoid writing a comma. */
845 ARRAY_ITEM( INT(0), true );
849 std::ostream &JavaTabCodeGen::TRANS_TARGS_WI()
851 /* Transitions must be written ordered by their id. */
852 RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
853 for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
854 transPtrs[trans->id] = trans;
856 /* Keep a count of the num of items in the array written. */
857 for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
858 /* Save the position. Needed for eofTargs. */
859 RedTransAp *trans = transPtrs[t];
862 /* Write out the target state. */
863 ARRAY_ITEM( INT(trans->targ->id), ( t >= redFsm->transSet.length()-1 ) );
870 std::ostream &JavaTabCodeGen::TRANS_ACTIONS_WI()
872 /* Transitions must be written ordered by their id. */
873 RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
874 for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
875 transPtrs[trans->id] = trans;
877 /* Keep a count of the num of items in the array written. */
878 for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
879 /* Write the function for the transition. */
880 RedTransAp *trans = transPtrs[t];
881 ARRAY_ITEM( INT(TRANS_ACTION( trans )), ( t >= redFsm->transSet.length()-1 ) );
887 void JavaTabCodeGen::writeExports()
889 if ( exportList.length() > 0 ) {
890 for ( ExportList::Iter ex = exportList; ex.lte(); ex++ ) {
891 STATIC_VAR( ALPH_TYPE(), DATA_PREFIX() + "ex_" + ex->name )
892 << " = " << KEY(ex->key) << ";\n";
898 void JavaTabCodeGen::writeStart()
900 out << START_STATE_ID();
903 void JavaTabCodeGen::writeFirstFinal()
905 out << FIRST_FINAL_STATE();
908 void JavaTabCodeGen::writeError()
910 out << ERROR_STATE();
913 void JavaTabCodeGen::writeData()
915 /* If there are any transtion functions then output the array. If there
916 * are none, don't bother emitting an empty array that won't be used. */
917 if ( redFsm->anyActions() ) {
918 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
924 if ( redFsm->anyConditions() ) {
925 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondOffset), CO() );
930 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondLen), CL() );
935 OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
940 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpaceId), C() );
946 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxKeyOffset), KO() );
951 OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
956 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSingleLen), SL() );
961 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxRangeLen), RL() );
966 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset), IO() );
972 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
977 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
982 if ( redFsm->anyActions() ) {
983 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
990 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
995 if ( redFsm->anyActions() ) {
996 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
1003 if ( redFsm->anyToStateActions() ) {
1004 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
1010 if ( redFsm->anyFromStateActions() ) {
1011 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
1012 FROM_STATE_ACTIONS();
1017 if ( redFsm->anyEofActions() ) {
1018 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
1024 if ( redFsm->anyEofTrans() ) {
1025 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset+1), ET() );
1031 if ( redFsm->startState != 0 )
1032 STATIC_VAR( "int", START() ) << " = " << START_STATE_ID() << ";\n";
1035 STATIC_VAR( "int" , FIRST_FINAL() ) << " = " << FIRST_FINAL_STATE() << ";\n";
1038 STATIC_VAR( "int", ERROR() ) << " = " << ERROR_STATE() << ";\n";
1042 if ( entryPointNames.length() > 0 ) {
1043 for ( EntryNameVect::Iter en = entryPointNames; en.lte(); en++ ) {
1044 STATIC_VAR( "int", DATA_PREFIX() + "en_" + *en ) <<
1045 " = " << entryPointIds[en.pos()] << ";\n";
1051 void JavaTabCodeGen::writeExec()
1057 if ( redFsm->anyRegCurStateRef() )
1062 " int _trans = 0;\n";
1064 if ( redFsm->anyConditions() )
1065 out << " int _widec;\n";
1067 if ( redFsm->anyToStateActions() || redFsm->anyRegActions() ||
1068 redFsm->anyFromStateActions() )
1077 " int _goto_targ = 0;\n"
1081 " _goto: while (true) {\n"
1082 " switch ( _goto_targ ) {\n"
1087 " if ( " << P() << " == " << PE() << " ) {\n"
1088 " _goto_targ = " << _test_eof << ";\n"
1089 " continue _goto;\n"
1093 if ( redFsm->errState != 0 ) {
1095 " if ( " << CS() << " == " << redFsm->errState->id << " ) {\n"
1096 " _goto_targ = " << _out << ";\n"
1097 " continue _goto;\n"
1101 out << "case " << _resume << ":\n";
1103 if ( redFsm->anyFromStateActions() ) {
1105 " _acts = " << FSA() << "[" << CS() << "]" << ";\n"
1106 " _nacts = " << CAST("int") << " " << A() << "[_acts++];\n"
1107 " while ( _nacts-- > 0 ) {\n"
1108 " switch ( " << A() << "[_acts++] ) {\n";
1109 FROM_STATE_ACTION_SWITCH() <<
1115 if ( redFsm->anyConditions() )
1121 out << " _trans = " << I() << "[_trans];\n";
1123 if ( redFsm->anyEofTrans() )
1124 out << "case " << _eof_trans << ":\n";
1126 if ( redFsm->anyRegCurStateRef() )
1127 out << " _ps = " << CS() << ";\n";
1130 " " << CS() << " = " << TT() << "[_trans];\n"
1133 if ( redFsm->anyRegActions() ) {
1135 " if ( " << TA() << "[_trans] != 0 ) {\n"
1136 " _acts = " << TA() << "[_trans]" << ";\n"
1137 " _nacts = " << CAST("int") << " " << A() << "[_acts++];\n"
1138 " while ( _nacts-- > 0 )\n {\n"
1139 " switch ( " << A() << "[_acts++] )\n"
1148 out << "case " << _again << ":\n";
1150 if ( redFsm->anyToStateActions() ) {
1152 " _acts = " << TSA() << "[" << CS() << "]" << ";\n"
1153 " _nacts = " << CAST("int") << " " << A() << "[_acts++];\n"
1154 " while ( _nacts-- > 0 ) {\n"
1155 " switch ( " << A() << "[_acts++] ) {\n";
1156 TO_STATE_ACTION_SWITCH() <<
1162 if ( redFsm->errState != 0 ) {
1164 " if ( " << CS() << " == " << redFsm->errState->id << " ) {\n"
1165 " _goto_targ = " << _out << ";\n"
1166 " continue _goto;\n"
1172 " if ( ++" << P() << " != " << PE() << " ) {\n"
1173 " _goto_targ = " << _resume << ";\n"
1174 " continue _goto;\n"
1179 " " << P() << " += 1;\n"
1180 " _goto_targ = " << _resume << ";\n"
1181 " continue _goto;\n";
1184 out << "case " << _test_eof << ":\n";
1186 if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
1188 " if ( " << P() << " == " << EOFV() << " )\n"
1191 if ( redFsm->anyEofTrans() ) {
1193 " if ( " << ET() << "[" << CS() << "] > 0 ) {\n"
1194 " _trans = " << ET() << "[" << CS() << "] - 1;\n"
1195 " _goto_targ = " << _eof_trans << ";\n"
1196 " continue _goto;\n"
1200 if ( redFsm->anyEofActions() ) {
1202 " int __acts = " << EA() << "[" << CS() << "]" << ";\n"
1203 " int __nacts = " << CAST("int") << " " << A() << "[__acts++];\n"
1204 " while ( __nacts-- > 0 ) {\n"
1205 " switch ( " << A() << "[__acts++] ) {\n";
1206 EOF_ACTION_SWITCH() <<
1216 out << "case " << _out << ":\n";
1218 /* The switch and goto loop. */
1220 out << " break; }\n";
1222 /* The execute block. */
1226 std::ostream &JavaTabCodeGen::OPEN_ARRAY( string type, string name )
1233 out << "private static " << type << "[] init_" << name << "_0()\n"
1235 "return new " << type << " [] {\n\t";
1239 std::ostream &JavaTabCodeGen::ARRAY_ITEM( string item, bool last )
1243 out << setw(5) << setiosflags(ios::right) << item;
1246 if ( item_count % SAIIC == 0 ) {
1247 out << "\n\t};\n};\n"
1248 "private static "<< array_type << "[] init_" <<
1249 array_name << "_" << div_count << "()\n"
1251 "return new " << array_type << " [] {\n\t";
1253 } else if (item_count % IALL == 0) {
1262 std::ostream &JavaTabCodeGen::CLOSE_ARRAY()
1264 out << "\n\t};\n}\n\n";
1266 if (item_count < SAIIC) {
1267 out << "private static final " << array_type << " " << array_name <<
1268 "[] = init_" << array_name << "_0();\n\n";
1270 out << "private static final " << array_type << " [] combine_" << array_name
1272 << array_type << " [] combined = new " << array_type <<
1273 " [ " << item_count << " ];\n\t";
1275 int full_blocks = item_count / SAIIC;
1276 for (;block < full_blocks; ++block) {
1277 out << "System.arraycopy ( init_" << array_name << "_" << block <<
1278 "(), 0, combined, " << SAIIC * block << ", " << SAIIC << " );\n\t";
1280 if ( (item_count % SAIIC) > 0 ) {
1281 out << "System.arraycopy ( init_" << array_name << "_" << block <<
1282 "(), 0, combined, " << SAIIC * block << ", " <<
1283 (item_count % SAIIC) << " );\n\t";
1285 out << "return combined;\n}\n";
1286 out << "private static final " << array_type << " [] " << array_name <<
1287 " = combine_" << array_name << "();";
1293 std::ostream &JavaTabCodeGen::STATIC_VAR( string type, string name )
1295 out << "static final " << type << " " << name;
1299 string JavaTabCodeGen::ARR_OFF( string ptr, string offset )
1301 return ptr + " + " + offset;
1304 string JavaTabCodeGen::CAST( string type )
1306 return "(" + type + ")";
1309 string JavaTabCodeGen::NULL_ITEM()
1311 /* In java we use integers instead of pointers. */
1315 string JavaTabCodeGen::GET_KEY()
1318 if ( getKeyExpr != 0 ) {
1319 /* Emit the user supplied method of retrieving the key. */
1321 INLINE_LIST( ret, getKeyExpr, 0, false );
1325 /* Expression for retrieving the key, use simple dereference. */
1326 ret << DATA() << "[" << P() << "]";
1331 string JavaTabCodeGen::CTRL_FLOW()
1333 return "if (true) ";
1336 unsigned int JavaTabCodeGen::arrayTypeSize( unsigned long maxVal )
1338 long long maxValLL = (long long) maxVal;
1339 HostType *arrayType = keyOps->typeSubsumes( maxValLL );
1340 assert( arrayType != 0 );
1341 return arrayType->size;
1344 string JavaTabCodeGen::ARRAY_TYPE( unsigned long maxVal )
1346 long long maxValLL = (long long) maxVal;
1347 HostType *arrayType = keyOps->typeSubsumes( maxValLL );
1348 assert( arrayType != 0 );
1350 string ret = arrayType->data1;
1351 if ( arrayType->data2 != 0 ) {
1353 ret += arrayType->data2;
1359 /* Write out the fsm name. */
1360 string JavaTabCodeGen::FSM_NAME()
1365 /* Emit the offset of the start state as a decimal integer. */
1366 string JavaTabCodeGen::START_STATE_ID()
1369 ret << redFsm->startState->id;
1373 /* Write out the array of actions. */
1374 std::ostream &JavaTabCodeGen::ACTIONS_ARRAY()
1376 ARRAY_ITEM( INT(0), false );
1377 for ( GenActionTableMap::Iter act = redFsm->actionMap; act.lte(); act++ ) {
1378 /* Write out the length, which will never be the last character. */
1379 ARRAY_ITEM( INT(act->key.length()), false );
1381 for ( GenActionTable::Iter item = act->key; item.lte(); item++ )
1382 ARRAY_ITEM( INT(item->value->actionId), (act.last() && item.last()) );
1388 string JavaTabCodeGen::ACCESS()
1391 if ( accessExpr != 0 )
1392 INLINE_LIST( ret, accessExpr, 0, false );
1396 string JavaTabCodeGen::P()
1403 INLINE_LIST( ret, pExpr, 0, false );
1409 string JavaTabCodeGen::PE()
1416 INLINE_LIST( ret, peExpr, 0, false );
1422 string JavaTabCodeGen::EOFV()
1429 INLINE_LIST( ret, eofExpr, 0, false );
1435 string JavaTabCodeGen::CS()
1439 ret << ACCESS() << "cs";
1441 /* Emit the user supplied method of retrieving the key. */
1443 INLINE_LIST( ret, csExpr, 0, false );
1449 string JavaTabCodeGen::TOP()
1453 ret << ACCESS() + "top";
1456 INLINE_LIST( ret, topExpr, 0, false );
1462 string JavaTabCodeGen::STACK()
1465 if ( stackExpr == 0 )
1466 ret << ACCESS() + "stack";
1469 INLINE_LIST( ret, stackExpr, 0, false );
1475 string JavaTabCodeGen::ACT()
1479 ret << ACCESS() + "act";
1482 INLINE_LIST( ret, actExpr, 0, false );
1488 string JavaTabCodeGen::TOKSTART()
1491 if ( tokstartExpr == 0 )
1492 ret << ACCESS() + "ts";
1495 INLINE_LIST( ret, tokstartExpr, 0, false );
1501 string JavaTabCodeGen::TOKEND()
1504 if ( tokendExpr == 0 )
1505 ret << ACCESS() + "te";
1508 INLINE_LIST( ret, tokendExpr, 0, false );
1514 string JavaTabCodeGen::DATA()
1517 if ( dataExpr == 0 )
1518 ret << ACCESS() + "data";
1521 INLINE_LIST( ret, dataExpr, 0, false );
1528 string JavaTabCodeGen::GET_WIDE_KEY()
1530 if ( redFsm->anyConditions() )
1536 string JavaTabCodeGen::GET_WIDE_KEY( RedStateAp *state )
1538 if ( state->stateCondList.length() > 0 )
1544 /* Write out level number of tabs. Makes the nested binary search nice
1546 string JavaTabCodeGen::TABS( int level )
1549 while ( level-- > 0 )
1554 string JavaTabCodeGen::KEY( Key key )
1557 if ( keyOps->isSigned || !hostLang->explicitUnsigned )
1558 ret << key.getVal();
1560 ret << (unsigned long) key.getVal();
1564 string JavaTabCodeGen::INT( int i )
1571 void JavaTabCodeGen::LM_SWITCH( ostream &ret, GenInlineItem *item,
1572 int targState, int inFinish )
1575 " switch( " << ACT() << " ) {\n";
1577 for ( GenInlineList::Iter lma = *item->children; lma.lte(); lma++ ) {
1578 /* Write the case label, the action and the case break. */
1579 if ( lma->lmId < 0 )
1580 ret << " default:\n";
1582 ret << " case " << lma->lmId << ":\n";
1584 /* Write the block and close it off. */
1586 INLINE_LIST( ret, lma->children, targState, inFinish );
1597 void JavaTabCodeGen::SET_ACT( ostream &ret, GenInlineItem *item )
1599 ret << ACT() << " = " << item->lmId << ";";
1602 void JavaTabCodeGen::SET_TOKEND( ostream &ret, GenInlineItem *item )
1604 /* The tokend action sets tokend. */
1605 ret << TOKEND() << " = " << P();
1606 if ( item->offset != 0 )
1607 out << "+" << item->offset;
1611 void JavaTabCodeGen::GET_TOKEND( ostream &ret, GenInlineItem *item )
1616 void JavaTabCodeGen::INIT_TOKSTART( ostream &ret, GenInlineItem *item )
1618 ret << TOKSTART() << " = " << NULL_ITEM() << ";";
1621 void JavaTabCodeGen::INIT_ACT( ostream &ret, GenInlineItem *item )
1623 ret << ACT() << " = 0;";
1626 void JavaTabCodeGen::SET_TOKSTART( ostream &ret, GenInlineItem *item )
1628 ret << TOKSTART() << " = " << P() << ";";
1631 void JavaTabCodeGen::SUB_ACTION( ostream &ret, GenInlineItem *item,
1632 int targState, bool inFinish )
1634 if ( item->children->length() > 0 ) {
1635 /* Write the block and close it off. */
1637 INLINE_LIST( ret, item->children, targState, inFinish );
1642 void JavaTabCodeGen::ACTION( ostream &ret, GenAction *action, int targState, bool inFinish )
1644 /* Write the preprocessor line info for going into the source file. */
1645 javaLineDirective( ret, sourceFileName, action->loc.line );
1647 /* Write the block and close it off. */
1649 INLINE_LIST( ret, action->inlineList, targState, inFinish );
1653 void JavaTabCodeGen::CONDITION( ostream &ret, GenAction *condition )
1656 javaLineDirective( ret, sourceFileName, condition->loc.line );
1657 INLINE_LIST( ret, condition->inlineList, 0, false );
1660 string JavaTabCodeGen::ERROR_STATE()
1663 if ( redFsm->errState != 0 )
1664 ret << redFsm->errState->id;
1670 string JavaTabCodeGen::FIRST_FINAL_STATE()
1673 if ( redFsm->firstFinState != 0 )
1674 ret << redFsm->firstFinState->id;
1676 ret << redFsm->nextStateId;
1680 void JavaTabCodeGen::writeInit()
1685 out << "\t" << CS() << " = " << START() << ";\n";
1687 /* If there are any calls, then the stack top needs initialization. */
1688 if ( redFsm->anyActionCalls() || redFsm->anyActionRets() )
1689 out << "\t" << TOP() << " = 0;\n";
1691 if ( hasLongestMatch ) {
1693 " " << TOKSTART() << " = " << NULL_ITEM() << ";\n"
1694 " " << TOKEND() << " = " << NULL_ITEM() << ";\n"
1695 " " << ACT() << " = 0;\n";
1700 void JavaTabCodeGen::finishRagelDef()
1702 /* The frontend will do this for us, but it may be a good idea to force it
1703 * if the intermediate file is edited. */
1704 redFsm->sortByStateId();
1706 /* Choose default transitions and the single transition. */
1707 redFsm->chooseDefaultSpan();
1709 /* Maybe do flat expand, otherwise choose single. */
1710 redFsm->chooseSingle();
1712 /* If any errors have occured in the input file then don't write anything. */
1713 if ( gblErrorCount > 0 )
1716 /* Anlayze Machine will find the final action reference counts, among
1717 * other things. We will use these in reporting the usage
1718 * of fsm directives in action code. */
1721 /* Determine if we should use indicies. */
1725 ostream &JavaTabCodeGen::source_warning( const InputLoc &loc )
1727 cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": warning: ";
1731 ostream &JavaTabCodeGen::source_error( const InputLoc &loc )
1734 assert( sourceFileName != 0 );
1735 cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": ";