2 * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
3 * 2004 Erich Ocean <eric.ocean@ampede.com>
4 * 2005 Alan West <alan@alanz.com>
7 /* This file is part of Ragel.
9 * Ragel is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * Ragel is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with Ragel; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 /* Emit the goto to take for a given transition. */
33 std::ostream
&GoGotoCodeGen::TRANS_GOTO( RedTransAp
*trans
, int level
)
35 out
<< TABS(level
) << "goto tr" << trans
->id
<< ";";
39 int GoGotoCodeGen::TRANS_NR( RedTransAp
*trans
)
44 std::ostream
&GoGotoCodeGen::TO_STATE_ACTION_SWITCH( int level
)
46 /* Walk the list of functions, printing the cases. */
47 for ( GenActionList::Iter act
= actionList
; act
.lte(); act
++ ) {
48 /* Write out referenced actions. */
49 if ( act
->numToStateRefs
> 0 ) {
50 /* Write the case label, the action and the case break. */
51 out
<< TABS(level
) << "case " << act
->actionId
<< ":" << endl
;
52 ACTION( out
, act
, 0, false, false );
56 genLineDirective( out
);
60 std::ostream
&GoGotoCodeGen::FROM_STATE_ACTION_SWITCH( int level
)
62 /* Walk the list of functions, printing the cases. */
63 for ( GenActionList::Iter act
= actionList
; act
.lte(); act
++ ) {
64 /* Write out referenced actions. */
65 if ( act
->numFromStateRefs
> 0 ) {
66 /* Write the case label, the action and the case break. */
67 out
<< TABS(level
) << "case " << act
->actionId
<< ":" << endl
;
68 ACTION( out
, act
, 0, false, false );
72 genLineDirective( out
);
76 std::ostream
&GoGotoCodeGen::EOF_ACTION_SWITCH( int level
)
78 /* Walk the list of functions, printing the cases. */
79 for ( GenActionList::Iter act
= actionList
; act
.lte(); act
++ ) {
80 /* Write out referenced actions. */
81 if ( act
->numEofRefs
> 0 ) {
82 /* Write the case label, the action and the case break. */
83 out
<< TABS(level
) << "case " << act
->actionId
<< ":" << endl
;
84 ACTION( out
, act
, 0, true, false );
88 genLineDirective( out
);
92 std::ostream
&GoGotoCodeGen::ACTION_SWITCH( int level
)
94 /* Walk the list of functions, printing the cases. */
95 for ( GenActionList::Iter act
= actionList
; act
.lte(); act
++ ) {
96 /* Write out referenced actions. */
97 if ( act
->numTransRefs
> 0 ) {
98 /* Write the case label, the action and the case break. */
99 out
<< TABS(level
) << "case " << act
->actionId
<< ":" << endl
;
100 ACTION( out
, act
, 0, false, false );
104 genLineDirective( out
);
108 void GoGotoCodeGen::GOTO_HEADER( RedStateAp
*state
, int level
)
110 /* Label the state. */
111 out
<< TABS(level
) << "case " << state
->id
<< ":" << endl
;
114 void GoGotoCodeGen::emitSingleSwitch( RedStateAp
*state
, int level
)
116 /* Load up the singles. */
117 int numSingles
= state
->outSingle
.length();
118 RedTransEl
*data
= state
->outSingle
.data
;
120 if ( numSingles
== 1 ) {
121 /* If there is a single single key then write it out as an if. */
122 out
<< TABS(level
) << "if " << GET_WIDE_KEY(state
) << " == " <<
123 WIDE_KEY(state
, data
[0].lowKey
) << " {" << endl
;
125 /* Virtual function for writing the target of the transition. */
126 TRANS_GOTO(data
[0].value
, level
+ 1) << endl
;
127 out
<< TABS(level
) << "}" << endl
;
129 else if ( numSingles
> 1 ) {
130 /* Write out single keys in a switch if there is more than one. */
131 out
<< TABS(level
) << "switch " << GET_WIDE_KEY(state
) << " {" << endl
;
133 /* Write out the single indicies. */
134 for ( int j
= 0; j
< numSingles
; j
++ ) {
135 out
<< TABS(level
) << "case " << WIDE_KEY(state
, data
[j
].lowKey
) << ":" << endl
;
136 TRANS_GOTO(data
[j
].value
, level
+ 1) << endl
;
139 /* Close off the transition switch. */
140 out
<< TABS(level
) << "}" << endl
;
144 void GoGotoCodeGen::emitRangeBSearch( RedStateAp
*state
, int level
, int low
, int high
)
146 /* Get the mid position, staying on the lower end of the range. */
147 int mid
= (low
+ high
) >> 1;
148 RedTransEl
*data
= state
->outRange
.data
;
150 /* Determine if we need to look higher or lower. */
151 bool anyLower
= mid
> low
;
152 bool anyHigher
= mid
< high
;
154 /* Determine if the keys at mid are the limits of the alphabet. */
155 bool limitLow
= data
[mid
].lowKey
== keyOps
->minKey
;
156 bool limitHigh
= data
[mid
].highKey
== keyOps
->maxKey
;
158 if ( anyLower
&& anyHigher
) {
159 /* Can go lower and higher than mid. */
160 out
<< TABS(level
) << "switch {" << endl
;
161 out
<< TABS(level
) << "case " << GET_WIDE_KEY(state
) << " < " <<
162 WIDE_KEY(state
, data
[mid
].lowKey
) << ":" << endl
;
163 emitRangeBSearch( state
, level
+1, low
, mid
-1 );
164 out
<< TABS(level
) << "case " << GET_WIDE_KEY(state
) << " > " <<
165 WIDE_KEY(state
, data
[mid
].highKey
) << ":" << endl
;
166 emitRangeBSearch( state
, level
+1, mid
+1, high
);
167 out
<< TABS(level
) << "default:" << endl
;
168 TRANS_GOTO(data
[mid
].value
, level
+1) << endl
;
169 out
<< TABS(level
) << "}" << endl
;
171 else if ( anyLower
&& !anyHigher
) {
172 /* Can go lower than mid but not higher. */
173 out
<< TABS(level
) << "switch {" << endl
;
174 out
<< TABS(level
) << "case " << GET_WIDE_KEY(state
) << " < " <<
175 WIDE_KEY(state
, data
[mid
].lowKey
) << ":" << endl
;
176 emitRangeBSearch( state
, level
+1, low
, mid
-1 );
178 /* if the higher is the highest in the alphabet then there is no
179 * sense testing it. */
181 out
<< TABS(level
) << "default:" << endl
;
182 TRANS_GOTO(data
[mid
].value
, level
+1) << endl
;
185 out
<< TABS(level
) << "case " << GET_WIDE_KEY(state
) << " <= " <<
186 WIDE_KEY(state
, data
[mid
].highKey
) << ":" << endl
;
187 TRANS_GOTO(data
[mid
].value
, level
+1) << endl
;
189 out
<< TABS(level
) << "}" << endl
;
191 else if ( !anyLower
&& anyHigher
) {
192 /* Can go higher than mid but not lower. */
193 out
<< TABS(level
) << "switch {" << endl
;
194 out
<< TABS(level
) << "case " << GET_WIDE_KEY(state
) << " > " <<
195 WIDE_KEY(state
, data
[mid
].highKey
) << ":" << endl
;
196 emitRangeBSearch( state
, level
+1, mid
+1, high
);
198 /* If the lower end is the lowest in the alphabet then there is no
199 * sense testing it. */
201 out
<< TABS(level
) << "default:" << endl
;
202 TRANS_GOTO(data
[mid
].value
, level
+1) << endl
;
205 out
<< TABS(level
) << "case " << GET_WIDE_KEY(state
) << " >= " <<
206 WIDE_KEY(state
, data
[mid
].lowKey
) << ":" << endl
;
207 TRANS_GOTO(data
[mid
].value
, level
+1) << endl
;
209 out
<< TABS(level
) << "}" << endl
;
212 /* Cannot go higher or lower than mid. It's mid or bust. What
213 * tests to do depends on limits of alphabet. */
214 if ( !limitLow
&& !limitHigh
) {
215 out
<< TABS(level
) << "if " << WIDE_KEY(state
, data
[mid
].lowKey
) << " <= " <<
216 GET_WIDE_KEY(state
) << " && " << GET_WIDE_KEY(state
) << " <= " <<
217 WIDE_KEY(state
, data
[mid
].highKey
) << " {" << endl
;
218 TRANS_GOTO(data
[mid
].value
, level
+1) << endl
;
219 out
<< TABS(level
) << "}" << endl
;
221 else if ( limitLow
&& !limitHigh
) {
222 out
<< TABS(level
) << "if " << GET_WIDE_KEY(state
) << " <= " <<
223 WIDE_KEY(state
, data
[mid
].highKey
) << " {" << endl
;
224 TRANS_GOTO(data
[mid
].value
, level
+1) << endl
;
225 out
<< TABS(level
) << "}" << endl
;
227 else if ( !limitLow
&& limitHigh
) {
228 out
<< TABS(level
) << "if " << WIDE_KEY(state
, data
[mid
].lowKey
) << " <= " <<
229 GET_WIDE_KEY(state
) << " {" << endl
;
230 TRANS_GOTO(data
[mid
].value
, level
+1) << endl
;
231 out
<< TABS(level
) << "}" << endl
;
234 /* Both high and low are at the limit. No tests to do. */
235 TRANS_GOTO(data
[mid
].value
, level
) << endl
;
240 void GoGotoCodeGen::STATE_GOTO_ERROR( int level
)
242 /* Label the state and bail immediately. */
244 RedStateAp
*state
= redFsm
->errState
;
245 out
<< TABS(level
) << "case " << state
->id
<< ":" << endl
;
246 out
<< TABS(level
+ 1) << "goto _out" << endl
;
249 void GoGotoCodeGen::COND_TRANSLATE( GenStateCond
*stateCond
, int level
)
251 GenCondSpace
*condSpace
= stateCond
->condSpace
;
252 out
<< TABS(level
) << "_widec = " <<
253 KEY(condSpace
->baseKey
) << " + (" << CAST(WIDE_ALPH_TYPE(), GET_KEY()) <<
254 " - " << KEY(keyOps
->minKey
) << ")" << endl
;
256 for ( GenCondSet::Iter csi
= condSpace
->condSet
; csi
.lte(); csi
++ ) {
257 out
<< TABS(level
) << "if ";
258 CONDITION( out
, *csi
);
259 Size condValOffset
= ((1 << csi
.pos()) * keyOps
->alphSize());
261 out
<< TABS(level
+ 1) << "_widec += " << condValOffset
<< endl
;
262 out
<< TABS(level
) << "}" << endl
;
266 void GoGotoCodeGen::emitCondBSearch( RedStateAp
*state
, int level
, int low
, int high
)
268 /* Get the mid position, staying on the lower end of the range. */
269 int mid
= (low
+ high
) >> 1;
270 GenStateCond
**data
= state
->stateCondVect
.data
;
272 /* Determine if we need to look higher or lower. */
273 bool anyLower
= mid
> low
;
274 bool anyHigher
= mid
< high
;
276 /* Determine if the keys at mid are the limits of the alphabet. */
277 bool limitLow
= data
[mid
]->lowKey
== keyOps
->minKey
;
278 bool limitHigh
= data
[mid
]->highKey
== keyOps
->maxKey
;
280 if ( anyLower
&& anyHigher
) {
281 /* Can go lower and higher than mid. */
282 out
<< TABS(level
) << "switch {" << endl
;
283 out
<< TABS(level
) << "case " << GET_KEY() << " < " <<
284 KEY(data
[mid
]->lowKey
) << ":" << endl
;
285 emitCondBSearch( state
, level
+1, low
, mid
-1 );
286 out
<< TABS(level
) << "case " << GET_KEY() << " > " <<
287 KEY(data
[mid
]->highKey
) << ":" << endl
;
288 emitCondBSearch( state
, level
+1, mid
+1, high
);
289 out
<< TABS(level
) << "default:" << endl
;
290 COND_TRANSLATE(data
[mid
], level
+1);
291 out
<< TABS(level
) << "}" << endl
;
293 else if ( anyLower
&& !anyHigher
) {
294 /* Can go lower than mid but not higher. */
295 out
<< TABS(level
) << "switch {" << endl
;
296 out
<< TABS(level
) << "case " << GET_KEY() << " < " <<
297 KEY(data
[mid
]->lowKey
) << ":" << endl
;
298 emitCondBSearch( state
, level
+1, low
, mid
-1 );
300 /* if the higher is the highest in the alphabet then there is no
301 * sense testing it. */
303 out
<< TABS(level
) << "default:" << endl
;
304 COND_TRANSLATE(data
[mid
], level
+1);
307 out
<< TABS(level
) << "case " << GET_KEY() << " <= " <<
308 KEY(data
[mid
]->highKey
) << ":" << endl
;
309 COND_TRANSLATE(data
[mid
], level
+1);
311 out
<< TABS(level
) << "}" << endl
;
313 else if ( !anyLower
&& anyHigher
) {
314 /* Can go higher than mid but not lower. */
315 out
<< TABS(level
) << "switch {" << endl
;
316 out
<< TABS(level
) << "case " << GET_KEY() << " > " <<
317 KEY(data
[mid
]->highKey
) << ":" << endl
;
318 emitCondBSearch( state
, level
+1, mid
+1, high
);
320 /* If the lower end is the lowest in the alphabet then there is no
321 * sense testing it. */
323 out
<< TABS(level
) << "default:" << endl
;
324 COND_TRANSLATE(data
[mid
], level
+1);
327 out
<< TABS(level
) << "case " << GET_KEY() << " >= " <<
328 KEY(data
[mid
]->lowKey
) << ":" << endl
;
329 COND_TRANSLATE(data
[mid
], level
+1);
331 out
<< TABS(level
) << "}" << endl
;
334 /* Cannot go higher or lower than mid. It's mid or bust. What
335 * tests to do depends on limits of alphabet. */
336 if ( !limitLow
&& !limitHigh
) {
337 out
<< TABS(level
) << "if " << KEY(data
[mid
]->lowKey
) << " <= " <<
338 GET_KEY() << " && " << GET_KEY() << " <= " <<
339 KEY(data
[mid
]->highKey
) << " {" << endl
;
340 COND_TRANSLATE(data
[mid
], level
+1);
341 out
<< TABS(level
) << "}" << endl
;
343 else if ( limitLow
&& !limitHigh
) {
344 out
<< TABS(level
) << "if " << GET_KEY() << " <= " <<
345 KEY(data
[mid
]->highKey
) << " {" << endl
;
346 COND_TRANSLATE(data
[mid
], level
+1);
347 out
<< TABS(level
) << "}" << endl
;
349 else if ( !limitLow
&& limitHigh
) {
350 out
<< TABS(level
) << "if " << KEY(data
[mid
]->lowKey
) << " <= " <<
351 GET_KEY() << " {" << endl
;
352 COND_TRANSLATE(data
[mid
], level
+1);
353 out
<< TABS(level
) << "}" << endl
;
356 /* Both high and low are at the limit. No tests to do. */
357 COND_TRANSLATE(data
[mid
], level
);
362 std::ostream
&GoGotoCodeGen::STATE_GOTOS( int level
)
364 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ ) {
365 if ( st
== redFsm
->errState
)
366 STATE_GOTO_ERROR(level
);
368 /* Writing code above state gotos. */
369 GOTO_HEADER( st
, level
);
371 if ( st
->stateCondVect
.length() > 0 ) {
372 out
<< TABS(level
+ 1) << "_widec = " << CAST(WIDE_ALPH_TYPE(), GET_KEY()) << endl
;
373 emitCondBSearch( st
, level
+ 1, 0, st
->stateCondVect
.length() - 1 );
377 if ( st
->outSingle
.length() > 0 )
378 emitSingleSwitch( st
, level
+ 1 );
380 /* Default case is to binary search for the ranges, if that fails then */
381 if ( st
->outRange
.length() > 0 )
382 emitRangeBSearch( st
, level
+ 1, 0, st
->outRange
.length() - 1 );
384 /* Write the default transition. */
385 TRANS_GOTO( st
->defTrans
, level
+ 1 ) << endl
;
391 std::ostream
&GoGotoCodeGen::TRANSITIONS()
393 /* Emit any transitions that have functions and that go to
395 for ( TransApSet::Iter trans
= redFsm
->transSet
; trans
.lte(); trans
++ ) {
396 /* Write the label for the transition so it can be jumped to. */
397 out
<< " tr" << trans
->id
<< ": ";
399 /* Destination state. */
400 if ( trans
->action
!= 0 && trans
->action
->anyCurStateRef() )
401 out
<< "_ps = " << vCS() << ";";
402 out
<< vCS() << " = " << trans
->targ
->id
<< "; ";
404 if ( trans
->action
!= 0 ) {
405 /* Write out the transition func. */
406 out
<< "goto f" << trans
->action
->actListId
<< endl
;
409 /* No code to execute, just loop around. */
410 out
<< "goto _again" << endl
;
416 std::ostream
&GoGotoCodeGen::EXEC_FUNCS()
418 /* Make labels that set acts and jump to execFuncs. Loop func indicies. */
419 for ( GenActionTableMap::Iter redAct
= redFsm
->actionMap
; redAct
.lte(); redAct
++ ) {
420 if ( redAct
->numTransRefs
> 0 ) {
421 out
<< " f" << redAct
->actListId
<< ": " <<
422 "_acts = " << (redAct
->location
+ 1) << ";"
423 " goto execFuncs" << endl
;
429 "execFuncs:" << endl
<<
430 " _nacts = " << CAST(UINT(), A() + "[_acts]") << "; _acts++" << endl
<<
431 " for ; _nacts > 0; _nacts-- {" << endl
<<
432 " _acts++" << endl
<<
433 " switch " << A() << "[_acts - 1]" << " {" << endl
;
438 " goto _again" << endl
;
442 unsigned int GoGotoCodeGen::TO_STATE_ACTION( RedStateAp
*state
)
445 if ( state
->toStateAction
!= 0 )
446 act
= state
->toStateAction
->location
+1;
450 unsigned int GoGotoCodeGen::FROM_STATE_ACTION( RedStateAp
*state
)
453 if ( state
->fromStateAction
!= 0 )
454 act
= state
->fromStateAction
->location
+1;
458 unsigned int GoGotoCodeGen::EOF_ACTION( RedStateAp
*state
)
461 if ( state
->eofAction
!= 0 )
462 act
= state
->eofAction
->location
+1;
466 std::ostream
&GoGotoCodeGen::TO_STATE_ACTIONS()
468 /* Take one off for the psuedo start state. */
469 int numStates
= redFsm
->stateList
.length();
470 unsigned int *vals
= new unsigned int[numStates
];
471 memset( vals
, 0, sizeof(unsigned int)*numStates
);
473 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ )
474 vals
[st
->id
] = TO_STATE_ACTION(st
);
477 for ( int st
= 0; st
< redFsm
->nextStateId
; st
++ ) {
478 /* Write any eof action. */
479 out
<< vals
[st
] << ", ";
480 if ( st
< numStates
-1 ) {
481 if ( (st
+1) % IALL
== 0 )
490 std::ostream
&GoGotoCodeGen::FROM_STATE_ACTIONS()
492 /* Take one off for the psuedo start state. */
493 int numStates
= redFsm
->stateList
.length();
494 unsigned int *vals
= new unsigned int[numStates
];
495 memset( vals
, 0, sizeof(unsigned int)*numStates
);
497 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ )
498 vals
[st
->id
] = FROM_STATE_ACTION(st
);
501 for ( int st
= 0; st
< redFsm
->nextStateId
; st
++ ) {
502 /* Write any eof action. */
503 out
<< vals
[st
] << ", ";
504 if ( st
< numStates
-1 ) {
505 if ( (st
+1) % IALL
== 0 )
514 std::ostream
&GoGotoCodeGen::EOF_ACTIONS()
516 /* Take one off for the psuedo start state. */
517 int numStates
= redFsm
->stateList
.length();
518 unsigned int *vals
= new unsigned int[numStates
];
519 memset( vals
, 0, sizeof(unsigned int)*numStates
);
521 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ )
522 vals
[st
->id
] = EOF_ACTION(st
);
525 for ( int st
= 0; st
< redFsm
->nextStateId
; st
++ ) {
526 /* Write any eof action. */
527 out
<< vals
[st
] << ", ";
528 if ( st
< numStates
-1 ) {
529 if ( (st
+1) % IALL
== 0 )
538 std::ostream
&GoGotoCodeGen::FINISH_CASES()
540 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ ) {
541 /* States that are final and have an out action need a case. */
542 if ( st
->eofAction
!= 0 ) {
543 /* Write the case label. */
544 out
<< TABS(2) << "case " << st
->id
<< ":" << endl
;
546 /* Write the goto func. */
547 out
<< TABS(3) << "goto f" << st
->eofAction
->actListId
<< endl
;
554 void GoGotoCodeGen::writeData()
556 if ( redFsm
->anyActions() ) {
557 OPEN_ARRAY( ARRAY_TYPE(redFsm
->maxActArrItem
), A() );
563 if ( redFsm
->anyToStateActions() ) {
564 OPEN_ARRAY( ARRAY_TYPE(redFsm
->maxActionLoc
), TSA() );
570 if ( redFsm
->anyFromStateActions() ) {
571 OPEN_ARRAY( ARRAY_TYPE(redFsm
->maxActionLoc
), FSA() );
572 FROM_STATE_ACTIONS();
577 if ( redFsm
->anyEofActions() ) {
578 OPEN_ARRAY( ARRAY_TYPE(redFsm
->maxActionLoc
), EA() );
587 void GoGotoCodeGen::writeExec()
590 outLabelUsed
= false;
594 if ( redFsm
->anyRegCurStateRef() )
595 out
<< " var _ps " << INT() << " = 0" << endl
;
597 if ( redFsm
->anyToStateActions() || redFsm
->anyRegActions()
598 || redFsm
->anyFromStateActions() )
601 " var _acts " << INT() << endl
<<
602 " var _nacts " << UINT() << endl
;
605 if ( redFsm
->anyConditions() )
606 out
<< " var _widec " << WIDE_ALPH_TYPE() << endl
;
613 " if " << P() << " == " << PE() << " {" << endl
<<
614 " goto _test_eof" << endl
<<
618 if ( redFsm
->errState
!= 0 ) {
621 " if " << vCS() << " == " << redFsm
->errState
->id
<< " {" << endl
<<
622 " goto _out" << endl
<<
626 out
<< "_resume:" << endl
;
628 if ( redFsm
->anyFromStateActions() ) {
630 " _acts = " << CAST(INT(), FSA() + "[" + vCS() + "]") << endl
<<
631 " _nacts = " << CAST(UINT(), A() + "[_acts]") << "; _acts++" << endl
<<
632 " for ; _nacts > 0; _nacts-- {" << endl
<<
633 " _acts++" << endl
<<
634 " switch " << A() << "[_acts - 1]" << " {" << endl
;
635 FROM_STATE_ACTION_SWITCH(2);
643 " switch " << vCS() << " {" << endl
;
651 if ( redFsm
->anyRegActions() )
652 EXEC_FUNCS() << endl
;
654 out
<< "_again:" << endl
;
656 if ( redFsm
->anyToStateActions() ) {
658 " _acts = " << CAST(INT(), TSA() + "[" + vCS() + "]") << endl
<<
659 " _nacts = " << CAST(UINT(), A() + "[_acts]") << "; _acts++" << endl
<<
660 " for ; _nacts > 0; _nacts-- {" << endl
<<
661 " _acts++" << endl
<<
662 " switch " << A() << "[_acts - 1]" << " {" << endl
;
663 TO_STATE_ACTION_SWITCH(2);
670 if ( redFsm
->errState
!= 0 ) {
673 " if " << vCS() << " == " << redFsm
->errState
->id
<< " {" << endl
<<
674 " goto _out" << endl
<<
680 " if " << P() << "++; " << P() << " != " << PE() << " {" << endl
<<
681 " goto _resume" << endl
<<
686 " " << P() << "++" << endl
<<
687 " goto _resume" << endl
;
691 out
<< " _test_eof: {}" << endl
;
693 if ( redFsm
->anyEofTrans() || redFsm
->anyEofActions() ) {
695 " if " << P() << " == " << vEOF() << " {" << endl
;
697 if ( redFsm
->anyEofTrans() ) {
699 " switch " << vCS() << " {" << endl
;
701 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ ) {
702 if ( st
->eofTrans
!= 0 )
704 " case " << st
->id
<< ":" << endl
<<
705 " goto tr" << st
->eofTrans
->id
<< endl
;
712 if ( redFsm
->anyEofActions() ) {
714 " __acts := " << CAST(INT(), EA() + "[" + vCS() + "]") << endl
<<
715 " __nacts := " << CAST(UINT(), A() + "[__acts]") << "; __acts++" << endl
<<
716 " for ; __nacts > 0; __nacts-- {" << endl
<<
717 " __acts++" << endl
<<
718 " switch " << A() << "[__acts - 1]" << " {" << endl
;
719 EOF_ACTION_SWITCH(3);
731 out
<< " _out: {}" << endl
;