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). */
44 using std::ostringstream
;
49 void lineDirective( ostream
&out
, char *fileName
, int line
)
51 /* Write the preprocessor line info for to the input file. */
52 out
<< "// line " << line
<< " \"";
53 for ( char *pc
= fileName
; *pc
!= 0; pc
++ ) {
62 void genLineDirective( ostream
&out
)
64 std::streambuf
*sbuf
= out
.rdbuf();
65 output_filter
*filter
= static_cast<output_filter
*>(sbuf
);
66 lineDirective( out
, filter
->fileName
, filter
->line
+ 1 );
69 void JavaTabCodeGen::GOTO( ostream
&ret
, int gotoDest
, bool inFinish
)
71 ret
<< "{" << CS() << " = " << gotoDest
<< "; _goto_targ = " << _again
<< "; " <<
72 CTRL_FLOW() << "continue _goto;}";
75 void JavaTabCodeGen::GOTO_EXPR( ostream
&ret
, InlineItem
*ilItem
, bool inFinish
)
77 ret
<< "{" << CS() << " = (";
78 INLINE_LIST( ret
, ilItem
->children
, 0, inFinish
);
79 ret
<< "); _goto_targ = " << _again
<< "; " << CTRL_FLOW() << "continue _goto;}";
82 void JavaTabCodeGen::CALL( ostream
&ret
, int callDest
, int targState
, bool inFinish
)
84 if ( prePushExpr
!= 0 ) {
86 INLINE_LIST( ret
, prePushExpr
, 0, false );
89 ret
<< "{" << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = " <<
90 callDest
<< "; _goto_targ = " << _again
<< "; " << CTRL_FLOW() << "continue _goto;}";
92 if ( prePushExpr
!= 0 )
96 void JavaTabCodeGen::CALL_EXPR( ostream
&ret
, InlineItem
*ilItem
, int targState
, bool inFinish
)
98 if ( prePushExpr
!= 0 ) {
100 INLINE_LIST( ret
, prePushExpr
, 0, false );
103 ret
<< "{" << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = (";
104 INLINE_LIST( ret
, ilItem
->children
, targState
, inFinish
);
105 ret
<< "); _goto_targ = " << _again
<< "; " << CTRL_FLOW() << "continue _goto;}";
107 if ( prePushExpr
!= 0 )
111 void JavaTabCodeGen::RET( ostream
&ret
, bool inFinish
)
113 ret
<< "{" << CS() << " = " << STACK() << "[--" << TOP() << "];";
115 if ( postPopExpr
!= 0 ) {
117 INLINE_LIST( ret
, postPopExpr
, 0, false );
121 ret
<< "_goto_targ = " << _again
<< "; " << CTRL_FLOW() << "continue _goto;}";
124 void JavaTabCodeGen::BREAK( ostream
&ret
, int targState
)
126 ret
<< "{ _goto_targ = " << _out
<< "; " << CTRL_FLOW() << " continue _goto;}";
129 void JavaTabCodeGen::NEXT( ostream
&ret
, int nextDest
, bool inFinish
)
131 ret
<< CS() << " = " << nextDest
<< ";";
134 void JavaTabCodeGen::NEXT_EXPR( ostream
&ret
, InlineItem
*ilItem
, bool inFinish
)
136 ret
<< CS() << " = (";
137 INLINE_LIST( ret
, ilItem
->children
, 0, inFinish
);
141 void JavaTabCodeGen::EXEC( ostream
&ret
, InlineItem
*item
, int targState
, int inFinish
)
143 /* The parser gives fexec two children. The double brackets are for D
144 * code. If the inline list is a single word it will get interpreted as a
145 * C-style cast by the D compiler. */
146 ret
<< "{" << P() << " = ((";
147 INLINE_LIST( ret
, item
->children
, targState
, inFinish
);
151 /* Write out an inline tree structure. Walks the list and possibly calls out
152 * to virtual functions than handle language specific items in the tree. */
153 void JavaTabCodeGen::INLINE_LIST( ostream
&ret
, InlineList
*inlineList
,
154 int targState
, bool inFinish
)
156 for ( InlineList::Iter item
= *inlineList
; item
.lte(); item
++ ) {
157 switch ( item
->type
) {
158 case InlineItem::Text
:
161 case InlineItem::Goto
:
162 GOTO( ret
, item
->targState
->id
, inFinish
);
164 case InlineItem::Call
:
165 CALL( ret
, item
->targState
->id
, targState
, inFinish
);
167 case InlineItem::Next
:
168 NEXT( ret
, item
->targState
->id
, inFinish
);
170 case InlineItem::Ret
:
171 RET( ret
, inFinish
);
173 case InlineItem::PChar
:
176 case InlineItem::Char
:
179 case InlineItem::Hold
:
182 case InlineItem::Exec
:
183 EXEC( ret
, item
, targState
, inFinish
);
185 case InlineItem::Curs
:
188 case InlineItem::Targs
:
189 ret
<< "(" << CS() << ")";
191 case InlineItem::Entry
:
192 ret
<< item
->targState
->id
;
194 case InlineItem::GotoExpr
:
195 GOTO_EXPR( ret
, item
, inFinish
);
197 case InlineItem::CallExpr
:
198 CALL_EXPR( ret
, item
, targState
, inFinish
);
200 case InlineItem::NextExpr
:
201 NEXT_EXPR( ret
, item
, inFinish
);
203 case InlineItem::LmSwitch
:
204 LM_SWITCH( ret
, item
, targState
, inFinish
);
206 case InlineItem::LmSetActId
:
207 SET_ACT( ret
, item
);
209 case InlineItem::LmSetTokEnd
:
210 SET_TOKEND( ret
, item
);
212 case InlineItem::LmGetTokEnd
:
213 GET_TOKEND( ret
, item
);
215 case InlineItem::LmInitTokStart
:
216 INIT_TOKSTART( ret
, item
);
218 case InlineItem::LmInitAct
:
219 INIT_ACT( ret
, item
);
221 case InlineItem::LmSetTokStart
:
222 SET_TOKSTART( ret
, item
);
224 case InlineItem::SubAction
:
225 SUB_ACTION( ret
, item
, targState
, inFinish
);
227 case InlineItem::Break
:
228 BREAK( ret
, targState
);
234 string
JavaTabCodeGen::DATA_PREFIX()
237 return FSM_NAME() + "_";
241 /* Emit the alphabet data type. */
242 string
JavaTabCodeGen::ALPH_TYPE()
244 string ret
= keyOps
->alphType
->data1
;
245 if ( keyOps
->alphType
->data2
!= 0 ) {
247 ret
+= + keyOps
->alphType
->data2
;
252 /* Emit the alphabet data type. */
253 string
JavaTabCodeGen::WIDE_ALPH_TYPE()
256 if ( redFsm
->maxKey
<= keyOps
->maxKey
)
259 long long maxKeyVal
= redFsm
->maxKey
.getLongLong();
260 HostType
*wideType
= keyOps
->typeSubsumes( keyOps
->isSigned
, maxKeyVal
);
261 assert( wideType
!= 0 );
263 ret
= wideType
->data1
;
264 if ( wideType
->data2
!= 0 ) {
266 ret
+= wideType
->data2
;
274 void JavaTabCodeGen::COND_TRANSLATE()
277 " _widec = " << GET_KEY() << ";\n"
278 " _keys = " << CO() << "[" << CS() << "]*2\n;"
279 " _klen = " << CL() << "[" << CS() << "];\n"
280 " if ( _klen > 0 ) {\n"
281 " int _lower = _keys\n;"
283 " int _upper = _keys + (_klen<<1) - 2;\n"
285 " if ( _upper < _lower )\n"
288 " _mid = _lower + (((_upper-_lower) >> 1) & ~1);\n"
289 " if ( " << GET_WIDE_KEY() << " < " << CK() << "[_mid] )\n"
290 " _upper = _mid - 2;\n"
291 " else if ( " << GET_WIDE_KEY() << " > " << CK() << "[_mid+1] )\n"
292 " _lower = _mid + 2;\n"
294 " switch ( " << C() << "[" << CO() << "[" << CS() << "]"
295 " + ((_mid - _keys)>>1)] ) {\n"
298 for ( CondSpaceList::Iter csi
= condSpaceList
; csi
.lte(); csi
++ ) {
299 CondSpace
*condSpace
= csi
;
300 out
<< " case " << condSpace
->condSpaceId
<< ": {\n";
301 out
<< TABS(2) << "_widec = " << KEY(condSpace
->baseKey
) <<
302 " + (" << GET_KEY() << " - " << KEY(keyOps
->minKey
) << ");\n";
304 for ( CondSet::Iter csi
= condSpace
->condSet
; csi
.lte(); csi
++ ) {
305 out
<< TABS(2) << "if ( ";
306 CONDITION( out
, *csi
);
307 Size condValOffset
= ((1 << csi
.pos()) * keyOps
->alphSize());
308 out
<< " ) _widec += " << condValOffset
<< ";\n";
326 void JavaTabCodeGen::LOCATE_TRANS()
330 " _keys = " << KO() << "[" << CS() << "]" << ";\n"
331 " _trans = " << IO() << "[" << CS() << "];\n"
332 " _klen = " << SL() << "[" << CS() << "];\n"
333 " if ( _klen > 0 ) {\n"
334 " int _lower = _keys;\n"
336 " int _upper = _keys + _klen - 1;\n"
338 " if ( _upper < _lower )\n"
341 " _mid = _lower + ((_upper-_lower) >> 1);\n"
342 " if ( " << GET_WIDE_KEY() << " < " << K() << "[_mid] )\n"
343 " _upper = _mid - 1;\n"
344 " else if ( " << GET_WIDE_KEY() << " > " << K() << "[_mid] )\n"
345 " _lower = _mid + 1;\n"
347 " _trans += (_mid - _keys);\n"
352 " _trans += _klen;\n"
355 " _klen = " << RL() << "[" << CS() << "];\n"
356 " if ( _klen > 0 ) {\n"
357 " int _lower = _keys;\n"
359 " int _upper = _keys + (_klen<<1) - 2;\n"
361 " if ( _upper < _lower )\n"
364 " _mid = _lower + (((_upper-_lower) >> 1) & ~1);\n"
365 " if ( " << GET_WIDE_KEY() << " < " << K() << "[_mid] )\n"
366 " _upper = _mid - 2;\n"
367 " else if ( " << GET_WIDE_KEY() << " > " << K() << "[_mid+1] )\n"
368 " _lower = _mid + 2;\n"
370 " _trans += ((_mid - _keys)>>1);\n"
374 " _trans += _klen;\n"
376 " } while (false);\n"
380 /* Determine if we should use indicies or not. */
381 void JavaTabCodeGen::calcIndexSize()
383 int sizeWithInds
= 0, sizeWithoutInds
= 0;
385 /* Calculate cost of using with indicies. */
386 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ ) {
387 int totalIndex
= st
->outSingle
.length() + st
->outRange
.length() +
388 (st
->defTrans
== 0 ? 0 : 1);
389 sizeWithInds
+= arrayTypeSize(redFsm
->maxIndex
) * totalIndex
;
391 sizeWithInds
+= arrayTypeSize(redFsm
->maxState
) * redFsm
->transSet
.length();
392 if ( redFsm
->anyActions() )
393 sizeWithInds
+= arrayTypeSize(redFsm
->maxActionLoc
) * redFsm
->transSet
.length();
395 /* Calculate the cost of not using indicies. */
396 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ ) {
397 int totalIndex
= st
->outSingle
.length() + st
->outRange
.length() +
398 (st
->defTrans
== 0 ? 0 : 1);
399 sizeWithoutInds
+= arrayTypeSize(redFsm
->maxState
) * totalIndex
;
400 if ( redFsm
->anyActions() )
401 sizeWithoutInds
+= arrayTypeSize(redFsm
->maxActionLoc
) * totalIndex
;
404 /* If using indicies reduces the size, use them. */
405 useIndicies
= sizeWithInds
< sizeWithoutInds
;
408 int JavaTabCodeGen::TO_STATE_ACTION( RedStateAp
*state
)
411 if ( state
->toStateAction
!= 0 )
412 act
= state
->toStateAction
->location
+1;
416 int JavaTabCodeGen::FROM_STATE_ACTION( RedStateAp
*state
)
419 if ( state
->fromStateAction
!= 0 )
420 act
= state
->fromStateAction
->location
+1;
424 int JavaTabCodeGen::EOF_ACTION( RedStateAp
*state
)
427 if ( state
->eofAction
!= 0 )
428 act
= state
->eofAction
->location
+1;
433 int JavaTabCodeGen::TRANS_ACTION( RedTransAp
*trans
)
435 /* If there are actions, emit them. Otherwise emit zero. */
437 if ( trans
->action
!= 0 )
438 act
= trans
->action
->location
+1;
442 std::ostream
&JavaTabCodeGen::TO_STATE_ACTION_SWITCH()
444 /* Walk the list of functions, printing the cases. */
445 for ( ActionList::Iter act
= actionList
; act
.lte(); act
++ ) {
446 /* Write out referenced actions. */
447 if ( act
->numToStateRefs
> 0 ) {
448 /* Write the case label, the action and the case break. */
449 out
<< "\tcase " << act
->actionId
<< ":\n";
450 ACTION( out
, act
, 0, false );
455 genLineDirective( out
);
459 std::ostream
&JavaTabCodeGen::FROM_STATE_ACTION_SWITCH()
461 /* Walk the list of functions, printing the cases. */
462 for ( ActionList::Iter act
= actionList
; act
.lte(); act
++ ) {
463 /* Write out referenced actions. */
464 if ( act
->numFromStateRefs
> 0 ) {
465 /* Write the case label, the action and the case break. */
466 out
<< "\tcase " << act
->actionId
<< ":\n";
467 ACTION( out
, act
, 0, false );
472 genLineDirective( out
);
476 std::ostream
&JavaTabCodeGen::EOF_ACTION_SWITCH()
478 /* Walk the list of functions, printing the cases. */
479 for ( ActionList::Iter act
= actionList
; act
.lte(); act
++ ) {
480 /* Write out referenced actions. */
481 if ( act
->numEofRefs
> 0 ) {
482 /* Write the case label, the action and the case break. */
483 out
<< "\tcase " << act
->actionId
<< ":\n";
484 ACTION( out
, act
, 0, true );
489 genLineDirective( out
);
494 std::ostream
&JavaTabCodeGen::ACTION_SWITCH()
496 /* Walk the list of functions, printing the cases. */
497 for ( ActionList::Iter act
= actionList
; act
.lte(); act
++ ) {
498 /* Write out referenced actions. */
499 if ( act
->numTransRefs
> 0 ) {
500 /* Write the case label, the action and the case break. */
501 out
<< "\tcase " << act
->actionId
<< ":\n";
502 ACTION( out
, act
, 0, false );
507 genLineDirective( out
);
511 std::ostream
&JavaTabCodeGen::COND_OFFSETS()
513 int curKeyOffset
= 0;
514 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ ) {
515 /* Write the key offset. */
516 ARRAY_ITEM( INT(curKeyOffset
), st
.last() );
518 /* Move the key offset ahead. */
519 curKeyOffset
+= st
->stateCondList
.length();
524 std::ostream
&JavaTabCodeGen::KEY_OFFSETS()
526 int curKeyOffset
= 0;
527 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ ) {
528 /* Write the key offset. */
529 ARRAY_ITEM( INT(curKeyOffset
), st
.last() );
531 /* Move the key offset ahead. */
532 curKeyOffset
+= st
->outSingle
.length() + st
->outRange
.length()*2;
538 std::ostream
&JavaTabCodeGen::INDEX_OFFSETS()
540 int curIndOffset
= 0;
541 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ ) {
542 /* Write the index offset. */
543 ARRAY_ITEM( INT(curIndOffset
), st
.last() );
545 /* Move the index offset ahead. */
546 curIndOffset
+= st
->outSingle
.length() + st
->outRange
.length();
547 if ( st
->defTrans
!= 0 )
553 std::ostream
&JavaTabCodeGen::COND_LENS()
555 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ ) {
556 /* Write singles length. */
557 ARRAY_ITEM( INT(st
->stateCondList
.length()), st
.last() );
563 std::ostream
&JavaTabCodeGen::SINGLE_LENS()
565 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ ) {
566 /* Write singles length. */
567 ARRAY_ITEM( INT(st
->outSingle
.length()), st
.last() );
572 std::ostream
&JavaTabCodeGen::RANGE_LENS()
574 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ ) {
575 /* Emit length of range index. */
576 ARRAY_ITEM( INT(st
->outRange
.length()), st
.last() );
581 std::ostream
&JavaTabCodeGen::TO_STATE_ACTIONS()
583 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ ) {
584 /* Write any eof action. */
585 ARRAY_ITEM( INT(TO_STATE_ACTION(st
)), st
.last() );
590 std::ostream
&JavaTabCodeGen::FROM_STATE_ACTIONS()
592 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ ) {
593 /* Write any eof action. */
594 ARRAY_ITEM( INT(FROM_STATE_ACTION(st
)), st
.last() );
599 std::ostream
&JavaTabCodeGen::EOF_ACTIONS()
601 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ ) {
602 /* Write any eof action. */
603 ARRAY_ITEM( INT(EOF_ACTION(st
)), st
.last() );
608 std::ostream
&JavaTabCodeGen::EOF_TRANS()
610 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ ) {
611 /* Write any eof action. */
613 if ( st
->eofTrans
!= 0 )
614 trans
= st
->eofTrans
->id
+1;
616 /* Write any eof action. */
617 ARRAY_ITEM( INT(trans
), st
.last() );
623 std::ostream
&JavaTabCodeGen::COND_KEYS()
625 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ ) {
626 /* Loop the state's transitions. */
627 for ( StateCondList::Iter sc
= st
->stateCondList
; sc
.lte(); sc
++ ) {
629 ARRAY_ITEM( KEY( sc
->lowKey
), false );
630 ARRAY_ITEM( KEY( sc
->highKey
), false );
634 /* Output one last number so we don't have to figure out when the last
635 * entry is and avoid writing a comma. */
636 ARRAY_ITEM( INT(0), true );
640 std::ostream
&JavaTabCodeGen::COND_SPACES()
642 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ ) {
643 /* Loop the state's transitions. */
644 for ( StateCondList::Iter sc
= st
->stateCondList
; sc
.lte(); sc
++ ) {
646 ARRAY_ITEM( KEY( sc
->condSpace
->condSpaceId
), false );
650 /* Output one last number so we don't have to figure out when the last
651 * entry is and avoid writing a comma. */
652 ARRAY_ITEM( INT(0), true );
656 std::ostream
&JavaTabCodeGen::KEYS()
658 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ ) {
659 /* Loop the singles. */
660 for ( RedTransList::Iter stel
= st
->outSingle
; stel
.lte(); stel
++ ) {
661 ARRAY_ITEM( KEY( stel
->lowKey
), false );
664 /* Loop the state's transitions. */
665 for ( RedTransList::Iter rtel
= st
->outRange
; rtel
.lte(); rtel
++ ) {
667 ARRAY_ITEM( KEY( rtel
->lowKey
), false );
670 ARRAY_ITEM( KEY( rtel
->highKey
), false );
674 /* Output one last number so we don't have to figure out when the last
675 * entry is and avoid writing a comma. */
676 ARRAY_ITEM( INT(0), true );
680 std::ostream
&JavaTabCodeGen::INDICIES()
682 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ ) {
683 /* Walk the singles. */
684 for ( RedTransList::Iter stel
= st
->outSingle
; stel
.lte(); stel
++ ) {
685 ARRAY_ITEM( KEY( stel
->value
->id
), false );
688 /* Walk the ranges. */
689 for ( RedTransList::Iter rtel
= st
->outRange
; rtel
.lte(); rtel
++ ) {
690 ARRAY_ITEM( KEY( rtel
->value
->id
), false );
693 /* The state's default index goes next. */
694 if ( st
->defTrans
!= 0 ) {
695 ARRAY_ITEM( KEY( st
->defTrans
->id
), 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::TRANS_TARGS()
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 RedTransAp
*trans
= stel
->value
;
711 ARRAY_ITEM( KEY( trans
->targ
->id
), false );
714 /* Walk the ranges. */
715 for ( RedTransList::Iter rtel
= st
->outRange
; rtel
.lte(); rtel
++ ) {
716 RedTransAp
*trans
= rtel
->value
;
717 ARRAY_ITEM( KEY( trans
->targ
->id
), false );
720 /* The state's default target state. */
721 if ( st
->defTrans
!= 0 ) {
722 RedTransAp
*trans
= st
->defTrans
;
723 ARRAY_ITEM( KEY( trans
->targ
->id
), false );
727 /* Output one last number so we don't have to figure out when the last
728 * entry is and avoid writing a comma. */
729 ARRAY_ITEM( INT(0), true );
734 std::ostream
&JavaTabCodeGen::TRANS_ACTIONS()
736 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ ) {
737 /* Walk the singles. */
738 for ( RedTransList::Iter stel
= st
->outSingle
; stel
.lte(); stel
++ ) {
739 RedTransAp
*trans
= stel
->value
;
740 ARRAY_ITEM( INT(TRANS_ACTION( trans
)), false );
743 /* Walk the ranges. */
744 for ( RedTransList::Iter rtel
= st
->outRange
; rtel
.lte(); rtel
++ ) {
745 RedTransAp
*trans
= rtel
->value
;
746 ARRAY_ITEM( INT(TRANS_ACTION( trans
)), false );
749 /* The state's default index goes next. */
750 if ( st
->defTrans
!= 0 ) {
751 RedTransAp
*trans
= st
->defTrans
;
752 ARRAY_ITEM( INT(TRANS_ACTION( trans
)), false );
756 /* Output one last number so we don't have to figure out when the last
757 * entry is and avoid writing a comma. */
758 ARRAY_ITEM( INT(0), true );
762 std::ostream
&JavaTabCodeGen::TRANS_TARGS_WI()
764 /* Transitions must be written ordered by their id. */
765 RedTransAp
**transPtrs
= new RedTransAp
*[redFsm
->transSet
.length()];
766 for ( TransApSet::Iter trans
= redFsm
->transSet
; trans
.lte(); trans
++ )
767 transPtrs
[trans
->id
] = trans
;
769 /* Keep a count of the num of items in the array written. */
770 for ( int t
= 0; t
< redFsm
->transSet
.length(); t
++ ) {
771 /* Write out the target state. */
772 RedTransAp
*trans
= transPtrs
[t
];
773 ARRAY_ITEM( INT(trans
->targ
->id
), ( t
>= redFsm
->transSet
.length()-1 ) );
780 std::ostream
&JavaTabCodeGen::TRANS_ACTIONS_WI()
782 /* Transitions must be written ordered by their id. */
783 RedTransAp
**transPtrs
= new RedTransAp
*[redFsm
->transSet
.length()];
784 for ( TransApSet::Iter trans
= redFsm
->transSet
; trans
.lte(); trans
++ )
785 transPtrs
[trans
->id
] = trans
;
787 /* Keep a count of the num of items in the array written. */
788 for ( int t
= 0; t
< redFsm
->transSet
.length(); t
++ ) {
789 /* Write the function for the transition. */
790 RedTransAp
*trans
= transPtrs
[t
];
791 ARRAY_ITEM( INT(TRANS_ACTION( trans
)), ( t
>= redFsm
->transSet
.length()-1 ) );
797 void JavaTabCodeGen::writeExports()
799 if ( exportList
.length() > 0 ) {
800 for ( ExportList::Iter ex
= exportList
; ex
.lte(); ex
++ ) {
801 STATIC_VAR( ALPH_TYPE(), DATA_PREFIX() + "ex_" + ex
->name
)
802 << " = " << KEY(ex
->key
) << ";\n";
808 void JavaTabCodeGen::writeData()
810 /* If there are any transtion functions then output the array. If there
811 * are none, don't bother emitting an empty array that won't be used. */
812 if ( redFsm
->anyActions() ) {
813 OPEN_ARRAY( ARRAY_TYPE(redFsm
->maxActArrItem
), A() );
819 if ( redFsm
->anyConditions() ) {
820 OPEN_ARRAY( ARRAY_TYPE(redFsm
->maxCondOffset
), CO() );
825 OPEN_ARRAY( ARRAY_TYPE(redFsm
->maxCondLen
), CL() );
830 OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
835 OPEN_ARRAY( ARRAY_TYPE(redFsm
->maxCondSpaceId
), C() );
841 OPEN_ARRAY( ARRAY_TYPE(redFsm
->maxKeyOffset
), KO() );
846 OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
851 OPEN_ARRAY( ARRAY_TYPE(redFsm
->maxSingleLen
), SL() );
856 OPEN_ARRAY( ARRAY_TYPE(redFsm
->maxRangeLen
), RL() );
861 OPEN_ARRAY( ARRAY_TYPE(redFsm
->maxIndexOffset
), IO() );
867 OPEN_ARRAY( ARRAY_TYPE(redFsm
->maxIndex
), I() );
872 OPEN_ARRAY( ARRAY_TYPE(redFsm
->maxState
), TT() );
877 if ( redFsm
->anyActions() ) {
878 OPEN_ARRAY( ARRAY_TYPE(redFsm
->maxActionLoc
), TA() );
885 OPEN_ARRAY( ARRAY_TYPE(redFsm
->maxState
), TT() );
890 if ( redFsm
->anyActions() ) {
891 OPEN_ARRAY( ARRAY_TYPE(redFsm
->maxActionLoc
), TA() );
898 if ( redFsm
->anyToStateActions() ) {
899 OPEN_ARRAY( ARRAY_TYPE(redFsm
->maxActionLoc
), TSA() );
905 if ( redFsm
->anyFromStateActions() ) {
906 OPEN_ARRAY( ARRAY_TYPE(redFsm
->maxActionLoc
), FSA() );
907 FROM_STATE_ACTIONS();
912 if ( redFsm
->anyEofActions() ) {
913 OPEN_ARRAY( ARRAY_TYPE(redFsm
->maxActionLoc
), EA() );
919 if ( redFsm
->anyEofTrans() ) {
920 OPEN_ARRAY( ARRAY_TYPE(redFsm
->maxIndex
+1), ET() );
926 if ( redFsm
->startState
!= 0 )
927 STATIC_VAR( "int", START() ) << " = " << START_STATE_ID() << ";\n";
929 if ( writeFirstFinal
)
930 STATIC_VAR( "int" , FIRST_FINAL() ) << " = " << FIRST_FINAL_STATE() << ";\n";
933 STATIC_VAR( "int", ERROR() ) << " = " << ERROR_STATE() << ";\n";
937 if ( entryPointNames
.length() > 0 ) {
938 for ( EntryNameVect::Iter en
= entryPointNames
; en
.lte(); en
++ ) {
939 STATIC_VAR( "int", DATA_PREFIX() + "en_" + *en
) <<
940 " = " << entryPointIds
[en
.pos()] << ";\n";
946 void JavaTabCodeGen::writeExec()
952 if ( redFsm
->anyRegCurStateRef() )
957 " int _trans = 0;\n";
959 if ( redFsm
->anyConditions() )
960 out
<< " int _widec;\n";
962 if ( redFsm
->anyToStateActions() || redFsm
->anyRegActions() ||
963 redFsm
->anyFromStateActions() )
972 " int _goto_targ = 0;\n"
976 " _goto: while (true) {\n"
977 " switch ( _goto_targ ) {\n"
982 " if ( " << P() << " == " << PE() << " ) {\n"
983 " _goto_targ = " << _test_eof
<< ";\n"
988 if ( redFsm
->errState
!= 0 ) {
990 " if ( " << CS() << " == " << redFsm
->errState
->id
<< " ) {\n"
991 " _goto_targ = " << _out
<< ";\n"
996 out
<< "case " << _resume
<< ":\n";
998 if ( redFsm
->anyFromStateActions() ) {
1000 " _acts = " << FSA() << "[" << CS() << "]" << ";\n"
1001 " _nacts = " << CAST("int") << " " << A() << "[_acts++];\n"
1002 " while ( _nacts-- > 0 ) {\n"
1003 " switch ( " << A() << "[_acts++] ) {\n";
1004 FROM_STATE_ACTION_SWITCH() <<
1010 if ( redFsm
->anyConditions() )
1016 out
<< " _trans = " << I() << "[_trans];\n";
1018 if ( redFsm
->anyEofTrans() )
1019 out
<< "case " << _eof_trans
<< ":\n";
1021 if ( redFsm
->anyRegCurStateRef() )
1022 out
<< " _ps = " << CS() << ";\n";
1025 " " << CS() << " = " << TT() << "[_trans];\n"
1028 if ( redFsm
->anyRegActions() ) {
1030 " if ( " << TA() << "[_trans] != 0 ) {\n"
1031 " _acts = " << TA() << "[_trans]" << ";\n"
1032 " _nacts = " << CAST("int") << " " << A() << "[_acts++];\n"
1033 " while ( _nacts-- > 0 )\n {\n"
1034 " switch ( " << A() << "[_acts++] )\n"
1043 out
<< "case " << _again
<< ":\n";
1045 if ( redFsm
->anyToStateActions() ) {
1047 " _acts = " << TSA() << "[" << CS() << "]" << ";\n"
1048 " _nacts = " << CAST("int") << " " << A() << "[_acts++];\n"
1049 " while ( _nacts-- > 0 ) {\n"
1050 " switch ( " << A() << "[_acts++] ) {\n";
1051 TO_STATE_ACTION_SWITCH() <<
1057 if ( redFsm
->errState
!= 0 ) {
1059 " if ( " << CS() << " == " << redFsm
->errState
->id
<< " ) {\n"
1060 " _goto_targ = " << _out
<< ";\n"
1061 " continue _goto;\n"
1067 " if ( ++" << P() << " != " << PE() << " ) {\n"
1068 " _goto_targ = " << _resume
<< ";\n"
1069 " continue _goto;\n"
1074 " " << P() << " += 1;\n"
1075 " _goto_targ = " << _resume
<< ";\n"
1076 " continue _goto;\n";
1079 out
<< "case " << _test_eof
<< ":\n";
1081 if ( redFsm
->anyEofTrans() || redFsm
->anyEofActions() ) {
1083 " if ( " << P() << " == " << EOFV() << " )\n"
1086 if ( redFsm
->anyEofTrans() ) {
1088 " if ( " << ET() << "[" << CS() << "] > 0 ) {\n"
1089 " _trans = " << ET() << "[" << CS() << "] - 1;\n"
1090 " _goto_targ = " << _eof_trans
<< ";\n"
1091 " continue _goto;\n"
1095 if ( redFsm
->anyEofActions() ) {
1097 " int __acts = " << EA() << "[" << CS() << "]" << ";\n"
1098 " int __nacts = " << CAST("int") << " " << A() << "[__acts++];\n"
1099 " while ( __nacts-- > 0 ) {\n"
1100 " switch ( " << A() << "[__acts++] ) {\n";
1101 EOF_ACTION_SWITCH() <<
1111 out
<< "case " << _out
<< ":\n";
1113 /* The switch and goto loop. */
1115 out
<< " break; }\n";
1117 /* The execute block. */
1121 std::ostream
&JavaTabCodeGen::OPEN_ARRAY( string type
, string name
)
1129 "private static void init_" << name
<< "_0( " << type
<< "[] r )\n"
1135 std::ostream
&JavaTabCodeGen::ARRAY_ITEM( string item
, bool last
)
1137 out
<< "r[" << item_count
<< "]=" << item
<< "; ";
1142 if ( item_count
% SAIIC
== 0 ) {
1144 out
<< "private static void init_" << array_name
<< "_" << div_count
<<
1145 "( " << array_type
<< "[] r )\n{\n\t";
1148 else if ( item_count
% IALL
== 0 )
1155 std::ostream
&JavaTabCodeGen::CLOSE_ARRAY()
1160 "private static " << array_type
<< "[] create_" << array_name
<< "( )\n"
1162 " " << array_type
<< "[] r = new " << array_type
<< "[" << item_count
<< "];\n";
1164 for ( int i
= 0; i
< div_count
; i
++ )
1165 out
<< " init_" << array_name
<< "_" << i
<< "( r );\n";
1173 "private static final " << array_type
<< " " << array_name
<<
1174 "[] = create_" << array_name
<< "();\n\n";
1180 std::ostream
&JavaTabCodeGen::STATIC_VAR( string type
, string name
)
1182 out
<< "static final " << type
<< " " << name
;
1186 string
JavaTabCodeGen::ARR_OFF( string ptr
, string offset
)
1188 return ptr
+ " + " + offset
;
1191 string
JavaTabCodeGen::CAST( string type
)
1193 return "(" + type
+ ")";
1196 string
JavaTabCodeGen::NULL_ITEM()
1198 /* In java we use integers instead of pointers. */
1202 string
JavaTabCodeGen::GET_KEY()
1205 if ( getKeyExpr
!= 0 ) {
1206 /* Emit the user supplied method of retrieving the key. */
1208 INLINE_LIST( ret
, getKeyExpr
, 0, false );
1212 /* Expression for retrieving the key, use simple dereference. */
1213 ret
<< DATA() << "[" << P() << "]";
1218 string
JavaTabCodeGen::CTRL_FLOW()
1220 return "if (true) ";
1223 unsigned int JavaTabCodeGen::arrayTypeSize( unsigned long maxVal
)
1225 long long maxValLL
= (long long) maxVal
;
1226 HostType
*arrayType
= keyOps
->typeSubsumes( maxValLL
);
1227 assert( arrayType
!= 0 );
1228 return arrayType
->size
;
1231 string
JavaTabCodeGen::ARRAY_TYPE( unsigned long maxVal
)
1233 long long maxValLL
= (long long) maxVal
;
1234 HostType
*arrayType
= keyOps
->typeSubsumes( maxValLL
);
1235 assert( arrayType
!= 0 );
1237 string ret
= arrayType
->data1
;
1238 if ( arrayType
->data2
!= 0 ) {
1240 ret
+= arrayType
->data2
;
1246 /* Write out the fsm name. */
1247 string
JavaTabCodeGen::FSM_NAME()
1252 /* Emit the offset of the start state as a decimal integer. */
1253 string
JavaTabCodeGen::START_STATE_ID()
1256 ret
<< redFsm
->startState
->id
;
1260 /* Write out the array of actions. */
1261 std::ostream
&JavaTabCodeGen::ACTIONS_ARRAY()
1263 ARRAY_ITEM( INT(0), false );
1264 for ( ActionTableMap::Iter act
= redFsm
->actionMap
; act
.lte(); act
++ ) {
1265 /* Write out the length, which will never be the last character. */
1266 ARRAY_ITEM( INT(act
->key
.length()), false );
1268 for ( ActionTable::Iter item
= act
->key
; item
.lte(); item
++ )
1269 ARRAY_ITEM( INT(item
->value
->actionId
), (act
.last() && item
.last()) );
1275 string
JavaTabCodeGen::ACCESS()
1278 if ( accessExpr
!= 0 )
1279 INLINE_LIST( ret
, accessExpr
, 0, false );
1283 string
JavaTabCodeGen::P()
1290 INLINE_LIST( ret
, pExpr
, 0, false );
1296 string
JavaTabCodeGen::PE()
1303 INLINE_LIST( ret
, peExpr
, 0, false );
1309 string
JavaTabCodeGen::EOFV()
1316 INLINE_LIST( ret
, eofExpr
, 0, false );
1322 string
JavaTabCodeGen::CS()
1326 ret
<< ACCESS() << "cs";
1328 /* Emit the user supplied method of retrieving the key. */
1330 INLINE_LIST( ret
, csExpr
, 0, false );
1336 string
JavaTabCodeGen::TOP()
1340 ret
<< ACCESS() + "top";
1343 INLINE_LIST( ret
, topExpr
, 0, false );
1349 string
JavaTabCodeGen::STACK()
1352 if ( stackExpr
== 0 )
1353 ret
<< ACCESS() + "stack";
1356 INLINE_LIST( ret
, stackExpr
, 0, false );
1362 string
JavaTabCodeGen::ACT()
1366 ret
<< ACCESS() + "act";
1369 INLINE_LIST( ret
, actExpr
, 0, false );
1375 string
JavaTabCodeGen::TOKSTART()
1378 if ( tokstartExpr
== 0 )
1379 ret
<< ACCESS() + "tokstart";
1382 INLINE_LIST( ret
, tokstartExpr
, 0, false );
1388 string
JavaTabCodeGen::TOKEND()
1391 if ( tokendExpr
== 0 )
1392 ret
<< ACCESS() + "tokend";
1395 INLINE_LIST( ret
, tokendExpr
, 0, false );
1401 string
JavaTabCodeGen::DATA()
1404 if ( dataExpr
== 0 )
1405 ret
<< ACCESS() + "data";
1408 INLINE_LIST( ret
, dataExpr
, 0, false );
1415 string
JavaTabCodeGen::GET_WIDE_KEY()
1417 if ( redFsm
->anyConditions() )
1423 string
JavaTabCodeGen::GET_WIDE_KEY( RedStateAp
*state
)
1425 if ( state
->stateCondList
.length() > 0 )
1431 /* Write out level number of tabs. Makes the nested binary search nice
1433 string
JavaTabCodeGen::TABS( int level
)
1436 while ( level
-- > 0 )
1441 string
JavaTabCodeGen::KEY( Key key
)
1444 if ( keyOps
->isSigned
|| !hostLang
->explicitUnsigned
)
1445 ret
<< key
.getVal();
1447 ret
<< (unsigned long) key
.getVal();
1451 string
JavaTabCodeGen::INT( int i
)
1458 void JavaTabCodeGen::LM_SWITCH( ostream
&ret
, InlineItem
*item
,
1459 int targState
, int inFinish
)
1462 " switch( " << ACT() << " ) {\n";
1464 for ( InlineList::Iter lma
= *item
->children
; lma
.lte(); lma
++ ) {
1465 /* Write the case label, the action and the case break. */
1466 ret
<< " case " << lma
->lmId
<< ":\n";
1468 /* Write the block and close it off. */
1470 INLINE_LIST( ret
, lma
->children
, targState
, inFinish
);
1475 /* Default required for D code. */
1477 " default: break;\n"
1482 void JavaTabCodeGen::SET_ACT( ostream
&ret
, InlineItem
*item
)
1484 ret
<< ACT() << " = " << item
->lmId
<< ";";
1487 void JavaTabCodeGen::SET_TOKEND( ostream
&ret
, InlineItem
*item
)
1489 /* The tokend action sets tokend. */
1490 ret
<< TOKEND() << " = " << P();
1491 if ( item
->offset
!= 0 )
1492 out
<< "+" << item
->offset
;
1496 void JavaTabCodeGen::GET_TOKEND( ostream
&ret
, InlineItem
*item
)
1501 void JavaTabCodeGen::INIT_TOKSTART( ostream
&ret
, InlineItem
*item
)
1503 ret
<< TOKSTART() << " = " << NULL_ITEM() << ";";
1506 void JavaTabCodeGen::INIT_ACT( ostream
&ret
, InlineItem
*item
)
1508 ret
<< ACT() << " = 0;";
1511 void JavaTabCodeGen::SET_TOKSTART( ostream
&ret
, InlineItem
*item
)
1513 ret
<< TOKSTART() << " = " << P() << ";";
1516 void JavaTabCodeGen::SUB_ACTION( ostream
&ret
, InlineItem
*item
,
1517 int targState
, bool inFinish
)
1519 if ( item
->children
->length() > 0 ) {
1520 /* Write the block and close it off. */
1522 INLINE_LIST( ret
, item
->children
, targState
, inFinish
);
1527 void JavaTabCodeGen::ACTION( ostream
&ret
, Action
*action
, int targState
, bool inFinish
)
1529 /* Write the preprocessor line info for going into the source file. */
1530 lineDirective( ret
, sourceFileName
, action
->loc
.line
);
1532 /* Write the block and close it off. */
1534 INLINE_LIST( ret
, action
->inlineList
, targState
, inFinish
);
1538 void JavaTabCodeGen::CONDITION( ostream
&ret
, Action
*condition
)
1541 lineDirective( ret
, sourceFileName
, condition
->loc
.line
);
1542 INLINE_LIST( ret
, condition
->inlineList
, 0, false );
1545 string
JavaTabCodeGen::ERROR_STATE()
1548 if ( redFsm
->errState
!= 0 )
1549 ret
<< redFsm
->errState
->id
;
1555 string
JavaTabCodeGen::FIRST_FINAL_STATE()
1558 if ( redFsm
->firstFinState
!= 0 )
1559 ret
<< redFsm
->firstFinState
->id
;
1561 ret
<< redFsm
->nextStateId
;
1565 void JavaTabCodeGen::writeInit()
1570 out
<< "\t" << CS() << " = " << START() << ";\n";
1572 /* If there are any calls, then the stack top needs initialization. */
1573 if ( redFsm
->anyActionCalls() || redFsm
->anyActionRets() )
1574 out
<< "\t" << TOP() << " = 0;\n";
1576 if ( hasLongestMatch
) {
1578 " " << TOKSTART() << " = " << NULL_ITEM() << ";\n"
1579 " " << TOKEND() << " = " << NULL_ITEM() << ";\n"
1580 " " << ACT() << " = 0;\n";
1585 void JavaTabCodeGen::finishRagelDef()
1587 /* The frontend will do this for us, but it may be a good idea to force it
1588 * if the intermediate file is edited. */
1589 redFsm
->sortByStateId();
1591 /* Choose default transitions and the single transition. */
1592 redFsm
->chooseDefaultSpan();
1594 /* Maybe do flat expand, otherwise choose single. */
1595 redFsm
->chooseSingle();
1597 /* If any errors have occured in the input file then don't write anything. */
1598 if ( gblErrorCount
> 0 )
1601 /* Anlayze Machine will find the final action reference counts, among
1602 * other things. We will use these in reporting the usage
1603 * of fsm directives in action code. */
1606 /* Determine if we should use indicies. */
1610 ostream
&JavaTabCodeGen::source_warning( const InputLoc
&loc
)
1612 cerr
<< sourceFileName
<< ":" << loc
.line
<< ":" << loc
.col
<< ": warning: ";
1616 ostream
&JavaTabCodeGen::source_error( const InputLoc
&loc
)
1619 assert( sourceFileName
!= 0 );
1620 cerr
<< sourceFileName
<< ":" << loc
.line
<< ":" << loc
.col
<< ": ";