2 * Copyright 2006-2007 Adrian Thurston <thurston@cs.queensu.ca>
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
23 #include "rlgen-java.h"
24 #include "javacodegen.h"
30 /* Integer array line length. */
33 /* Static array initialization item count
34 * (should be multiple of IALL). */
38 using std::ostringstream;
43 void lineDirective( ostream &out, char *fileName, int line )
45 /* Write the preprocessor line info for to the input file. */
46 out << "// line " << line << " \"";
47 for ( char *pc = fileName; *pc != 0; pc++ ) {
56 void genLineDirective( ostream &out )
58 std::streambuf *sbuf = out.rdbuf();
59 output_filter *filter = static_cast<output_filter*>(sbuf);
60 lineDirective( out, filter->fileName, filter->line + 1 );
63 void JavaTabCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
65 ret << "{" << CS() << " = " << gotoDest << "; " <<
66 CTRL_FLOW() << "break _again;}";
69 void JavaTabCodeGen::GOTO_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish )
71 ret << "{" << CS() << " = (";
72 INLINE_LIST( ret, ilItem->children, 0, inFinish );
73 ret << "); " << CTRL_FLOW() << "break _again;}";
76 void JavaTabCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
78 ret << "{" << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = " <<
79 callDest << "; " << CTRL_FLOW() << "break _again;}";
82 void JavaTabCodeGen::CALL_EXPR( ostream &ret, InlineItem *ilItem, int targState, bool inFinish )
84 ret << "{" << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = (";
85 INLINE_LIST( ret, ilItem->children, targState, inFinish );
86 ret << "); " << CTRL_FLOW() << "break _again;}";
89 void JavaTabCodeGen::RET( ostream &ret, bool inFinish )
91 ret << "{" << CS() << " = " << STACK() << "[--" << TOP()
92 << "]; " << CTRL_FLOW() << "break _again;}";
95 void JavaTabCodeGen::BREAK( ostream &ret, int targState )
97 ret << CTRL_FLOW() << "break _resume;";
100 void JavaTabCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
102 ret << CS() << " = " << nextDest << ";";
105 void JavaTabCodeGen::NEXT_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish )
107 ret << CS() << " = (";
108 INLINE_LIST( ret, ilItem->children, 0, inFinish );
112 void JavaTabCodeGen::EXEC( ostream &ret, InlineItem *item, int targState, int inFinish )
114 /* The parser gives fexec two children. The double brackets are for D
115 * code. If the inline list is a single word it will get interpreted as a
116 * C-style cast by the D compiler. */
117 ret << "{" << P() << " = ((";
118 INLINE_LIST( ret, item->children, targState, inFinish );
122 void JavaTabCodeGen::EXECTE( ostream &ret, InlineItem *item, int targState, int inFinish )
124 /* Tokend version of exec. */
126 /* The parser gives fexec two children. The double brackets are for D
127 * code. If the inline list is a single word it will get interpreted as a
128 * C-style cast by the D compiler. */
129 ret << "{" << TOKEND() << " = ((";
130 INLINE_LIST( ret, item->children, targState, inFinish );
134 /* Write out an inline tree structure. Walks the list and possibly calls out
135 * to virtual functions than handle language specific items in the tree. */
136 void JavaTabCodeGen::INLINE_LIST( ostream &ret, InlineList *inlineList,
137 int targState, bool inFinish )
139 for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
140 switch ( item->type ) {
141 case InlineItem::Text:
144 case InlineItem::Goto:
145 GOTO( ret, item->targState->id, inFinish );
147 case InlineItem::Call:
148 CALL( ret, item->targState->id, targState, inFinish );
150 case InlineItem::Next:
151 NEXT( ret, item->targState->id, inFinish );
153 case InlineItem::Ret:
154 RET( ret, inFinish );
156 case InlineItem::PChar:
159 case InlineItem::Char:
162 case InlineItem::Hold:
165 case InlineItem::Exec:
166 EXEC( ret, item, targState, inFinish );
168 case InlineItem::HoldTE:
169 ret << TOKEND() << "--;";
171 case InlineItem::ExecTE:
172 EXECTE( ret, item, targState, inFinish );
174 case InlineItem::Curs:
177 case InlineItem::Targs:
178 ret << "(" << CS() << ")";
180 case InlineItem::Entry:
181 ret << item->targState->id;
183 case InlineItem::GotoExpr:
184 GOTO_EXPR( ret, item, inFinish );
186 case InlineItem::CallExpr:
187 CALL_EXPR( ret, item, targState, inFinish );
189 case InlineItem::NextExpr:
190 NEXT_EXPR( ret, item, inFinish );
192 case InlineItem::LmSwitch:
193 LM_SWITCH( ret, item, targState, inFinish );
195 case InlineItem::LmSetActId:
196 SET_ACT( ret, item );
198 case InlineItem::LmSetTokEnd:
199 SET_TOKEND( ret, item );
201 case InlineItem::LmGetTokEnd:
202 GET_TOKEND( ret, item );
204 case InlineItem::LmInitTokStart:
205 INIT_TOKSTART( ret, item );
207 case InlineItem::LmInitAct:
208 INIT_ACT( ret, item );
210 case InlineItem::LmSetTokStart:
211 SET_TOKSTART( ret, item );
213 case InlineItem::SubAction:
214 SUB_ACTION( ret, item, targState, inFinish );
216 case InlineItem::Break:
217 BREAK( ret, targState );
223 string JavaTabCodeGen::DATA_PREFIX()
226 return FSM_NAME() + "_";
230 /* Emit the alphabet data type. */
231 string JavaTabCodeGen::ALPH_TYPE()
233 string ret = keyOps->alphType->data1;
234 if ( keyOps->alphType->data2 != 0 ) {
236 ret += + keyOps->alphType->data2;
241 /* Emit the alphabet data type. */
242 string JavaTabCodeGen::WIDE_ALPH_TYPE()
245 if ( redFsm->maxKey <= keyOps->maxKey )
248 long long maxKeyVal = redFsm->maxKey.getLongLong();
249 HostType *wideType = keyOps->typeSubsumes( keyOps->isSigned, maxKeyVal );
250 assert( wideType != 0 );
252 ret = wideType->data1;
253 if ( wideType->data2 != 0 ) {
255 ret += wideType->data2;
263 void JavaTabCodeGen::COND_TRANSLATE()
266 " _widec = " << GET_KEY() << ";\n"
267 " _keys = " << CO() << "[" << CS() << "]*2\n;"
268 " _klen = " << CL() << "[" << CS() << "];\n"
269 " if ( _klen > 0 ) {\n"
270 " int _lower = _keys\n;"
272 " int _upper = _keys + (_klen<<1) - 2;\n"
274 " if ( _upper < _lower )\n"
277 " _mid = _lower + (((_upper-_lower) >> 1) & ~1);\n"
278 " if ( " << GET_WIDE_KEY() << " < " << CK() << "[_mid] )\n"
279 " _upper = _mid - 2;\n"
280 " else if ( " << GET_WIDE_KEY() << " > " << CK() << "[_mid] )\n"
281 " _lower = _mid + 2;\n"
283 " switch ( " << C() << "[" << CO() << "[" << CS() << "]"
284 " + ((_mid - _keys)>>1)] ) {\n"
287 for ( CondSpaceList::Iter csi = condSpaceList; csi.lte(); csi++ ) {
288 CondSpace *condSpace = csi;
289 out << " case " << condSpace->condSpaceId << ": {\n";
290 out << TABS(2) << "_widec = " << KEY(condSpace->baseKey) <<
291 " + (" << GET_KEY() << " - " << KEY(keyOps->minKey) << ");\n";
293 for ( CondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
294 out << TABS(2) << "if ( ";
295 CONDITION( out, *csi );
296 Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize());
297 out << " ) _widec += " << condValOffset << ";\n";
315 void JavaTabCodeGen::LOCATE_TRANS()
319 " _keys = " << KO() << "[" << CS() << "]" << ";\n"
320 " _trans = " << IO() << "[" << CS() << "];\n"
321 " _klen = " << SL() << "[" << CS() << "];\n"
322 " if ( _klen > 0 ) {\n"
323 " int _lower = _keys;\n"
325 " int _upper = _keys + _klen - 1;\n"
327 " if ( _upper < _lower )\n"
330 " _mid = _lower + ((_upper-_lower) >> 1);\n"
331 " if ( " << GET_WIDE_KEY() << " < " << K() << "[_mid] )\n"
332 " _upper = _mid - 1;\n"
333 " else if ( " << GET_WIDE_KEY() << " > " << K() << "[_mid] )\n"
334 " _lower = _mid + 1;\n"
336 " _trans += (_mid - _keys);\n"
341 " _trans += _klen;\n"
344 " _klen = " << RL() << "[" << CS() << "];\n"
345 " if ( _klen > 0 ) {\n"
346 " int _lower = _keys;\n"
348 " int _upper = _keys + (_klen<<1) - 2;\n"
350 " if ( _upper < _lower )\n"
353 " _mid = _lower + (((_upper-_lower) >> 1) & ~1);\n"
354 " if ( " << GET_WIDE_KEY() << " < " << K() << "[_mid] )\n"
355 " _upper = _mid - 2;\n"
356 " else if ( " << GET_WIDE_KEY() << " > " << K() << "[_mid+1] )\n"
357 " _lower = _mid + 2;\n"
359 " _trans += ((_mid - _keys)>>1);\n"
363 " _trans += _klen;\n"
365 " } while (false);\n"
369 /* Determine if we should use indicies or not. */
370 void JavaTabCodeGen::calcIndexSize()
372 int sizeWithInds = 0, sizeWithoutInds = 0;
374 /* Calculate cost of using with indicies. */
375 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
376 int totalIndex = st->outSingle.length() + st->outRange.length() +
377 (st->defTrans == 0 ? 0 : 1);
378 sizeWithInds += arrayTypeSize(redFsm->maxIndex) * totalIndex;
380 sizeWithInds += arrayTypeSize(redFsm->maxState) * redFsm->transSet.length();
381 if ( redFsm->anyActions() )
382 sizeWithInds += arrayTypeSize(redFsm->maxActionLoc) * redFsm->transSet.length();
384 /* Calculate the cost of not using indicies. */
385 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
386 int totalIndex = st->outSingle.length() + st->outRange.length() +
387 (st->defTrans == 0 ? 0 : 1);
388 sizeWithoutInds += arrayTypeSize(redFsm->maxState) * totalIndex;
389 if ( redFsm->anyActions() )
390 sizeWithoutInds += arrayTypeSize(redFsm->maxActionLoc) * totalIndex;
393 /* If using indicies reduces the size, use them. */
394 useIndicies = sizeWithInds < sizeWithoutInds;
397 int JavaTabCodeGen::TO_STATE_ACTION( RedStateAp *state )
400 if ( state->toStateAction != 0 )
401 act = state->toStateAction->location+1;
405 int JavaTabCodeGen::FROM_STATE_ACTION( RedStateAp *state )
408 if ( state->fromStateAction != 0 )
409 act = state->fromStateAction->location+1;
413 int JavaTabCodeGen::EOF_ACTION( RedStateAp *state )
416 if ( state->eofAction != 0 )
417 act = state->eofAction->location+1;
422 int JavaTabCodeGen::TRANS_ACTION( RedTransAp *trans )
424 /* If there are actions, emit them. Otherwise emit zero. */
426 if ( trans->action != 0 )
427 act = trans->action->location+1;
431 std::ostream &JavaTabCodeGen::TO_STATE_ACTION_SWITCH()
433 /* Walk the list of functions, printing the cases. */
434 for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
435 /* Write out referenced actions. */
436 if ( act->numToStateRefs > 0 ) {
437 /* Write the case label, the action and the case break. */
438 out << "\tcase " << act->actionId << ":\n";
439 ACTION( out, act, 0, false );
444 genLineDirective( out );
448 std::ostream &JavaTabCodeGen::FROM_STATE_ACTION_SWITCH()
450 /* Walk the list of functions, printing the cases. */
451 for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
452 /* Write out referenced actions. */
453 if ( act->numFromStateRefs > 0 ) {
454 /* Write the case label, the action and the case break. */
455 out << "\tcase " << act->actionId << ":\n";
456 ACTION( out, act, 0, false );
461 genLineDirective( out );
465 std::ostream &JavaTabCodeGen::EOF_ACTION_SWITCH()
467 /* Walk the list of functions, printing the cases. */
468 for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
469 /* Write out referenced actions. */
470 if ( act->numEofRefs > 0 ) {
471 /* Write the case label, the action and the case break. */
472 out << "\tcase " << act->actionId << ":\n";
473 ACTION( out, act, 0, true );
478 genLineDirective( out );
483 std::ostream &JavaTabCodeGen::ACTION_SWITCH()
485 /* Walk the list of functions, printing the cases. */
486 for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
487 /* Write out referenced actions. */
488 if ( act->numTransRefs > 0 ) {
489 /* Write the case label, the action and the case break. */
490 out << "\tcase " << act->actionId << ":\n";
491 ACTION( out, act, 0, false );
496 genLineDirective( out );
500 std::ostream &JavaTabCodeGen::COND_OFFSETS()
502 int curKeyOffset = 0;
503 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
504 /* Write the key offset. */
505 ARRAY_ITEM( INT(curKeyOffset), st.last() );
507 /* Move the key offset ahead. */
508 curKeyOffset += st->stateCondList.length();
513 std::ostream &JavaTabCodeGen::KEY_OFFSETS()
515 int curKeyOffset = 0;
516 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
517 /* Write the key offset. */
518 ARRAY_ITEM( INT(curKeyOffset), st.last() );
520 /* Move the key offset ahead. */
521 curKeyOffset += st->outSingle.length() + st->outRange.length()*2;
527 std::ostream &JavaTabCodeGen::INDEX_OFFSETS()
529 int curIndOffset = 0;
530 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
531 /* Write the index offset. */
532 ARRAY_ITEM( INT(curIndOffset), st.last() );
534 /* Move the index offset ahead. */
535 curIndOffset += st->outSingle.length() + st->outRange.length();
536 if ( st->defTrans != 0 )
542 std::ostream &JavaTabCodeGen::COND_LENS()
544 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
545 /* Write singles length. */
546 ARRAY_ITEM( INT(st->stateCondList.length()), st.last() );
552 std::ostream &JavaTabCodeGen::SINGLE_LENS()
554 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
555 /* Write singles length. */
556 ARRAY_ITEM( INT(st->outSingle.length()), st.last() );
561 std::ostream &JavaTabCodeGen::RANGE_LENS()
563 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
564 /* Emit length of range index. */
565 ARRAY_ITEM( INT(st->outRange.length()), st.last() );
570 std::ostream &JavaTabCodeGen::TO_STATE_ACTIONS()
572 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
573 /* Write any eof action. */
574 ARRAY_ITEM( INT(TO_STATE_ACTION(st)), st.last() );
579 std::ostream &JavaTabCodeGen::FROM_STATE_ACTIONS()
581 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
582 /* Write any eof action. */
583 ARRAY_ITEM( INT(FROM_STATE_ACTION(st)), st.last() );
588 std::ostream &JavaTabCodeGen::EOF_ACTIONS()
590 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
591 /* Write any eof action. */
592 ARRAY_ITEM( INT(EOF_ACTION(st)), st.last() );
597 std::ostream &JavaTabCodeGen::COND_KEYS()
599 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
600 /* Loop the state's transitions. */
601 for ( StateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
603 ARRAY_ITEM( KEY( sc->lowKey ), false );
604 ARRAY_ITEM( KEY( sc->highKey ), false );
608 /* Output one last number so we don't have to figure out when the last
609 * entry is and avoid writing a comma. */
610 ARRAY_ITEM( INT(0), true );
614 std::ostream &JavaTabCodeGen::COND_SPACES()
616 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
617 /* Loop the state's transitions. */
618 for ( StateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
620 ARRAY_ITEM( KEY( sc->condSpace->condSpaceId ), false );
624 /* Output one last number so we don't have to figure out when the last
625 * entry is and avoid writing a comma. */
626 ARRAY_ITEM( INT(0), true );
630 std::ostream &JavaTabCodeGen::KEYS()
632 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
633 /* Loop the singles. */
634 for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
635 ARRAY_ITEM( KEY( stel->lowKey ), false );
638 /* Loop the state's transitions. */
639 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
641 ARRAY_ITEM( KEY( rtel->lowKey ), false );
644 ARRAY_ITEM( KEY( rtel->highKey ), false );
648 /* Output one last number so we don't have to figure out when the last
649 * entry is and avoid writing a comma. */
650 ARRAY_ITEM( INT(0), true );
654 std::ostream &JavaTabCodeGen::INDICIES()
656 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
657 /* Walk the singles. */
658 for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
659 ARRAY_ITEM( KEY( stel->value->id ), false );
662 /* Walk the ranges. */
663 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
664 ARRAY_ITEM( KEY( rtel->value->id ), false );
667 /* The state's default index goes next. */
668 if ( st->defTrans != 0 ) {
669 ARRAY_ITEM( KEY( st->defTrans->id ), false );
673 /* Output one last number so we don't have to figure out when the last
674 * entry is and avoid writing a comma. */
675 ARRAY_ITEM( INT(0), true );
679 std::ostream &JavaTabCodeGen::TRANS_TARGS()
681 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
682 /* Walk the singles. */
683 for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
684 RedTransAp *trans = stel->value;
685 ARRAY_ITEM( KEY( trans->targ->id ), false );
688 /* Walk the ranges. */
689 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
690 RedTransAp *trans = rtel->value;
691 ARRAY_ITEM( KEY( trans->targ->id ), false );
694 /* The state's default target state. */
695 if ( st->defTrans != 0 ) {
696 RedTransAp *trans = st->defTrans;
697 ARRAY_ITEM( KEY( trans->targ->id ), false );
701 /* Output one last number so we don't have to figure out when the last
702 * entry is and avoid writing a comma. */
703 ARRAY_ITEM( INT(0), true );
708 std::ostream &JavaTabCodeGen::TRANS_ACTIONS()
710 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
711 /* Walk the singles. */
712 for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
713 RedTransAp *trans = stel->value;
714 ARRAY_ITEM( INT(TRANS_ACTION( trans )), false );
717 /* Walk the ranges. */
718 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
719 RedTransAp *trans = rtel->value;
720 ARRAY_ITEM( INT(TRANS_ACTION( trans )), false );
723 /* The state's default index goes next. */
724 if ( st->defTrans != 0 ) {
725 RedTransAp *trans = st->defTrans;
726 ARRAY_ITEM( INT(TRANS_ACTION( trans )), false );
730 /* Output one last number so we don't have to figure out when the last
731 * entry is and avoid writing a comma. */
732 ARRAY_ITEM( INT(0), true );
736 std::ostream &JavaTabCodeGen::TRANS_TARGS_WI()
738 /* Transitions must be written ordered by their id. */
739 RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
740 for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
741 transPtrs[trans->id] = trans;
743 /* Keep a count of the num of items in the array written. */
744 for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
745 /* Write out the target state. */
746 RedTransAp *trans = transPtrs[t];
747 ARRAY_ITEM( INT(trans->targ->id), ( t >= redFsm->transSet.length()-1 ) );
754 std::ostream &JavaTabCodeGen::TRANS_ACTIONS_WI()
756 /* Transitions must be written ordered by their id. */
757 RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
758 for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
759 transPtrs[trans->id] = trans;
761 /* Keep a count of the num of items in the array written. */
762 for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
763 /* Write the function for the transition. */
764 RedTransAp *trans = transPtrs[t];
765 ARRAY_ITEM( INT(TRANS_ACTION( trans )), ( t >= redFsm->transSet.length()-1 ) );
771 void JavaTabCodeGen::writeExports()
773 if ( exportList.length() > 0 ) {
774 for ( ExportList::Iter ex = exportList; ex.lte(); ex++ ) {
775 STATIC_VAR( ALPH_TYPE(), DATA_PREFIX() + "ex_" + ex->name )
776 << " = " << KEY(ex->key) << ";\n";
782 void JavaTabCodeGen::writeData()
784 /* If there are any transtion functions then output the array. If there
785 * are none, don't bother emitting an empty array that won't be used. */
786 if ( redFsm->anyActions() ) {
787 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
793 if ( redFsm->anyConditions() ) {
794 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondOffset), CO() );
799 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondLen), CL() );
804 OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
809 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpaceId), C() );
815 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxKeyOffset), KO() );
820 OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
825 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSingleLen), SL() );
830 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxRangeLen), RL() );
835 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset), IO() );
841 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
846 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
851 if ( redFsm->anyActions() ) {
852 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
859 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
864 if ( redFsm->anyActions() ) {
865 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
872 if ( redFsm->anyToStateActions() ) {
873 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
879 if ( redFsm->anyFromStateActions() ) {
880 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
881 FROM_STATE_ACTIONS();
886 if ( redFsm->anyEofActions() ) {
887 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
893 STATIC_VAR( "int", START() ) << " = " << START_STATE_ID() << ";\n";
895 if ( writeFirstFinal )
896 STATIC_VAR( "int" , FIRST_FINAL() ) << " = " << FIRST_FINAL_STATE() << ";\n";
899 STATIC_VAR( "int", ERROR() ) << " = " << ERROR_STATE() << ";\n";
903 if ( entryPointNames.length() > 0 ) {
904 for ( EntryNameVect::Iter en = entryPointNames; en.lte(); en++ ) {
905 STATIC_VAR( "int", DATA_PREFIX() + "en_" + *en ) <<
906 " = " << entryPointIds[en.pos()] << ";\n";
912 void JavaTabCodeGen::writeExec()
918 if ( redFsm->anyRegCurStateRef() )
925 if ( redFsm->anyConditions() )
926 out << " int _widec;\n";
928 if ( redFsm->anyToStateActions() || redFsm->anyRegActions() ||
929 redFsm->anyFromStateActions() )
941 out << " if ( " << P() << " != " << PE() << " ) {\n";
943 out << " _resume: while ( true ) {\n";
945 out << " _again: do {\n";
947 if ( redFsm->errState != 0 ) {
949 " if ( " << CS() << " == " << redFsm->errState->id << " )\n"
953 if ( redFsm->anyFromStateActions() ) {
955 " _acts = " << FSA() << "[" << CS() << "]" << ";\n"
956 " _nacts = " << CAST("int") << " " << A() << "[_acts++];\n"
957 " while ( _nacts-- > 0 ) {\n"
958 " switch ( " << A() << "[_acts++] ) {\n";
959 FROM_STATE_ACTION_SWITCH() <<
965 if ( redFsm->anyConditions() )
970 if ( redFsm->anyRegCurStateRef() )
971 out << " _ps = " << CS() << ";\n";
974 out << " _trans = " << I() << "[_trans];\n";
977 " " << CS() << " = " << TT() << "[_trans];\n"
980 if ( redFsm->anyRegActions() ) {
982 " if ( " << TA() << "[_trans] == 0 )\n"
985 " _acts = " << TA() << "[_trans]" << ";\n"
986 " _nacts = " << CAST("int") << " " << A() << "[_acts++];\n"
987 " while ( _nacts-- > 0 )\n {\n"
988 " switch ( " << A() << "[_acts++] )\n"
996 /* Again loop, functions as again label. */
997 out << " } while (false);\n";
999 if ( redFsm->anyToStateActions() ) {
1001 " _acts = " << TSA() << "[" << CS() << "]" << ";\n"
1002 " _nacts = " << CAST("int") << " " << A() << "[_acts++];\n"
1003 " while ( _nacts-- > 0 ) {\n"
1004 " switch ( " << A() << "[_acts++] ) {\n";
1005 TO_STATE_ACTION_SWITCH() <<
1013 " if ( ++" << P() << " == " << PE() << " )\n"
1014 " break _resume;\n";
1018 " " << P() << " += 1;\n";
1021 /* Close the resume loop. */
1024 /* The if guarding on empty string. */
1028 /* The execute block. */
1032 void JavaTabCodeGen::writeEOF()
1034 if ( redFsm->anyEofActions() ) {
1036 " int _acts = " << EA() << "[" << CS() << "]" << ";\n"
1037 " int _nacts = " << CAST("int") << " " << A() << "[_acts++];\n"
1038 " while ( _nacts-- > 0 ) {\n"
1039 " switch ( " << A() << "[_acts++] ) {\n";
1040 EOF_ACTION_SWITCH() <<
1047 std::ostream &JavaTabCodeGen::OPEN_ARRAY( string type, string name )
1055 "private static void init_" << name << "_0( " << type << "[] r )\n"
1061 std::ostream &JavaTabCodeGen::ARRAY_ITEM( string item, bool last )
1063 out << "r[" << item_count << "]=" << item << "; ";
1068 if ( item_count % SAIIC == 0 ) {
1070 out << "private static void init_" << array_name << "_" << div_count <<
1071 "( " << array_type << "[] r )\n{\n\t";
1074 else if ( item_count % IALL == 0 )
1081 std::ostream &JavaTabCodeGen::CLOSE_ARRAY()
1086 "private static " << array_type << "[] create_" << array_name << "( )\n"
1088 " " << array_type << "[] r = new " << array_type << "[" << item_count << "];\n";
1090 for ( int i = 0; i < div_count; i++ )
1091 out << " init_" << array_name << "_" << i << "( r );\n";
1099 "private static final " << array_type << " " << array_name <<
1100 "[] = create_" << array_name << "();\n\n";
1106 std::ostream &JavaTabCodeGen::STATIC_VAR( string type, string name )
1108 out << "static final " << type << " " << name;
1112 string JavaTabCodeGen::ARR_OFF( string ptr, string offset )
1114 return ptr + " + " + offset;
1117 string JavaTabCodeGen::CAST( string type )
1119 return "(" + type + ")";
1122 string JavaTabCodeGen::NULL_ITEM()
1124 /* In java we use integers instead of pointers. */
1128 string JavaTabCodeGen::GET_KEY()
1131 if ( getKeyExpr != 0 ) {
1132 /* Emit the user supplied method of retrieving the key. */
1134 INLINE_LIST( ret, getKeyExpr, 0, false );
1138 /* Expression for retrieving the key, use simple dereference. */
1139 ret << "data[" << P() << "]";
1144 string JavaTabCodeGen::CTRL_FLOW()
1146 return "if (true) ";
1149 unsigned int JavaTabCodeGen::arrayTypeSize( unsigned long maxVal )
1151 long long maxValLL = (long long) maxVal;
1152 HostType *arrayType = keyOps->typeSubsumes( maxValLL );
1153 assert( arrayType != 0 );
1154 return arrayType->size;
1157 string JavaTabCodeGen::ARRAY_TYPE( unsigned long maxVal )
1159 long long maxValLL = (long long) maxVal;
1160 HostType *arrayType = keyOps->typeSubsumes( maxValLL );
1161 assert( arrayType != 0 );
1163 string ret = arrayType->data1;
1164 if ( arrayType->data2 != 0 ) {
1166 ret += arrayType->data2;
1172 /* Write out the fsm name. */
1173 string JavaTabCodeGen::FSM_NAME()
1178 /* Emit the offset of the start state as a decimal integer. */
1179 string JavaTabCodeGen::START_STATE_ID()
1182 ret << redFsm->startState->id;
1186 /* Write out the array of actions. */
1187 std::ostream &JavaTabCodeGen::ACTIONS_ARRAY()
1189 ARRAY_ITEM( INT(0), false );
1190 for ( ActionTableMap::Iter act = redFsm->actionMap; act.lte(); act++ ) {
1191 /* Write out the length, which will never be the last character. */
1192 ARRAY_ITEM( INT(act->key.length()), false );
1194 for ( ActionTable::Iter item = act->key; item.lte(); item++ )
1195 ARRAY_ITEM( INT(item->value->actionId), (act.last() && item.last()) );
1201 string JavaTabCodeGen::CS()
1204 if ( curStateExpr != 0 ) {
1205 /* Emit the user supplied method of retrieving the key. */
1207 INLINE_LIST( ret, curStateExpr, 0, false );
1211 /* Expression for retrieving the key, use simple dereference. */
1212 ret << ACCESS() << "cs";
1217 string JavaTabCodeGen::ACCESS()
1220 if ( accessExpr != 0 )
1221 INLINE_LIST( ret, accessExpr, 0, false );
1225 string JavaTabCodeGen::GET_WIDE_KEY()
1227 if ( redFsm->anyConditions() )
1233 string JavaTabCodeGen::GET_WIDE_KEY( RedStateAp *state )
1235 if ( state->stateCondList.length() > 0 )
1241 /* Write out level number of tabs. Makes the nested binary search nice
1243 string JavaTabCodeGen::TABS( int level )
1246 while ( level-- > 0 )
1251 string JavaTabCodeGen::KEY( Key key )
1254 if ( keyOps->isSigned || !hostLang->explicitUnsigned )
1255 ret << key.getVal();
1257 ret << (unsigned long) key.getVal();
1261 string JavaTabCodeGen::INT( int i )
1268 void JavaTabCodeGen::LM_SWITCH( ostream &ret, InlineItem *item,
1269 int targState, int inFinish )
1272 " switch( " << ACT() << " ) {\n";
1274 /* If the switch handles error then we also forced the error state. It
1276 if ( item->handlesError ) {
1277 ret << " case 0: " << TOKEND() << " = " << TOKSTART() << "; ";
1278 GOTO( ret, redFsm->errState->id, inFinish );
1282 for ( InlineList::Iter lma = *item->children; lma.lte(); lma++ ) {
1283 /* Write the case label, the action and the case break. */
1284 ret << " case " << lma->lmId << ":\n";
1286 /* Write the block and close it off. */
1288 INLINE_LIST( ret, lma->children, targState, inFinish );
1293 /* Default required for D code. */
1295 " default: break;\n"
1300 void JavaTabCodeGen::SET_ACT( ostream &ret, InlineItem *item )
1302 ret << ACT() << " = " << item->lmId << ";";
1305 void JavaTabCodeGen::SET_TOKEND( ostream &ret, InlineItem *item )
1307 /* The tokend action sets tokend. */
1308 ret << TOKEND() << " = " << P();
1309 if ( item->offset != 0 )
1310 out << "+" << item->offset;
1314 void JavaTabCodeGen::GET_TOKEND( ostream &ret, InlineItem *item )
1319 void JavaTabCodeGen::INIT_TOKSTART( ostream &ret, InlineItem *item )
1321 ret << TOKSTART() << " = " << NULL_ITEM() << ";";
1324 void JavaTabCodeGen::INIT_ACT( ostream &ret, InlineItem *item )
1326 ret << ACT() << " = 0;";
1329 void JavaTabCodeGen::SET_TOKSTART( ostream &ret, InlineItem *item )
1331 ret << TOKSTART() << " = " << P() << ";";
1334 void JavaTabCodeGen::SUB_ACTION( ostream &ret, InlineItem *item,
1335 int targState, bool inFinish )
1337 if ( item->children->length() > 0 ) {
1338 /* Write the block and close it off. */
1340 INLINE_LIST( ret, item->children, targState, inFinish );
1345 void JavaTabCodeGen::ACTION( ostream &ret, Action *action, int targState, bool inFinish )
1347 /* Write the preprocessor line info for going into the source file. */
1348 lineDirective( ret, sourceFileName, action->loc.line );
1350 /* Write the block and close it off. */
1352 INLINE_LIST( ret, action->inlineList, targState, inFinish );
1356 void JavaTabCodeGen::CONDITION( ostream &ret, Action *condition )
1359 lineDirective( ret, sourceFileName, condition->loc.line );
1360 INLINE_LIST( ret, condition->inlineList, 0, false );
1363 string JavaTabCodeGen::ERROR_STATE()
1366 if ( redFsm->errState != 0 )
1367 ret << redFsm->errState->id;
1373 string JavaTabCodeGen::FIRST_FINAL_STATE()
1376 if ( redFsm->firstFinState != 0 )
1377 ret << redFsm->firstFinState->id;
1379 ret << redFsm->nextStateId;
1383 void JavaTabCodeGen::writeInit()
1386 out << "\t" << CS() << " = " << START() << ";\n";
1388 /* If there are any calls, then the stack top needs initialization. */
1389 if ( redFsm->anyActionCalls() || redFsm->anyActionRets() )
1390 out << "\t" << TOP() << " = 0;\n";
1392 if ( hasLongestMatch ) {
1394 " " << TOKSTART() << " = " << NULL_ITEM() << ";\n"
1395 " " << TOKEND() << " = " << NULL_ITEM() << ";\n"
1396 " " << ACT() << " = 0;\n";
1401 void JavaTabCodeGen::finishRagelDef()
1403 /* The frontend will do this for us, but it may be a good idea to force it
1404 * if the intermediate file is edited. */
1405 redFsm->sortByStateId();
1407 /* Choose default transitions and the single transition. */
1408 redFsm->chooseDefaultSpan();
1410 /* Maybe do flat expand, otherwise choose single. */
1411 redFsm->chooseSingle();
1413 /* If any errors have occured in the input file then don't write anything. */
1414 if ( gblErrorCount > 0 )
1417 /* Anlayze Machine will find the final action reference counts, among
1418 * other things. We will use these in reporting the usage
1419 * of fsm directives in action code. */
1422 /* Determine if we should use indicies. */
1426 ostream &JavaTabCodeGen::source_warning( const InputLoc &loc )
1428 cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": warning: ";
1432 ostream &JavaTabCodeGen::source_error( const InputLoc &loc )
1435 assert( sourceFileName != 0 );
1436 cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": ";