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 );
86 /* Open the output stream, attaching it to the filter. */
87 outStream = new ostream( outFilter );
90 /* Writing out ot std out. */
96 /* Invoked by the parser when a ragel definition is opened. */
97 CodeGenData *javaMakeCodeGen( const char *sourceFileName, const char *fsmName,
98 ostream &out, bool wantComplete )
100 CodeGenData *codeGen = new JavaTabCodeGen(out);
102 codeGen->sourceFileName = sourceFileName;
103 codeGen->fsmName = fsmName;
104 codeGen->wantComplete = wantComplete;
109 void javaLineDirective( ostream &out, const char *fileName, int line )
111 /* Write the preprocessor line info for to the input file. */
112 out << "// line " << line << " \"";
113 for ( const char *pc = fileName; *pc != 0; pc++ ) {
122 void JavaTabCodeGen::genLineDirective( ostream &out )
124 std::streambuf *sbuf = out.rdbuf();
125 output_filter *filter = static_cast<output_filter*>(sbuf);
126 javaLineDirective( out, filter->fileName, filter->line + 1 );
129 void JavaTabCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
131 ret << "{" << CS() << " = " << gotoDest << "; _goto_targ = " << _again << "; " <<
132 CTRL_FLOW() << "continue _goto;}";
135 void JavaTabCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
137 ret << "{" << CS() << " = (";
138 INLINE_LIST( ret, ilItem->children, 0, inFinish );
139 ret << "); _goto_targ = " << _again << "; " << CTRL_FLOW() << "continue _goto;}";
142 void JavaTabCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
144 if ( prePushExpr != 0 ) {
146 INLINE_LIST( ret, prePushExpr, 0, false );
149 ret << "{" << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = " <<
150 callDest << "; _goto_targ = " << _again << "; " << CTRL_FLOW() << "continue _goto;}";
152 if ( prePushExpr != 0 )
156 void JavaTabCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish )
158 if ( prePushExpr != 0 ) {
160 INLINE_LIST( ret, prePushExpr, 0, false );
163 ret << "{" << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = (";
164 INLINE_LIST( ret, ilItem->children, targState, inFinish );
165 ret << "); _goto_targ = " << _again << "; " << CTRL_FLOW() << "continue _goto;}";
167 if ( prePushExpr != 0 )
171 void JavaTabCodeGen::RET( ostream &ret, bool inFinish )
173 ret << "{" << CS() << " = " << STACK() << "[--" << TOP() << "];";
175 if ( postPopExpr != 0 ) {
177 INLINE_LIST( ret, postPopExpr, 0, false );
181 ret << "_goto_targ = " << _again << "; " << CTRL_FLOW() << "continue _goto;}";
184 void JavaTabCodeGen::BREAK( ostream &ret, int targState )
186 ret << "{ " << P() << " += 1; _goto_targ = " << _out << "; " <<
187 CTRL_FLOW() << " continue _goto;}";
190 void JavaTabCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
192 ret << CS() << " = " << nextDest << ";";
195 void JavaTabCodeGen::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
197 ret << CS() << " = (";
198 INLINE_LIST( ret, ilItem->children, 0, inFinish );
202 void JavaTabCodeGen::EXEC( ostream &ret, GenInlineItem *item, int targState, int inFinish )
204 /* The parser gives fexec two children. The double brackets are for D
205 * code. If the inline list is a single word it will get interpreted as a
206 * C-style cast by the D compiler. */
207 ret << "{" << P() << " = ((";
208 INLINE_LIST( ret, item->children, targState, inFinish );
212 /* Write out an inline tree structure. Walks the list and possibly calls out
213 * to virtual functions than handle language specific items in the tree. */
214 void JavaTabCodeGen::INLINE_LIST( ostream &ret, GenInlineList *inlineList,
215 int targState, bool inFinish )
217 for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) {
218 switch ( item->type ) {
219 case GenInlineItem::Text:
222 case GenInlineItem::Goto:
223 GOTO( ret, item->targState->id, inFinish );
225 case GenInlineItem::Call:
226 CALL( ret, item->targState->id, targState, inFinish );
228 case GenInlineItem::Next:
229 NEXT( ret, item->targState->id, inFinish );
231 case GenInlineItem::Ret:
232 RET( ret, inFinish );
234 case GenInlineItem::PChar:
237 case GenInlineItem::Char:
240 case GenInlineItem::Hold:
243 case GenInlineItem::Exec:
244 EXEC( ret, item, targState, inFinish );
246 case GenInlineItem::Curs:
249 case GenInlineItem::Targs:
250 ret << "(" << CS() << ")";
252 case GenInlineItem::Entry:
253 ret << item->targState->id;
255 case GenInlineItem::GotoExpr:
256 GOTO_EXPR( ret, item, inFinish );
258 case GenInlineItem::CallExpr:
259 CALL_EXPR( ret, item, targState, inFinish );
261 case GenInlineItem::NextExpr:
262 NEXT_EXPR( ret, item, inFinish );
264 case GenInlineItem::LmSwitch:
265 LM_SWITCH( ret, item, targState, inFinish );
267 case GenInlineItem::LmSetActId:
268 SET_ACT( ret, item );
270 case GenInlineItem::LmSetTokEnd:
271 SET_TOKEND( ret, item );
273 case GenInlineItem::LmGetTokEnd:
274 GET_TOKEND( ret, item );
276 case GenInlineItem::LmInitTokStart:
277 INIT_TOKSTART( ret, item );
279 case GenInlineItem::LmInitAct:
280 INIT_ACT( ret, item );
282 case GenInlineItem::LmSetTokStart:
283 SET_TOKSTART( ret, item );
285 case GenInlineItem::SubAction:
286 SUB_ACTION( ret, item, targState, inFinish );
288 case GenInlineItem::Break:
289 BREAK( ret, targState );
295 string JavaTabCodeGen::DATA_PREFIX()
298 return FSM_NAME() + "_";
302 /* Emit the alphabet data type. */
303 string JavaTabCodeGen::ALPH_TYPE()
305 string ret = keyOps->alphType->data1;
306 if ( keyOps->alphType->data2 != 0 ) {
308 ret += + keyOps->alphType->data2;
313 /* Emit the alphabet data type. */
314 string JavaTabCodeGen::WIDE_ALPH_TYPE()
317 if ( redFsm->maxKey <= keyOps->maxKey )
320 long long maxKeyVal = redFsm->maxKey.getLongLong();
321 HostType *wideType = keyOps->typeSubsumes( keyOps->isSigned, maxKeyVal );
322 assert( wideType != 0 );
324 ret = wideType->data1;
325 if ( wideType->data2 != 0 ) {
327 ret += wideType->data2;
335 void JavaTabCodeGen::COND_TRANSLATE()
338 " _widec = " << GET_KEY() << ";\n"
339 " _keys = " << CO() << "[" << CS() << "]*2\n;"
340 " _klen = " << CL() << "[" << CS() << "];\n"
341 " if ( _klen > 0 ) {\n"
342 " int _lower = _keys\n;"
344 " int _upper = _keys + (_klen<<1) - 2;\n"
346 " if ( _upper < _lower )\n"
349 " _mid = _lower + (((_upper-_lower) >> 1) & ~1);\n"
350 " if ( " << GET_WIDE_KEY() << " < " << CK() << "[_mid] )\n"
351 " _upper = _mid - 2;\n"
352 " else if ( " << GET_WIDE_KEY() << " > " << CK() << "[_mid+1] )\n"
353 " _lower = _mid + 2;\n"
355 " switch ( " << C() << "[" << CO() << "[" << CS() << "]"
356 " + ((_mid - _keys)>>1)] ) {\n"
359 for ( CondSpaceList::Iter csi = condSpaceList; csi.lte(); csi++ ) {
360 GenCondSpace *condSpace = csi;
361 out << " case " << condSpace->condSpaceId << ": {\n";
362 out << TABS(2) << "_widec = " << KEY(condSpace->baseKey) <<
363 " + (" << GET_KEY() << " - " << KEY(keyOps->minKey) << ");\n";
365 for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
366 out << TABS(2) << "if ( ";
367 CONDITION( out, *csi );
368 Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize());
369 out << " ) _widec += " << condValOffset << ";\n";
387 void JavaTabCodeGen::LOCATE_TRANS()
391 " _keys = " << KO() << "[" << CS() << "]" << ";\n"
392 " _trans = " << IO() << "[" << CS() << "];\n"
393 " _klen = " << SL() << "[" << CS() << "];\n"
394 " if ( _klen > 0 ) {\n"
395 " int _lower = _keys;\n"
397 " int _upper = _keys + _klen - 1;\n"
399 " if ( _upper < _lower )\n"
402 " _mid = _lower + ((_upper-_lower) >> 1);\n"
403 " if ( " << GET_WIDE_KEY() << " < " << K() << "[_mid] )\n"
404 " _upper = _mid - 1;\n"
405 " else if ( " << GET_WIDE_KEY() << " > " << K() << "[_mid] )\n"
406 " _lower = _mid + 1;\n"
408 " _trans += (_mid - _keys);\n"
413 " _trans += _klen;\n"
416 " _klen = " << RL() << "[" << CS() << "];\n"
417 " if ( _klen > 0 ) {\n"
418 " int _lower = _keys;\n"
420 " int _upper = _keys + (_klen<<1) - 2;\n"
422 " if ( _upper < _lower )\n"
425 " _mid = _lower + (((_upper-_lower) >> 1) & ~1);\n"
426 " if ( " << GET_WIDE_KEY() << " < " << K() << "[_mid] )\n"
427 " _upper = _mid - 2;\n"
428 " else if ( " << GET_WIDE_KEY() << " > " << K() << "[_mid+1] )\n"
429 " _lower = _mid + 2;\n"
431 " _trans += ((_mid - _keys)>>1);\n"
435 " _trans += _klen;\n"
437 " } while (false);\n"
441 /* Determine if we should use indicies or not. */
442 void JavaTabCodeGen::calcIndexSize()
444 int sizeWithInds = 0, sizeWithoutInds = 0;
446 /* Calculate cost of using with indicies. */
447 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
448 int totalIndex = st->outSingle.length() + st->outRange.length() +
449 (st->defTrans == 0 ? 0 : 1);
450 sizeWithInds += arrayTypeSize(redFsm->maxIndex) * totalIndex;
452 sizeWithInds += arrayTypeSize(redFsm->maxState) * redFsm->transSet.length();
453 if ( redFsm->anyActions() )
454 sizeWithInds += arrayTypeSize(redFsm->maxActionLoc) * redFsm->transSet.length();
456 /* Calculate the cost of not using indicies. */
457 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
458 int totalIndex = st->outSingle.length() + st->outRange.length() +
459 (st->defTrans == 0 ? 0 : 1);
460 sizeWithoutInds += arrayTypeSize(redFsm->maxState) * totalIndex;
461 if ( redFsm->anyActions() )
462 sizeWithoutInds += arrayTypeSize(redFsm->maxActionLoc) * totalIndex;
465 /* If using indicies reduces the size, use them. */
466 useIndicies = sizeWithInds < sizeWithoutInds;
469 int JavaTabCodeGen::TO_STATE_ACTION( RedStateAp *state )
472 if ( state->toStateAction != 0 )
473 act = state->toStateAction->location+1;
477 int JavaTabCodeGen::FROM_STATE_ACTION( RedStateAp *state )
480 if ( state->fromStateAction != 0 )
481 act = state->fromStateAction->location+1;
485 int JavaTabCodeGen::EOF_ACTION( RedStateAp *state )
488 if ( state->eofAction != 0 )
489 act = state->eofAction->location+1;
494 int JavaTabCodeGen::TRANS_ACTION( RedTransAp *trans )
496 /* If there are actions, emit them. Otherwise emit zero. */
498 if ( trans->action != 0 )
499 act = trans->action->location+1;
503 std::ostream &JavaTabCodeGen::TO_STATE_ACTION_SWITCH()
505 /* Walk the list of functions, printing the cases. */
506 for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
507 /* Write out referenced actions. */
508 if ( act->numToStateRefs > 0 ) {
509 /* Write the case label, the action and the case break. */
510 out << "\tcase " << act->actionId << ":\n";
511 ACTION( out, act, 0, false );
516 genLineDirective( out );
520 std::ostream &JavaTabCodeGen::FROM_STATE_ACTION_SWITCH()
522 /* Walk the list of functions, printing the cases. */
523 for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
524 /* Write out referenced actions. */
525 if ( act->numFromStateRefs > 0 ) {
526 /* Write the case label, the action and the case break. */
527 out << "\tcase " << act->actionId << ":\n";
528 ACTION( out, act, 0, false );
533 genLineDirective( out );
537 std::ostream &JavaTabCodeGen::EOF_ACTION_SWITCH()
539 /* Walk the list of functions, printing the cases. */
540 for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
541 /* Write out referenced actions. */
542 if ( act->numEofRefs > 0 ) {
543 /* Write the case label, the action and the case break. */
544 out << "\tcase " << act->actionId << ":\n";
545 ACTION( out, act, 0, true );
550 genLineDirective( out );
555 std::ostream &JavaTabCodeGen::ACTION_SWITCH()
557 /* Walk the list of functions, printing the cases. */
558 for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
559 /* Write out referenced actions. */
560 if ( act->numTransRefs > 0 ) {
561 /* Write the case label, the action and the case break. */
562 out << "\tcase " << act->actionId << ":\n";
563 ACTION( out, act, 0, false );
568 genLineDirective( out );
572 std::ostream &JavaTabCodeGen::COND_OFFSETS()
574 int curKeyOffset = 0;
575 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
576 /* Write the key offset. */
577 ARRAY_ITEM( INT(curKeyOffset), st.last() );
579 /* Move the key offset ahead. */
580 curKeyOffset += st->stateCondList.length();
585 std::ostream &JavaTabCodeGen::KEY_OFFSETS()
587 int curKeyOffset = 0;
588 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
589 /* Write the key offset. */
590 ARRAY_ITEM( INT(curKeyOffset), st.last() );
592 /* Move the key offset ahead. */
593 curKeyOffset += st->outSingle.length() + st->outRange.length()*2;
599 std::ostream &JavaTabCodeGen::INDEX_OFFSETS()
601 int curIndOffset = 0;
602 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
603 /* Write the index offset. */
604 ARRAY_ITEM( INT(curIndOffset), st.last() );
606 /* Move the index offset ahead. */
607 curIndOffset += st->outSingle.length() + st->outRange.length();
608 if ( st->defTrans != 0 )
614 std::ostream &JavaTabCodeGen::COND_LENS()
616 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
617 /* Write singles length. */
618 ARRAY_ITEM( INT(st->stateCondList.length()), st.last() );
624 std::ostream &JavaTabCodeGen::SINGLE_LENS()
626 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
627 /* Write singles length. */
628 ARRAY_ITEM( INT(st->outSingle.length()), st.last() );
633 std::ostream &JavaTabCodeGen::RANGE_LENS()
635 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
636 /* Emit length of range index. */
637 ARRAY_ITEM( INT(st->outRange.length()), st.last() );
642 std::ostream &JavaTabCodeGen::TO_STATE_ACTIONS()
644 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
645 /* Write any eof action. */
646 ARRAY_ITEM( INT(TO_STATE_ACTION(st)), st.last() );
651 std::ostream &JavaTabCodeGen::FROM_STATE_ACTIONS()
653 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
654 /* Write any eof action. */
655 ARRAY_ITEM( INT(FROM_STATE_ACTION(st)), st.last() );
660 std::ostream &JavaTabCodeGen::EOF_ACTIONS()
662 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
663 /* Write any eof action. */
664 ARRAY_ITEM( INT(EOF_ACTION(st)), st.last() );
669 std::ostream &JavaTabCodeGen::EOF_TRANS()
671 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
672 /* Write any eof action. */
674 if ( st->eofTrans != 0 ) {
675 assert( st->eofTrans->pos >= 0 );
676 trans = st->eofTrans->pos+1;
679 /* Write any eof action. */
680 ARRAY_ITEM( INT(trans), st.last() );
686 std::ostream &JavaTabCodeGen::COND_KEYS()
688 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
689 /* Loop the state's transitions. */
690 for ( GenStateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
692 ARRAY_ITEM( KEY( sc->lowKey ), false );
693 ARRAY_ITEM( KEY( sc->highKey ), false );
697 /* Output one last number so we don't have to figure out when the last
698 * entry is and avoid writing a comma. */
699 ARRAY_ITEM( INT(0), true );
703 std::ostream &JavaTabCodeGen::COND_SPACES()
705 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
706 /* Loop the state's transitions. */
707 for ( GenStateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
709 ARRAY_ITEM( KEY( sc->condSpace->condSpaceId ), false );
713 /* Output one last number so we don't have to figure out when the last
714 * entry is and avoid writing a comma. */
715 ARRAY_ITEM( INT(0), true );
719 std::ostream &JavaTabCodeGen::KEYS()
721 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
722 /* Loop the singles. */
723 for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
724 ARRAY_ITEM( KEY( stel->lowKey ), false );
727 /* Loop the state's transitions. */
728 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
730 ARRAY_ITEM( KEY( rtel->lowKey ), false );
733 ARRAY_ITEM( KEY( rtel->highKey ), false );
737 /* Output one last number so we don't have to figure out when the last
738 * entry is and avoid writing a comma. */
739 ARRAY_ITEM( INT(0), true );
743 std::ostream &JavaTabCodeGen::INDICIES()
745 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
746 /* Walk the singles. */
747 for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
748 ARRAY_ITEM( KEY( stel->value->id ), false );
751 /* Walk the ranges. */
752 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
753 ARRAY_ITEM( KEY( rtel->value->id ), false );
756 /* The state's default index goes next. */
757 if ( st->defTrans != 0 ) {
758 ARRAY_ITEM( KEY( st->defTrans->id ), false );
762 /* Output one last number so we don't have to figure out when the last
763 * entry is and avoid writing a comma. */
764 ARRAY_ITEM( INT(0), true );
768 std::ostream &JavaTabCodeGen::TRANS_TARGS()
771 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
772 /* Walk the singles. */
773 for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
774 RedTransAp *trans = stel->value;
775 ARRAY_ITEM( KEY( trans->targ->id ), false );
779 /* Walk the ranges. */
780 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
781 RedTransAp *trans = rtel->value;
782 ARRAY_ITEM( KEY( trans->targ->id ), false );
786 /* The state's default target state. */
787 if ( st->defTrans != 0 ) {
788 RedTransAp *trans = st->defTrans;
789 ARRAY_ITEM( KEY( trans->targ->id ), false );
794 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
795 if ( st->eofTrans != 0 ) {
796 RedTransAp *trans = st->eofTrans;
797 trans->pos = totalTrans++;
798 ARRAY_ITEM( KEY( trans->targ->id ), false );
802 /* Output one last number so we don't have to figure out when the last
803 * entry is and avoid writing a comma. */
804 ARRAY_ITEM( INT(0), true );
809 std::ostream &JavaTabCodeGen::TRANS_ACTIONS()
811 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
812 /* Walk the singles. */
813 for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
814 RedTransAp *trans = stel->value;
815 ARRAY_ITEM( INT(TRANS_ACTION( trans )), false );
818 /* Walk the ranges. */
819 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
820 RedTransAp *trans = rtel->value;
821 ARRAY_ITEM( INT(TRANS_ACTION( trans )), false );
824 /* The state's default index goes next. */
825 if ( st->defTrans != 0 ) {
826 RedTransAp *trans = st->defTrans;
827 ARRAY_ITEM( INT(TRANS_ACTION( trans )), false );
831 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
832 if ( st->eofTrans != 0 ) {
833 RedTransAp *trans = st->eofTrans;
834 ARRAY_ITEM( INT(TRANS_ACTION( trans )), false );
838 /* Output one last number so we don't have to figure out when the last
839 * entry is and avoid writing a comma. */
840 ARRAY_ITEM( INT(0), true );
844 std::ostream &JavaTabCodeGen::TRANS_TARGS_WI()
846 /* Transitions must be written ordered by their id. */
847 RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
848 for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
849 transPtrs[trans->id] = trans;
851 /* Keep a count of the num of items in the array written. */
852 for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
853 /* Save the position. Needed for eofTargs. */
854 RedTransAp *trans = transPtrs[t];
857 /* Write out the target state. */
858 ARRAY_ITEM( INT(trans->targ->id), ( t >= redFsm->transSet.length()-1 ) );
865 std::ostream &JavaTabCodeGen::TRANS_ACTIONS_WI()
867 /* Transitions must be written ordered by their id. */
868 RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
869 for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
870 transPtrs[trans->id] = trans;
872 /* Keep a count of the num of items in the array written. */
873 for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
874 /* Write the function for the transition. */
875 RedTransAp *trans = transPtrs[t];
876 ARRAY_ITEM( INT(TRANS_ACTION( trans )), ( t >= redFsm->transSet.length()-1 ) );
882 void JavaTabCodeGen::writeExports()
884 if ( exportList.length() > 0 ) {
885 for ( ExportList::Iter ex = exportList; ex.lte(); ex++ ) {
886 STATIC_VAR( ALPH_TYPE(), DATA_PREFIX() + "ex_" + ex->name )
887 << " = " << KEY(ex->key) << ";\n";
893 void JavaTabCodeGen::writeStart()
895 out << START_STATE_ID();
898 void JavaTabCodeGen::writeFirstFinal()
900 out << FIRST_FINAL_STATE();
903 void JavaTabCodeGen::writeError()
905 out << ERROR_STATE();
908 void JavaTabCodeGen::writeData()
910 /* If there are any transtion functions then output the array. If there
911 * are none, don't bother emitting an empty array that won't be used. */
912 if ( redFsm->anyActions() ) {
913 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
919 if ( redFsm->anyConditions() ) {
920 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondOffset), CO() );
925 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondLen), CL() );
930 OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
935 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpaceId), C() );
941 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxKeyOffset), KO() );
946 OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
951 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSingleLen), SL() );
956 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxRangeLen), RL() );
961 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset), IO() );
967 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
972 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
977 if ( redFsm->anyActions() ) {
978 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
985 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
990 if ( redFsm->anyActions() ) {
991 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
998 if ( redFsm->anyToStateActions() ) {
999 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
1005 if ( redFsm->anyFromStateActions() ) {
1006 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
1007 FROM_STATE_ACTIONS();
1012 if ( redFsm->anyEofActions() ) {
1013 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
1019 if ( redFsm->anyEofTrans() ) {
1020 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset+1), ET() );
1026 if ( redFsm->startState != 0 )
1027 STATIC_VAR( "int", START() ) << " = " << START_STATE_ID() << ";\n";
1030 STATIC_VAR( "int" , FIRST_FINAL() ) << " = " << FIRST_FINAL_STATE() << ";\n";
1033 STATIC_VAR( "int", ERROR() ) << " = " << ERROR_STATE() << ";\n";
1037 if ( entryPointNames.length() > 0 ) {
1038 for ( EntryNameVect::Iter en = entryPointNames; en.lte(); en++ ) {
1039 STATIC_VAR( "int", DATA_PREFIX() + "en_" + *en ) <<
1040 " = " << entryPointIds[en.pos()] << ";\n";
1046 void JavaTabCodeGen::writeExec()
1052 if ( redFsm->anyRegCurStateRef() )
1057 " int _trans = 0;\n";
1059 if ( redFsm->anyConditions() )
1060 out << " int _widec;\n";
1062 if ( redFsm->anyToStateActions() || redFsm->anyRegActions() ||
1063 redFsm->anyFromStateActions() )
1072 " int _goto_targ = 0;\n"
1076 " _goto: while (true) {\n"
1077 " switch ( _goto_targ ) {\n"
1082 " if ( " << P() << " == " << PE() << " ) {\n"
1083 " _goto_targ = " << _test_eof << ";\n"
1084 " continue _goto;\n"
1088 if ( redFsm->errState != 0 ) {
1090 " if ( " << CS() << " == " << redFsm->errState->id << " ) {\n"
1091 " _goto_targ = " << _out << ";\n"
1092 " continue _goto;\n"
1096 out << "case " << _resume << ":\n";
1098 if ( redFsm->anyFromStateActions() ) {
1100 " _acts = " << FSA() << "[" << CS() << "]" << ";\n"
1101 " _nacts = " << CAST("int") << " " << A() << "[_acts++];\n"
1102 " while ( _nacts-- > 0 ) {\n"
1103 " switch ( " << A() << "[_acts++] ) {\n";
1104 FROM_STATE_ACTION_SWITCH() <<
1110 if ( redFsm->anyConditions() )
1116 out << " _trans = " << I() << "[_trans];\n";
1118 if ( redFsm->anyEofTrans() )
1119 out << "case " << _eof_trans << ":\n";
1121 if ( redFsm->anyRegCurStateRef() )
1122 out << " _ps = " << CS() << ";\n";
1125 " " << CS() << " = " << TT() << "[_trans];\n"
1128 if ( redFsm->anyRegActions() ) {
1130 " if ( " << TA() << "[_trans] != 0 ) {\n"
1131 " _acts = " << TA() << "[_trans]" << ";\n"
1132 " _nacts = " << CAST("int") << " " << A() << "[_acts++];\n"
1133 " while ( _nacts-- > 0 )\n {\n"
1134 " switch ( " << A() << "[_acts++] )\n"
1143 out << "case " << _again << ":\n";
1145 if ( redFsm->anyToStateActions() ) {
1147 " _acts = " << TSA() << "[" << CS() << "]" << ";\n"
1148 " _nacts = " << CAST("int") << " " << A() << "[_acts++];\n"
1149 " while ( _nacts-- > 0 ) {\n"
1150 " switch ( " << A() << "[_acts++] ) {\n";
1151 TO_STATE_ACTION_SWITCH() <<
1157 if ( redFsm->errState != 0 ) {
1159 " if ( " << CS() << " == " << redFsm->errState->id << " ) {\n"
1160 " _goto_targ = " << _out << ";\n"
1161 " continue _goto;\n"
1167 " if ( ++" << P() << " != " << PE() << " ) {\n"
1168 " _goto_targ = " << _resume << ";\n"
1169 " continue _goto;\n"
1174 " " << P() << " += 1;\n"
1175 " _goto_targ = " << _resume << ";\n"
1176 " continue _goto;\n";
1179 out << "case " << _test_eof << ":\n";
1181 if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
1183 " if ( " << P() << " == " << EOFV() << " )\n"
1186 if ( redFsm->anyEofTrans() ) {
1188 " if ( " << ET() << "[" << CS() << "] > 0 ) {\n"
1189 " _trans = " << ET() << "[" << CS() << "] - 1;\n"
1190 " _goto_targ = " << _eof_trans << ";\n"
1191 " continue _goto;\n"
1195 if ( redFsm->anyEofActions() ) {
1197 " int __acts = " << EA() << "[" << CS() << "]" << ";\n"
1198 " int __nacts = " << CAST("int") << " " << A() << "[__acts++];\n"
1199 " while ( __nacts-- > 0 ) {\n"
1200 " switch ( " << A() << "[__acts++] ) {\n";
1201 EOF_ACTION_SWITCH() <<
1211 out << "case " << _out << ":\n";
1213 /* The switch and goto loop. */
1215 out << " break; }\n";
1217 /* The execute block. */
1221 std::ostream &JavaTabCodeGen::OPEN_ARRAY( string type, string name )
1228 out << "private static " << type << "[] init_" << name << "_0()\n"
1230 "return new " << type << " [] {\n\t";
1234 std::ostream &JavaTabCodeGen::ARRAY_ITEM( string item, bool last )
1238 out << setw(5) << setiosflags(ios::right) << item;
1241 if ( item_count % SAIIC == 0 ) {
1242 out << "\n\t};\n};\n"
1243 "private static "<< array_type << "[] init_" <<
1244 array_name << "_" << div_count << "()\n"
1246 "return new " << array_type << " [] {\n\t";
1248 } else if (item_count % IALL == 0) {
1257 std::ostream &JavaTabCodeGen::CLOSE_ARRAY()
1259 out << "\n\t};\n}\n\n";
1261 if (item_count < SAIIC) {
1262 out << "private static final " << array_type << " " << array_name <<
1263 "[] = init_" << array_name << "_0();\n\n";
1265 out << "private static final " << array_type << " [] combine_" << array_name
1267 << array_type << " [] combined = new " << array_type <<
1268 " [ " << item_count << " ];\n\t";
1270 int full_blocks = item_count / SAIIC;
1271 for (;block < full_blocks; ++block) {
1272 out << "System.arraycopy ( init_" << array_name << "_" << block <<
1273 "(), 0, combined, " << SAIIC * block << ", " << SAIIC << " );\n\t";
1275 if ( (item_count % SAIIC) > 0 ) {
1276 out << "System.arraycopy ( init_" << array_name << "_" << block <<
1277 "(), 0, combined, " << SAIIC * block << ", " <<
1278 (item_count % SAIIC) << " );\n\t";
1280 out << "return combined;\n}\n";
1281 out << "private static final " << array_type << " [] " << array_name <<
1282 " = combine_" << array_name << "();";
1288 std::ostream &JavaTabCodeGen::STATIC_VAR( string type, string name )
1290 out << "static final " << type << " " << name;
1294 string JavaTabCodeGen::ARR_OFF( string ptr, string offset )
1296 return ptr + " + " + offset;
1299 string JavaTabCodeGen::CAST( string type )
1301 return "(" + type + ")";
1304 string JavaTabCodeGen::NULL_ITEM()
1306 /* In java we use integers instead of pointers. */
1310 string JavaTabCodeGen::GET_KEY()
1313 if ( getKeyExpr != 0 ) {
1314 /* Emit the user supplied method of retrieving the key. */
1316 INLINE_LIST( ret, getKeyExpr, 0, false );
1320 /* Expression for retrieving the key, use simple dereference. */
1321 ret << DATA() << "[" << P() << "]";
1326 string JavaTabCodeGen::CTRL_FLOW()
1328 return "if (true) ";
1331 unsigned int JavaTabCodeGen::arrayTypeSize( unsigned long maxVal )
1333 long long maxValLL = (long long) maxVal;
1334 HostType *arrayType = keyOps->typeSubsumes( maxValLL );
1335 assert( arrayType != 0 );
1336 return arrayType->size;
1339 string JavaTabCodeGen::ARRAY_TYPE( unsigned long maxVal )
1341 long long maxValLL = (long long) maxVal;
1342 HostType *arrayType = keyOps->typeSubsumes( maxValLL );
1343 assert( arrayType != 0 );
1345 string ret = arrayType->data1;
1346 if ( arrayType->data2 != 0 ) {
1348 ret += arrayType->data2;
1354 /* Write out the fsm name. */
1355 string JavaTabCodeGen::FSM_NAME()
1360 /* Emit the offset of the start state as a decimal integer. */
1361 string JavaTabCodeGen::START_STATE_ID()
1364 ret << redFsm->startState->id;
1368 /* Write out the array of actions. */
1369 std::ostream &JavaTabCodeGen::ACTIONS_ARRAY()
1371 ARRAY_ITEM( INT(0), false );
1372 for ( GenActionTableMap::Iter act = redFsm->actionMap; act.lte(); act++ ) {
1373 /* Write out the length, which will never be the last character. */
1374 ARRAY_ITEM( INT(act->key.length()), false );
1376 for ( GenActionTable::Iter item = act->key; item.lte(); item++ )
1377 ARRAY_ITEM( INT(item->value->actionId), (act.last() && item.last()) );
1383 string JavaTabCodeGen::ACCESS()
1386 if ( accessExpr != 0 )
1387 INLINE_LIST( ret, accessExpr, 0, false );
1391 string JavaTabCodeGen::P()
1398 INLINE_LIST( ret, pExpr, 0, false );
1404 string JavaTabCodeGen::PE()
1411 INLINE_LIST( ret, peExpr, 0, false );
1417 string JavaTabCodeGen::EOFV()
1424 INLINE_LIST( ret, eofExpr, 0, false );
1430 string JavaTabCodeGen::CS()
1434 ret << ACCESS() << "cs";
1436 /* Emit the user supplied method of retrieving the key. */
1438 INLINE_LIST( ret, csExpr, 0, false );
1444 string JavaTabCodeGen::TOP()
1448 ret << ACCESS() + "top";
1451 INLINE_LIST( ret, topExpr, 0, false );
1457 string JavaTabCodeGen::STACK()
1460 if ( stackExpr == 0 )
1461 ret << ACCESS() + "stack";
1464 INLINE_LIST( ret, stackExpr, 0, false );
1470 string JavaTabCodeGen::ACT()
1474 ret << ACCESS() + "act";
1477 INLINE_LIST( ret, actExpr, 0, false );
1483 string JavaTabCodeGen::TOKSTART()
1486 if ( tokstartExpr == 0 )
1487 ret << ACCESS() + "ts";
1490 INLINE_LIST( ret, tokstartExpr, 0, false );
1496 string JavaTabCodeGen::TOKEND()
1499 if ( tokendExpr == 0 )
1500 ret << ACCESS() + "te";
1503 INLINE_LIST( ret, tokendExpr, 0, false );
1509 string JavaTabCodeGen::DATA()
1512 if ( dataExpr == 0 )
1513 ret << ACCESS() + "data";
1516 INLINE_LIST( ret, dataExpr, 0, false );
1523 string JavaTabCodeGen::GET_WIDE_KEY()
1525 if ( redFsm->anyConditions() )
1531 string JavaTabCodeGen::GET_WIDE_KEY( RedStateAp *state )
1533 if ( state->stateCondList.length() > 0 )
1539 /* Write out level number of tabs. Makes the nested binary search nice
1541 string JavaTabCodeGen::TABS( int level )
1544 while ( level-- > 0 )
1549 string JavaTabCodeGen::KEY( Key key )
1552 if ( keyOps->isSigned || !hostLang->explicitUnsigned )
1553 ret << key.getVal();
1555 ret << (unsigned long) key.getVal();
1559 string JavaTabCodeGen::INT( int i )
1566 void JavaTabCodeGen::LM_SWITCH( ostream &ret, GenInlineItem *item,
1567 int targState, int inFinish )
1570 " switch( " << ACT() << " ) {\n";
1572 for ( GenInlineList::Iter lma = *item->children; lma.lte(); lma++ ) {
1573 /* Write the case label, the action and the case break. */
1574 if ( lma->lmId < 0 )
1575 ret << " default:\n";
1577 ret << " case " << lma->lmId << ":\n";
1579 /* Write the block and close it off. */
1581 INLINE_LIST( ret, lma->children, targState, inFinish );
1592 void JavaTabCodeGen::SET_ACT( ostream &ret, GenInlineItem *item )
1594 ret << ACT() << " = " << item->lmId << ";";
1597 void JavaTabCodeGen::SET_TOKEND( ostream &ret, GenInlineItem *item )
1599 /* The tokend action sets tokend. */
1600 ret << TOKEND() << " = " << P();
1601 if ( item->offset != 0 )
1602 out << "+" << item->offset;
1606 void JavaTabCodeGen::GET_TOKEND( ostream &ret, GenInlineItem *item )
1611 void JavaTabCodeGen::INIT_TOKSTART( ostream &ret, GenInlineItem *item )
1613 ret << TOKSTART() << " = " << NULL_ITEM() << ";";
1616 void JavaTabCodeGen::INIT_ACT( ostream &ret, GenInlineItem *item )
1618 ret << ACT() << " = 0;";
1621 void JavaTabCodeGen::SET_TOKSTART( ostream &ret, GenInlineItem *item )
1623 ret << TOKSTART() << " = " << P() << ";";
1626 void JavaTabCodeGen::SUB_ACTION( ostream &ret, GenInlineItem *item,
1627 int targState, bool inFinish )
1629 if ( item->children->length() > 0 ) {
1630 /* Write the block and close it off. */
1632 INLINE_LIST( ret, item->children, targState, inFinish );
1637 void JavaTabCodeGen::ACTION( ostream &ret, GenAction *action, int targState, bool inFinish )
1639 /* Write the preprocessor line info for going into the source file. */
1640 javaLineDirective( ret, sourceFileName, action->loc.line );
1642 /* Write the block and close it off. */
1644 INLINE_LIST( ret, action->inlineList, targState, inFinish );
1648 void JavaTabCodeGen::CONDITION( ostream &ret, GenAction *condition )
1651 javaLineDirective( ret, sourceFileName, condition->loc.line );
1652 INLINE_LIST( ret, condition->inlineList, 0, false );
1655 string JavaTabCodeGen::ERROR_STATE()
1658 if ( redFsm->errState != 0 )
1659 ret << redFsm->errState->id;
1665 string JavaTabCodeGen::FIRST_FINAL_STATE()
1668 if ( redFsm->firstFinState != 0 )
1669 ret << redFsm->firstFinState->id;
1671 ret << redFsm->nextStateId;
1675 void JavaTabCodeGen::writeInit()
1680 out << "\t" << CS() << " = " << START() << ";\n";
1682 /* If there are any calls, then the stack top needs initialization. */
1683 if ( redFsm->anyActionCalls() || redFsm->anyActionRets() )
1684 out << "\t" << TOP() << " = 0;\n";
1686 if ( hasLongestMatch ) {
1688 " " << TOKSTART() << " = " << NULL_ITEM() << ";\n"
1689 " " << TOKEND() << " = " << NULL_ITEM() << ";\n"
1690 " " << ACT() << " = 0;\n";
1695 void JavaTabCodeGen::finishRagelDef()
1697 /* The frontend will do this for us, but it may be a good idea to force it
1698 * if the intermediate file is edited. */
1699 redFsm->sortByStateId();
1701 /* Choose default transitions and the single transition. */
1702 redFsm->chooseDefaultSpan();
1704 /* Maybe do flat expand, otherwise choose single. */
1705 redFsm->chooseSingle();
1707 /* If any errors have occured in the input file then don't write anything. */
1708 if ( gblErrorCount > 0 )
1711 /* Anlayze Machine will find the final action reference counts, among
1712 * other things. We will use these in reporting the usage
1713 * of fsm directives in action code. */
1716 /* Determine if we should use indicies. */
1720 ostream &JavaTabCodeGen::source_warning( const InputLoc &loc )
1722 cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": warning: ";
1726 ostream &JavaTabCodeGen::source_error( const InputLoc &loc )
1729 assert( sourceFileName != 0 );
1730 cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": ";