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 a ragel definition is opened. */
59 CodeGenData *javaMakeCodeGen( const char *sourceFileName, const char *fsmName,
60 ostream &out, bool wantComplete )
62 CodeGenData *codeGen = new JavaTabCodeGen(out);
64 codeGen->sourceFileName = sourceFileName;
65 codeGen->fsmName = fsmName;
66 codeGen->wantComplete = wantComplete;
71 void javaLineDirective( ostream &out, const char *fileName, int line )
73 /* Write the preprocessor line info for to the input file. */
74 out << "// line " << line << " \"";
75 for ( const char *pc = fileName; *pc != 0; pc++ ) {
84 void JavaTabCodeGen::genLineDirective( ostream &out )
86 std::streambuf *sbuf = out.rdbuf();
87 output_filter *filter = static_cast<output_filter*>(sbuf);
88 javaLineDirective( out, filter->fileName, filter->line + 1 );
91 void JavaTabCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
93 ret << "{" << CS() << " = " << gotoDest << "; _goto_targ = " << _again << "; " <<
94 CTRL_FLOW() << "continue _goto;}";
97 void JavaTabCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
99 ret << "{" << CS() << " = (";
100 INLINE_LIST( ret, ilItem->children, 0, inFinish );
101 ret << "); _goto_targ = " << _again << "; " << CTRL_FLOW() << "continue _goto;}";
104 void JavaTabCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
106 if ( prePushExpr != 0 ) {
108 INLINE_LIST( ret, prePushExpr, 0, false );
111 ret << "{" << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = " <<
112 callDest << "; _goto_targ = " << _again << "; " << CTRL_FLOW() << "continue _goto;}";
114 if ( prePushExpr != 0 )
118 void JavaTabCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish )
120 if ( prePushExpr != 0 ) {
122 INLINE_LIST( ret, prePushExpr, 0, false );
125 ret << "{" << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = (";
126 INLINE_LIST( ret, ilItem->children, targState, inFinish );
127 ret << "); _goto_targ = " << _again << "; " << CTRL_FLOW() << "continue _goto;}";
129 if ( prePushExpr != 0 )
133 void JavaTabCodeGen::RET( ostream &ret, bool inFinish )
135 ret << "{" << CS() << " = " << STACK() << "[--" << TOP() << "];";
137 if ( postPopExpr != 0 ) {
139 INLINE_LIST( ret, postPopExpr, 0, false );
143 ret << "_goto_targ = " << _again << "; " << CTRL_FLOW() << "continue _goto;}";
146 void JavaTabCodeGen::BREAK( ostream &ret, int targState )
148 ret << "{ " << P() << " += 1; _goto_targ = " << _out << "; " <<
149 CTRL_FLOW() << " continue _goto;}";
152 void JavaTabCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
154 ret << CS() << " = " << nextDest << ";";
157 void JavaTabCodeGen::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
159 ret << CS() << " = (";
160 INLINE_LIST( ret, ilItem->children, 0, inFinish );
164 void JavaTabCodeGen::EXEC( ostream &ret, GenInlineItem *item, int targState, int inFinish )
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 );
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 )
179 for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) {
180 switch ( item->type ) {
181 case GenInlineItem::Text:
184 case GenInlineItem::Goto:
185 GOTO( ret, item->targState->id, inFinish );
187 case GenInlineItem::Call:
188 CALL( ret, item->targState->id, targState, inFinish );
190 case GenInlineItem::Next:
191 NEXT( ret, item->targState->id, inFinish );
193 case GenInlineItem::Ret:
194 RET( ret, inFinish );
196 case GenInlineItem::PChar:
199 case GenInlineItem::Char:
202 case GenInlineItem::Hold:
205 case GenInlineItem::Exec:
206 EXEC( ret, item, targState, inFinish );
208 case GenInlineItem::Curs:
211 case GenInlineItem::Targs:
212 ret << "(" << CS() << ")";
214 case GenInlineItem::Entry:
215 ret << item->targState->id;
217 case GenInlineItem::GotoExpr:
218 GOTO_EXPR( ret, item, inFinish );
220 case GenInlineItem::CallExpr:
221 CALL_EXPR( ret, item, targState, inFinish );
223 case GenInlineItem::NextExpr:
224 NEXT_EXPR( ret, item, inFinish );
226 case GenInlineItem::LmSwitch:
227 LM_SWITCH( ret, item, targState, inFinish );
229 case GenInlineItem::LmSetActId:
230 SET_ACT( ret, item );
232 case GenInlineItem::LmSetTokEnd:
233 SET_TOKEND( ret, item );
235 case GenInlineItem::LmGetTokEnd:
236 GET_TOKEND( ret, item );
238 case GenInlineItem::LmInitTokStart:
239 INIT_TOKSTART( ret, item );
241 case GenInlineItem::LmInitAct:
242 INIT_ACT( ret, item );
244 case GenInlineItem::LmSetTokStart:
245 SET_TOKSTART( ret, item );
247 case GenInlineItem::SubAction:
248 SUB_ACTION( ret, item, targState, inFinish );
250 case GenInlineItem::Break:
251 BREAK( ret, targState );
257 string JavaTabCodeGen::DATA_PREFIX()
260 return FSM_NAME() + "_";
264 /* Emit the alphabet data type. */
265 string JavaTabCodeGen::ALPH_TYPE()
267 string ret = keyOps->alphType->data1;
268 if ( keyOps->alphType->data2 != 0 ) {
270 ret += + keyOps->alphType->data2;
275 /* Emit the alphabet data type. */
276 string JavaTabCodeGen::WIDE_ALPH_TYPE()
279 if ( redFsm->maxKey <= keyOps->maxKey )
282 long long maxKeyVal = redFsm->maxKey.getLongLong();
283 HostType *wideType = keyOps->typeSubsumes( keyOps->isSigned, maxKeyVal );
284 assert( wideType != 0 );
286 ret = wideType->data1;
287 if ( wideType->data2 != 0 ) {
289 ret += wideType->data2;
297 void JavaTabCodeGen::COND_TRANSLATE()
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;"
306 " int _upper = _keys + (_klen<<1) - 2;\n"
308 " if ( _upper < _lower )\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"
317 " switch ( " << C() << "[" << CO() << "[" << CS() << "]"
318 " + ((_mid - _keys)>>1)] ) {\n"
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";
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";
349 void JavaTabCodeGen::LOCATE_TRANS()
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"
359 " int _upper = _keys + _klen - 1;\n"
361 " if ( _upper < _lower )\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"
370 " _trans += (_mid - _keys);\n"
375 " _trans += _klen;\n"
378 " _klen = " << RL() << "[" << CS() << "];\n"
379 " if ( _klen > 0 ) {\n"
380 " int _lower = _keys;\n"
382 " int _upper = _keys + (_klen<<1) - 2;\n"
384 " if ( _upper < _lower )\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"
393 " _trans += ((_mid - _keys)>>1);\n"
397 " _trans += _klen;\n"
399 " } while (false);\n"
403 /* Determine if we should use indicies or not. */
404 void JavaTabCodeGen::calcIndexSize()
406 int sizeWithInds = 0, sizeWithoutInds = 0;
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;
414 sizeWithInds += arrayTypeSize(redFsm->maxState) * redFsm->transSet.length();
415 if ( redFsm->anyActions() )
416 sizeWithInds += arrayTypeSize(redFsm->maxActionLoc) * redFsm->transSet.length();
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;
427 /* If using indicies reduces the size, use them. */
428 useIndicies = sizeWithInds < sizeWithoutInds;
431 int JavaTabCodeGen::TO_STATE_ACTION( RedStateAp *state )
434 if ( state->toStateAction != 0 )
435 act = state->toStateAction->location+1;
439 int JavaTabCodeGen::FROM_STATE_ACTION( RedStateAp *state )
442 if ( state->fromStateAction != 0 )
443 act = state->fromStateAction->location+1;
447 int JavaTabCodeGen::EOF_ACTION( RedStateAp *state )
450 if ( state->eofAction != 0 )
451 act = state->eofAction->location+1;
456 int JavaTabCodeGen::TRANS_ACTION( RedTransAp *trans )
458 /* If there are actions, emit them. Otherwise emit zero. */
460 if ( trans->action != 0 )
461 act = trans->action->location+1;
465 std::ostream &JavaTabCodeGen::TO_STATE_ACTION_SWITCH()
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 );
478 genLineDirective( out );
482 std::ostream &JavaTabCodeGen::FROM_STATE_ACTION_SWITCH()
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 );
495 genLineDirective( out );
499 std::ostream &JavaTabCodeGen::EOF_ACTION_SWITCH()
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 );
512 genLineDirective( out );
517 std::ostream &JavaTabCodeGen::ACTION_SWITCH()
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 );
530 genLineDirective( out );
534 std::ostream &JavaTabCodeGen::COND_OFFSETS()
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() );
541 /* Move the key offset ahead. */
542 curKeyOffset += st->stateCondList.length();
547 std::ostream &JavaTabCodeGen::KEY_OFFSETS()
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() );
554 /* Move the key offset ahead. */
555 curKeyOffset += st->outSingle.length() + st->outRange.length()*2;
561 std::ostream &JavaTabCodeGen::INDEX_OFFSETS()
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() );
568 /* Move the index offset ahead. */
569 curIndOffset += st->outSingle.length() + st->outRange.length();
570 if ( st->defTrans != 0 )
576 std::ostream &JavaTabCodeGen::COND_LENS()
578 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
579 /* Write singles length. */
580 ARRAY_ITEM( INT(st->stateCondList.length()), st.last() );
586 std::ostream &JavaTabCodeGen::SINGLE_LENS()
588 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
589 /* Write singles length. */
590 ARRAY_ITEM( INT(st->outSingle.length()), st.last() );
595 std::ostream &JavaTabCodeGen::RANGE_LENS()
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() );
604 std::ostream &JavaTabCodeGen::TO_STATE_ACTIONS()
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() );
613 std::ostream &JavaTabCodeGen::FROM_STATE_ACTIONS()
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() );
622 std::ostream &JavaTabCodeGen::EOF_ACTIONS()
624 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
625 /* Write any eof action. */
626 ARRAY_ITEM( INT(EOF_ACTION(st)), st.last() );
631 std::ostream &JavaTabCodeGen::EOF_TRANS()
633 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
634 /* Write any eof action. */
636 if ( st->eofTrans != 0 ) {
637 assert( st->eofTrans->pos >= 0 );
638 trans = st->eofTrans->pos+1;
641 /* Write any eof action. */
642 ARRAY_ITEM( INT(trans), st.last() );
648 std::ostream &JavaTabCodeGen::COND_KEYS()
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++ ) {
654 ARRAY_ITEM( KEY( sc->lowKey ), false );
655 ARRAY_ITEM( KEY( sc->highKey ), false );
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 );
665 std::ostream &JavaTabCodeGen::COND_SPACES()
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++ ) {
671 ARRAY_ITEM( KEY( sc->condSpace->condSpaceId ), false );
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 );
681 std::ostream &JavaTabCodeGen::KEYS()
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 );
689 /* Loop the state's transitions. */
690 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
692 ARRAY_ITEM( KEY( rtel->lowKey ), false );
695 ARRAY_ITEM( KEY( rtel->highKey ), false );
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 );
705 std::ostream &JavaTabCodeGen::INDICIES()
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 );
713 /* Walk the ranges. */
714 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
715 ARRAY_ITEM( KEY( rtel->value->id ), false );
718 /* The state's default index goes next. */
719 if ( st->defTrans != 0 ) {
720 ARRAY_ITEM( KEY( st->defTrans->id ), false );
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 );
730 std::ostream &JavaTabCodeGen::TRANS_TARGS()
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 );
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 );
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 );
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 );
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 );
771 std::ostream &JavaTabCodeGen::TRANS_ACTIONS()
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 );
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 );
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 );
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 );
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 );
806 std::ostream &JavaTabCodeGen::TRANS_TARGS_WI()
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;
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];
819 /* Write out the target state. */
820 ARRAY_ITEM( INT(trans->targ->id), ( t >= redFsm->transSet.length()-1 ) );
827 std::ostream &JavaTabCodeGen::TRANS_ACTIONS_WI()
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;
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 ) );
844 void JavaTabCodeGen::writeExports()
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";
855 void JavaTabCodeGen::writeStart()
857 out << START_STATE_ID();
860 void JavaTabCodeGen::writeFirstFinal()
862 out << FIRST_FINAL_STATE();
865 void JavaTabCodeGen::writeError()
867 out << ERROR_STATE();
870 void JavaTabCodeGen::writeData()
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() );
881 if ( redFsm->anyConditions() ) {
882 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondOffset), CO() );
887 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondLen), CL() );
892 OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
897 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpaceId), C() );
903 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxKeyOffset), KO() );
908 OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
913 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSingleLen), SL() );
918 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxRangeLen), RL() );
923 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset), IO() );
929 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
934 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
939 if ( redFsm->anyActions() ) {
940 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
947 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
952 if ( redFsm->anyActions() ) {
953 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
960 if ( redFsm->anyToStateActions() ) {
961 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
967 if ( redFsm->anyFromStateActions() ) {
968 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
969 FROM_STATE_ACTIONS();
974 if ( redFsm->anyEofActions() ) {
975 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
981 if ( redFsm->anyEofTrans() ) {
982 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset+1), ET() );
988 if ( redFsm->startState != 0 )
989 STATIC_VAR( "int", START() ) << " = " << START_STATE_ID() << ";\n";
992 STATIC_VAR( "int" , FIRST_FINAL() ) << " = " << FIRST_FINAL_STATE() << ";\n";
995 STATIC_VAR( "int", ERROR() ) << " = " << ERROR_STATE() << ";\n";
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";
1008 void JavaTabCodeGen::writeExec()
1014 if ( redFsm->anyRegCurStateRef() )
1019 " int _trans = 0;\n";
1021 if ( redFsm->anyConditions() )
1022 out << " int _widec;\n";
1024 if ( redFsm->anyToStateActions() || redFsm->anyRegActions() ||
1025 redFsm->anyFromStateActions() )
1034 " int _goto_targ = 0;\n"
1038 " _goto: while (true) {\n"
1039 " switch ( _goto_targ ) {\n"
1044 " if ( " << P() << " == " << PE() << " ) {\n"
1045 " _goto_targ = " << _test_eof << ";\n"
1046 " continue _goto;\n"
1050 if ( redFsm->errState != 0 ) {
1052 " if ( " << CS() << " == " << redFsm->errState->id << " ) {\n"
1053 " _goto_targ = " << _out << ";\n"
1054 " continue _goto;\n"
1058 out << "case " << _resume << ":\n";
1060 if ( redFsm->anyFromStateActions() ) {
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() <<
1072 if ( redFsm->anyConditions() )
1078 out << " _trans = " << I() << "[_trans];\n";
1080 if ( redFsm->anyEofTrans() )
1081 out << "case " << _eof_trans << ":\n";
1083 if ( redFsm->anyRegCurStateRef() )
1084 out << " _ps = " << CS() << ";\n";
1087 " " << CS() << " = " << TT() << "[_trans];\n"
1090 if ( redFsm->anyRegActions() ) {
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"
1105 out << "case " << _again << ":\n";
1107 if ( redFsm->anyToStateActions() ) {
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() <<
1119 if ( redFsm->errState != 0 ) {
1121 " if ( " << CS() << " == " << redFsm->errState->id << " ) {\n"
1122 " _goto_targ = " << _out << ";\n"
1123 " continue _goto;\n"
1129 " if ( ++" << P() << " != " << PE() << " ) {\n"
1130 " _goto_targ = " << _resume << ";\n"
1131 " continue _goto;\n"
1136 " " << P() << " += 1;\n"
1137 " _goto_targ = " << _resume << ";\n"
1138 " continue _goto;\n";
1141 out << "case " << _test_eof << ":\n";
1143 if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
1145 " if ( " << P() << " == " << EOFV() << " )\n"
1148 if ( redFsm->anyEofTrans() ) {
1150 " if ( " << ET() << "[" << CS() << "] > 0 ) {\n"
1151 " _trans = " << ET() << "[" << CS() << "] - 1;\n"
1152 " _goto_targ = " << _eof_trans << ";\n"
1153 " continue _goto;\n"
1157 if ( redFsm->anyEofActions() ) {
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() <<
1173 out << "case " << _out << ":\n";
1175 /* The switch and goto loop. */
1177 out << " break; }\n";
1179 /* The execute block. */
1183 std::ostream &JavaTabCodeGen::OPEN_ARRAY( string type, string name )
1190 out << "private static " << type << "[] init_" << name << "_0()\n"
1192 "return new " << type << " [] {\n\t";
1196 std::ostream &JavaTabCodeGen::ARRAY_ITEM( string item, bool last )
1200 out << setw(5) << setiosflags(ios::right) << item;
1203 if ( item_count % SAIIC == 0 ) {
1204 out << "\n\t};\n};\n"
1205 "private static "<< array_type << "[] init_" <<
1206 array_name << "_" << div_count << "()\n"
1208 "return new " << array_type << " [] {\n\t";
1210 } else if (item_count % IALL == 0) {
1219 std::ostream &JavaTabCodeGen::CLOSE_ARRAY()
1221 out << "\n\t};\n}\n\n";
1223 if (item_count < SAIIC) {
1224 out << "private static final " << array_type << " " << array_name <<
1225 "[] = init_" << array_name << "_0();\n\n";
1227 out << "private static final " << array_type << " [] combine_" << array_name
1229 << array_type << " [] combined = new " << array_type <<
1230 " [ " << item_count << " ];\n\t";
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";
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";
1242 out << "return combined;\n}\n";
1243 out << "private static final " << array_type << " [] " << array_name <<
1244 " = combine_" << array_name << "();";
1250 std::ostream &JavaTabCodeGen::STATIC_VAR( string type, string name )
1252 out << "static final " << type << " " << name;
1256 string JavaTabCodeGen::ARR_OFF( string ptr, string offset )
1258 return ptr + " + " + offset;
1261 string JavaTabCodeGen::CAST( string type )
1263 return "(" + type + ")";
1266 string JavaTabCodeGen::NULL_ITEM()
1268 /* In java we use integers instead of pointers. */
1272 string JavaTabCodeGen::GET_KEY()
1275 if ( getKeyExpr != 0 ) {
1276 /* Emit the user supplied method of retrieving the key. */
1278 INLINE_LIST( ret, getKeyExpr, 0, false );
1282 /* Expression for retrieving the key, use simple dereference. */
1283 ret << DATA() << "[" << P() << "]";
1288 string JavaTabCodeGen::CTRL_FLOW()
1290 return "if (true) ";
1293 unsigned int JavaTabCodeGen::arrayTypeSize( unsigned long maxVal )
1295 long long maxValLL = (long long) maxVal;
1296 HostType *arrayType = keyOps->typeSubsumes( maxValLL );
1297 assert( arrayType != 0 );
1298 return arrayType->size;
1301 string JavaTabCodeGen::ARRAY_TYPE( unsigned long maxVal )
1303 long long maxValLL = (long long) maxVal;
1304 HostType *arrayType = keyOps->typeSubsumes( maxValLL );
1305 assert( arrayType != 0 );
1307 string ret = arrayType->data1;
1308 if ( arrayType->data2 != 0 ) {
1310 ret += arrayType->data2;
1316 /* Write out the fsm name. */
1317 string JavaTabCodeGen::FSM_NAME()
1322 /* Emit the offset of the start state as a decimal integer. */
1323 string JavaTabCodeGen::START_STATE_ID()
1326 ret << redFsm->startState->id;
1330 /* Write out the array of actions. */
1331 std::ostream &JavaTabCodeGen::ACTIONS_ARRAY()
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 );
1338 for ( GenActionTable::Iter item = act->key; item.lte(); item++ )
1339 ARRAY_ITEM( INT(item->value->actionId), (act.last() && item.last()) );
1345 string JavaTabCodeGen::ACCESS()
1348 if ( accessExpr != 0 )
1349 INLINE_LIST( ret, accessExpr, 0, false );
1353 string JavaTabCodeGen::P()
1360 INLINE_LIST( ret, pExpr, 0, false );
1366 string JavaTabCodeGen::PE()
1373 INLINE_LIST( ret, peExpr, 0, false );
1379 string JavaTabCodeGen::EOFV()
1386 INLINE_LIST( ret, eofExpr, 0, false );
1392 string JavaTabCodeGen::CS()
1396 ret << ACCESS() << "cs";
1398 /* Emit the user supplied method of retrieving the key. */
1400 INLINE_LIST( ret, csExpr, 0, false );
1406 string JavaTabCodeGen::TOP()
1410 ret << ACCESS() + "top";
1413 INLINE_LIST( ret, topExpr, 0, false );
1419 string JavaTabCodeGen::STACK()
1422 if ( stackExpr == 0 )
1423 ret << ACCESS() + "stack";
1426 INLINE_LIST( ret, stackExpr, 0, false );
1432 string JavaTabCodeGen::ACT()
1436 ret << ACCESS() + "act";
1439 INLINE_LIST( ret, actExpr, 0, false );
1445 string JavaTabCodeGen::TOKSTART()
1448 if ( tokstartExpr == 0 )
1449 ret << ACCESS() + "ts";
1452 INLINE_LIST( ret, tokstartExpr, 0, false );
1458 string JavaTabCodeGen::TOKEND()
1461 if ( tokendExpr == 0 )
1462 ret << ACCESS() + "te";
1465 INLINE_LIST( ret, tokendExpr, 0, false );
1471 string JavaTabCodeGen::DATA()
1474 if ( dataExpr == 0 )
1475 ret << ACCESS() + "data";
1478 INLINE_LIST( ret, dataExpr, 0, false );
1485 string JavaTabCodeGen::GET_WIDE_KEY()
1487 if ( redFsm->anyConditions() )
1493 string JavaTabCodeGen::GET_WIDE_KEY( RedStateAp *state )
1495 if ( state->stateCondList.length() > 0 )
1501 /* Write out level number of tabs. Makes the nested binary search nice
1503 string JavaTabCodeGen::TABS( int level )
1506 while ( level-- > 0 )
1511 string JavaTabCodeGen::KEY( Key key )
1514 if ( keyOps->isSigned || !hostLang->explicitUnsigned )
1515 ret << key.getVal();
1517 ret << (unsigned long) key.getVal();
1521 string JavaTabCodeGen::INT( int i )
1528 void JavaTabCodeGen::LM_SWITCH( ostream &ret, GenInlineItem *item,
1529 int targState, int inFinish )
1532 " switch( " << ACT() << " ) {\n";
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";
1539 ret << " case " << lma->lmId << ":\n";
1541 /* Write the block and close it off. */
1543 INLINE_LIST( ret, lma->children, targState, inFinish );
1554 void JavaTabCodeGen::SET_ACT( ostream &ret, GenInlineItem *item )
1556 ret << ACT() << " = " << item->lmId << ";";
1559 void JavaTabCodeGen::SET_TOKEND( ostream &ret, GenInlineItem *item )
1561 /* The tokend action sets tokend. */
1562 ret << TOKEND() << " = " << P();
1563 if ( item->offset != 0 )
1564 out << "+" << item->offset;
1568 void JavaTabCodeGen::GET_TOKEND( ostream &ret, GenInlineItem *item )
1573 void JavaTabCodeGen::INIT_TOKSTART( ostream &ret, GenInlineItem *item )
1575 ret << TOKSTART() << " = " << NULL_ITEM() << ";";
1578 void JavaTabCodeGen::INIT_ACT( ostream &ret, GenInlineItem *item )
1580 ret << ACT() << " = 0;";
1583 void JavaTabCodeGen::SET_TOKSTART( ostream &ret, GenInlineItem *item )
1585 ret << TOKSTART() << " = " << P() << ";";
1588 void JavaTabCodeGen::SUB_ACTION( ostream &ret, GenInlineItem *item,
1589 int targState, bool inFinish )
1591 if ( item->children->length() > 0 ) {
1592 /* Write the block and close it off. */
1594 INLINE_LIST( ret, item->children, targState, inFinish );
1599 void JavaTabCodeGen::ACTION( ostream &ret, GenAction *action, int targState, bool inFinish )
1601 /* Write the preprocessor line info for going into the source file. */
1602 javaLineDirective( ret, sourceFileName, action->loc.line );
1604 /* Write the block and close it off. */
1606 INLINE_LIST( ret, action->inlineList, targState, inFinish );
1610 void JavaTabCodeGen::CONDITION( ostream &ret, GenAction *condition )
1613 javaLineDirective( ret, sourceFileName, condition->loc.line );
1614 INLINE_LIST( ret, condition->inlineList, 0, false );
1617 string JavaTabCodeGen::ERROR_STATE()
1620 if ( redFsm->errState != 0 )
1621 ret << redFsm->errState->id;
1627 string JavaTabCodeGen::FIRST_FINAL_STATE()
1630 if ( redFsm->firstFinState != 0 )
1631 ret << redFsm->firstFinState->id;
1633 ret << redFsm->nextStateId;
1637 void JavaTabCodeGen::writeInit()
1642 out << "\t" << CS() << " = " << START() << ";\n";
1644 /* If there are any calls, then the stack top needs initialization. */
1645 if ( redFsm->anyActionCalls() || redFsm->anyActionRets() )
1646 out << "\t" << TOP() << " = 0;\n";
1648 if ( hasLongestMatch ) {
1650 " " << TOKSTART() << " = " << NULL_ITEM() << ";\n"
1651 " " << TOKEND() << " = " << NULL_ITEM() << ";\n"
1652 " " << ACT() << " = 0;\n";
1657 void JavaTabCodeGen::finishRagelDef()
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();
1663 /* Choose default transitions and the single transition. */
1664 redFsm->chooseDefaultSpan();
1666 /* Maybe do flat expand, otherwise choose single. */
1667 redFsm->chooseSingle();
1669 /* If any errors have occured in the input file then don't write anything. */
1670 if ( gblErrorCount > 0 )
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. */
1678 /* Determine if we should use indicies. */
1682 ostream &JavaTabCodeGen::source_warning( const InputLoc &loc )
1684 cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": warning: ";
1688 ostream &JavaTabCodeGen::source_error( const InputLoc &loc )
1691 assert( sourceFileName != 0 );
1692 cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": ";