2 * Copyright 2007 Victor Hugo Borja <vic@rubyforge.org>
3 * 2006-2007 Adrian Thurston <thurston@cs.queensu.ca>
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
25 #include "rlgen-ruby.h"
26 #include "rbx-gotocodegen.h"
34 inline string
label(string a
, int i
)
39 ostream
&RbxGotoCodeGen::rbxLabel(ostream
&out
, string label
)
41 out
<< "Rubinius.asm { @labels[:_" << FSM_NAME() << "_" << label
<< "].set! }\n";
45 ostream
&RbxGotoCodeGen::rbxGoto(ostream
&out
, string label
)
47 out
<< "Rubinius.asm { goto @labels[:_" << FSM_NAME() << "_" << label
<< "] }\n";
51 /* Emit the goto to take for a given transition. */
52 std::ostream
&RbxGotoCodeGen::TRANS_GOTO( RedTransAp
*trans
, int level
)
55 return rbxGoto(out
, label("tr",trans
->id
));
58 std::ostream
&RbxGotoCodeGen::TO_STATE_ACTION_SWITCH()
60 /* Walk the list of functions, printing the cases. */
61 for ( ActionList::Iter act
= actionList
; act
.lte(); act
++ ) {
62 /* Write out referenced actions. */
63 if ( act
->numToStateRefs
> 0 ) {
64 /* Write the case label, the action and the case break. */
65 out
<< "\twhen " << act
->actionId
<< " then\n";
66 ACTION( out
, act
, 0, false );
70 genLineDirective( out
);
74 std::ostream
&RbxGotoCodeGen::FROM_STATE_ACTION_SWITCH()
76 /* Walk the list of functions, printing the cases. */
77 for ( ActionList::Iter act
= actionList
; act
.lte(); act
++ ) {
78 /* Write out referenced actions. */
79 if ( act
->numFromStateRefs
> 0 ) {
80 /* Write the case label, the action and the case break. */
81 out
<< "\twhen " << act
->actionId
<< " then\n";
82 ACTION( out
, act
, 0, false );
86 genLineDirective( out
);
90 std::ostream
&RbxGotoCodeGen::EOF_ACTION_SWITCH()
92 /* Walk the list of functions, printing the cases. */
93 for ( ActionList::Iter act
= actionList
; act
.lte(); act
++ ) {
94 /* Write out referenced actions. */
95 if ( act
->numEofRefs
> 0 ) {
96 /* Write the case label, the action and the case break. */
97 out
<< "\twhen " << act
->actionId
<< " then\n";
98 ACTION( out
, act
, 0, true );
102 genLineDirective( out
);
106 std::ostream
&RbxGotoCodeGen::ACTION_SWITCH()
108 /* Walk the list of functions, printing the cases. */
109 for ( ActionList::Iter act
= actionList
; act
.lte(); act
++ ) {
110 /* Write out referenced actions. */
111 if ( act
->numTransRefs
> 0 ) {
112 /* Write the case label, the action and the case break. */
113 out
<< "\twhen " << act
->actionId
<< " then\n";
114 ACTION( out
, act
, 0, false );
118 genLineDirective( out
);
122 void RbxGotoCodeGen::GOTO_HEADER( RedStateAp
*state
)
124 /* Label the state. */
125 out
<< "when " << state
->id
<< " then\n";
129 void RbxGotoCodeGen::emitSingleSwitch( RedStateAp
*state
)
131 /* Load up the singles. */
132 int numSingles
= state
->outSingle
.length();
133 RedTransEl
*data
= state
->outSingle
.data
;
135 if ( numSingles
== 1 ) {
136 /* If there is a single single key then write it out as an if. */
137 out
<< "\tif " << GET_WIDE_KEY(state
) << " == " <<
138 KEY(data
[0].lowKey
) << " \n\t\t";
140 /* Virtual function for writing the target of the transition. */
141 TRANS_GOTO(data
[0].value
, 0) << "\n";
145 else if ( numSingles
> 1 ) {
146 /* Write out single keys in a switch if there is more than one. */
147 out
<< "\tcase " << GET_WIDE_KEY(state
) << "\n";
149 /* Write out the single indicies. */
150 for ( int j
= 0; j
< numSingles
; j
++ ) {
151 out
<< "\t\twhen " << KEY(data
[j
].lowKey
) << " then\n";
152 TRANS_GOTO(data
[j
].value
, 0) << "\n";
155 /* Close off the transition switch. */
160 void RbxGotoCodeGen::emitRangeBSearch( RedStateAp
*state
, int level
, int low
, int high
)
162 /* Get the mid position, staying on the lower end of the range. */
163 int mid
= (low
+ high
) >> 1;
164 RedTransEl
*data
= state
->outRange
.data
;
166 /* Determine if we need to look higher or lower. */
167 bool anyLower
= mid
> low
;
168 bool anyHigher
= mid
< high
;
170 /* Determine if the keys at mid are the limits of the alphabet. */
171 bool limitLow
= data
[mid
].lowKey
== keyOps
->minKey
;
172 bool limitHigh
= data
[mid
].highKey
== keyOps
->maxKey
;
174 if ( anyLower
&& anyHigher
) {
175 /* Can go lower and higher than mid. */
176 out
<< TABS(level
) << "if " << GET_WIDE_KEY(state
) << " < " <<
177 KEY(data
[mid
].lowKey
) << " \n";
178 emitRangeBSearch( state
, level
+1, low
, mid
-1 );
179 out
<< TABS(level
) << "elsif " << GET_WIDE_KEY(state
) << " > " <<
180 KEY(data
[mid
].highKey
) << " \n";
181 emitRangeBSearch( state
, level
+1, mid
+1, high
);
182 out
<< TABS(level
) << "else\n";
183 TRANS_GOTO(data
[mid
].value
, level
+1) << "\n";
184 out
<< TABS(level
) << "end\n";
186 else if ( anyLower
&& !anyHigher
) {
187 /* Can go lower than mid but not higher. */
188 out
<< TABS(level
) << "if " << GET_WIDE_KEY(state
) << " < " <<
189 KEY(data
[mid
].lowKey
) << " then\n";
190 emitRangeBSearch( state
, level
+1, low
, mid
-1 );
192 /* if the higher is the highest in the alphabet then there is no
193 * sense testing it. */
195 out
<< TABS(level
) << "else\n";
196 TRANS_GOTO(data
[mid
].value
, level
+1) << "\n";
199 out
<< TABS(level
) << "elsif" << GET_WIDE_KEY(state
) << " <= " <<
200 KEY(data
[mid
].highKey
) << " )\n";
201 TRANS_GOTO(data
[mid
].value
, level
+1) << "\n";
203 out
<< TABS(level
) << "end\n";
205 else if ( !anyLower
&& anyHigher
) {
206 /* Can go higher than mid but not lower. */
207 out
<< TABS(level
) << "if " << GET_WIDE_KEY(state
) << " > " <<
208 KEY(data
[mid
].highKey
) << " \n";
209 emitRangeBSearch( state
, level
+1, mid
+1, high
);
211 /* If the lower end is the lowest in the alphabet then there is no
212 * sense testing it. */
214 out
<< TABS(level
) << "else\n";
215 TRANS_GOTO(data
[mid
].value
, level
+1) << "\n";
218 out
<< TABS(level
) << "elsif " << GET_WIDE_KEY(state
) << " >= " <<
219 KEY(data
[mid
].lowKey
) << " then\n";
220 TRANS_GOTO(data
[mid
].value
, level
+1) << "\n";
222 out
<< TABS(level
) << "end\n";
225 /* Cannot go higher or lower than mid. It's mid or bust. What
226 * tests to do depends on limits of alphabet. */
227 if ( !limitLow
&& !limitHigh
) {
228 out
<< TABS(level
) << "if " << KEY(data
[mid
].lowKey
) << " <= " <<
229 GET_WIDE_KEY(state
) << " && " << GET_WIDE_KEY(state
) << " <= " <<
230 KEY(data
[mid
].highKey
) << " \n";
231 TRANS_GOTO(data
[mid
].value
, level
+1) << "\n";
232 out
<< TABS(level
) << "end\n";
234 else if ( limitLow
&& !limitHigh
) {
235 out
<< TABS(level
) << "if " << GET_WIDE_KEY(state
) << " <= " <<
236 KEY(data
[mid
].highKey
) << " \n";
237 TRANS_GOTO(data
[mid
].value
, level
+1) << "\n";
238 out
<< TABS(level
) << "end\n";
240 else if ( !limitLow
&& limitHigh
) {
241 out
<< TABS(level
) << "if " << KEY(data
[mid
].lowKey
) << " <= " <<
242 GET_WIDE_KEY(state
) << " \n";
243 TRANS_GOTO(data
[mid
].value
, level
+1) << "\n";
244 out
<< TABS(level
) << "end\n";
247 /* Both high and low are at the limit. No tests to do. */
248 TRANS_GOTO(data
[mid
].value
, level
+1) << "\n";
253 void RbxGotoCodeGen::STATE_GOTO_ERROR()
255 /* Label the state and bail immediately. */
257 RedStateAp
*state
= redFsm
->errState
;
258 out
<< "when " << state
->id
<< " then\n";
259 rbxGoto(out
<< " ", "_out") << "\n";
262 void RbxGotoCodeGen::COND_TRANSLATE( StateCond
*stateCond
, int level
)
264 CondSpace
*condSpace
= stateCond
->condSpace
;
265 out
<< TABS(level
) << "_widec = " <<
266 KEY(condSpace
->baseKey
) << " + (" << GET_KEY() <<
267 " - " << KEY(keyOps
->minKey
) << ");\n";
269 for ( CondSet::Iter csi
= condSpace
->condSet
; csi
.lte(); csi
++ ) {
270 out
<< TABS(level
) << "if ";
271 CONDITION( out
, *csi
);
272 Size condValOffset
= ((1 << csi
.pos()) * keyOps
->alphSize());
273 out
<< "\n _widec += " << condValOffset
<< ";\n end";
277 void RbxGotoCodeGen::emitCondBSearch( RedStateAp
*state
, int level
, int low
, int high
)
279 /* Get the mid position, staying on the lower end of the range. */
280 int mid
= (low
+ high
) >> 1;
281 StateCond
**data
= state
->stateCondVect
.data
;
283 /* Determine if we need to look higher or lower. */
284 bool anyLower
= mid
> low
;
285 bool anyHigher
= mid
< high
;
287 /* Determine if the keys at mid are the limits of the alphabet. */
288 bool limitLow
= data
[mid
]->lowKey
== keyOps
->minKey
;
289 bool limitHigh
= data
[mid
]->highKey
== keyOps
->maxKey
;
291 if ( anyLower
&& anyHigher
) {
292 /* Can go lower and higher than mid. */
293 out
<< TABS(level
) << "if " << GET_KEY() << " < " <<
294 KEY(data
[mid
]->lowKey
) << " \n";
295 emitCondBSearch( state
, level
+1, low
, mid
-1 );
296 out
<< TABS(level
) << "elsif " << GET_KEY() << " > " <<
297 KEY(data
[mid
]->highKey
) << " \n";
298 emitCondBSearch( state
, level
+1, mid
+1, high
);
299 out
<< TABS(level
) << "else\n";
300 COND_TRANSLATE(data
[mid
], level
+1);
301 out
<< TABS(level
) << "end\n";
303 else if ( anyLower
&& !anyHigher
) {
304 /* Can go lower than mid but not higher. */
305 out
<< TABS(level
) << "if " << GET_KEY() << " < " <<
306 KEY(data
[mid
]->lowKey
) << " \n";
307 emitCondBSearch( state
, level
+1, low
, mid
-1 );
309 /* if the higher is the highest in the alphabet then there is no
310 * sense testing it. */
312 out
<< TABS(level
) << "else\n";
313 COND_TRANSLATE(data
[mid
], level
+1);
316 out
<< TABS(level
) << "elsif " << GET_KEY() << " <= " <<
317 KEY(data
[mid
]->highKey
) << " then\n";
318 COND_TRANSLATE(data
[mid
], level
+1);
320 out
<< TABS(level
) << "end\n";
323 else if ( !anyLower
&& anyHigher
) {
324 /* Can go higher than mid but not lower. */
325 out
<< TABS(level
) << "if " << GET_KEY() << " > " <<
326 KEY(data
[mid
]->highKey
) << " \n";
327 emitCondBSearch( state
, level
+1, mid
+1, high
);
329 /* If the lower end is the lowest in the alphabet then there is no
330 * sense testing it. */
332 out
<< TABS(level
) << "else\n";
333 COND_TRANSLATE(data
[mid
], level
+1);
336 out
<< TABS(level
) << "elsif " << GET_KEY() << " >= " <<
337 KEY(data
[mid
]->lowKey
) << " then\n";
338 COND_TRANSLATE(data
[mid
], level
+1);
340 out
<< TABS(level
) << "end\n";
343 /* Cannot go higher or lower than mid. It's mid or bust. What
344 * tests to do depends on limits of alphabet. */
345 if ( !limitLow
&& !limitHigh
) {
346 out
<< TABS(level
) << "if " << KEY(data
[mid
]->lowKey
) << " <= " <<
347 GET_KEY() << " && " << GET_KEY() << " <= " <<
348 KEY(data
[mid
]->highKey
) << " then\n";
349 COND_TRANSLATE(data
[mid
], level
+1);
350 out
<< TABS(level
) << "end\n";
352 else if ( limitLow
&& !limitHigh
) {
353 out
<< TABS(level
) << "if " << GET_KEY() << " <= " <<
354 KEY(data
[mid
]->highKey
) << " then\n";
355 COND_TRANSLATE(data
[mid
], level
+1);
356 out
<< TABS(level
) << "end\n";
358 else if ( !limitLow
&& limitHigh
) {
359 out
<< TABS(level
) << "if " << KEY(data
[mid
]->lowKey
) << " <= " <<
360 GET_KEY() << " then\n";
361 COND_TRANSLATE(data
[mid
], level
+1);
362 out
<< TABS(level
) << "end\n";
365 /* Both high and low are at the limit. No tests to do. */
366 COND_TRANSLATE(data
[mid
], level
);
371 std::ostream
&RbxGotoCodeGen::STATE_GOTOS()
373 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ ) {
374 if ( st
== redFsm
->errState
)
377 /* Writing code above state gotos. */
380 if ( st
->stateCondVect
.length() > 0 ) {
381 out
<< " _widec = " << GET_KEY() << ";\n";
382 emitCondBSearch( st
, 1, 0, st
->stateCondVect
.length() - 1 );
386 if ( st
->outSingle
.length() > 0 )
387 emitSingleSwitch( st
);
389 /* Default case is to binary search for the ranges, if that fails then */
390 if ( st
->outRange
.length() > 0 )
391 emitRangeBSearch( st
, 1, 0, st
->outRange
.length() - 1 );
393 /* Write the default transition. */
394 TRANS_GOTO( st
->defTrans
, 1 ) << "\n";
400 std::ostream
&RbxGotoCodeGen::TRANSITIONS()
402 /* Emit any transitions that have functions and that go to
404 for ( TransApSet::Iter trans
= redFsm
->transSet
; trans
.lte(); trans
++ ) {
405 /* Write the label for the transition so it can be jumped to. */
406 rbxLabel(out
<< " ", label("tr", trans
->id
)) << "\n";
408 /* Destination state. */
409 if ( trans
->action
!= 0 && trans
->action
->anyCurStateRef() )
410 out
<< "_ps = " << CS() << "'n";
411 out
<< CS() << " = " << trans
->targ
->id
<< "\n";
413 if ( trans
->action
!= 0 ) {
414 /* Write out the transition func. */
415 rbxGoto(out
, label("f", trans
->action
->actListId
)) << "\n";
418 /* No code to execute, just loop around. */
419 rbxGoto(out
, "_again") << "\n";
425 std::ostream
&RbxGotoCodeGen::EXEC_FUNCS()
427 /* Make labels that set acts and jump to execFuncs. Loop func indicies. */
428 for ( ActionTableMap::Iter redAct
= redFsm
->actionMap
; redAct
.lte(); redAct
++ ) {
429 if ( redAct
->numTransRefs
> 0 ) {
430 rbxLabel(out
, label("f", redAct
->actListId
)) << "\n" <<
431 "_acts = " << itoa( redAct
->location
+1 ) << "\n";
432 rbxGoto(out
, "execFuncs") << "\n";
436 rbxLabel(out
, "execFuncs") <<
438 " _nacts = " << A() << "[_acts]\n"
440 " while ( _nacts > 0 ) \n"
443 " case ( "<< A() << "[_acts-1] ) \n";
448 rbxGoto(out
, "_again");
452 int RbxGotoCodeGen::TO_STATE_ACTION( RedStateAp
*state
)
455 if ( state
->toStateAction
!= 0 )
456 act
= state
->toStateAction
->location
+1;
460 int RbxGotoCodeGen::FROM_STATE_ACTION( RedStateAp
*state
)
463 if ( state
->fromStateAction
!= 0 )
464 act
= state
->fromStateAction
->location
+1;
468 int RbxGotoCodeGen::EOF_ACTION( RedStateAp
*state
)
471 if ( state
->eofAction
!= 0 )
472 act
= state
->eofAction
->location
+1;
476 std::ostream
&RbxGotoCodeGen::TO_STATE_ACTIONS()
478 /* Take one off for the psuedo start state. */
479 int numStates
= redFsm
->stateList
.length();
480 unsigned int *vals
= new unsigned int[numStates
];
481 memset( vals
, 0, sizeof(unsigned int)*numStates
);
483 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ )
484 vals
[st
->id
] = TO_STATE_ACTION(st
);
487 for ( int st
= 0; st
< redFsm
->nextStateId
; st
++ ) {
488 /* Write any eof action. */
490 if ( st
< numStates
-1 ) {
492 if ( (st
+1) % IALL
== 0 )
501 std::ostream
&RbxGotoCodeGen::FROM_STATE_ACTIONS()
503 /* Take one off for the psuedo start state. */
504 int numStates
= redFsm
->stateList
.length();
505 unsigned int *vals
= new unsigned int[numStates
];
506 memset( vals
, 0, sizeof(unsigned int)*numStates
);
508 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ )
509 vals
[st
->id
] = FROM_STATE_ACTION(st
);
512 for ( int st
= 0; st
< redFsm
->nextStateId
; st
++ ) {
513 /* Write any eof action. */
515 if ( st
< numStates
-1 ) {
517 if ( (st
+1) % IALL
== 0 )
526 std::ostream
&RbxGotoCodeGen::EOF_ACTIONS()
528 /* Take one off for the psuedo start state. */
529 int numStates
= redFsm
->stateList
.length();
530 unsigned int *vals
= new unsigned int[numStates
];
531 memset( vals
, 0, sizeof(unsigned int)*numStates
);
533 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ )
534 vals
[st
->id
] = EOF_ACTION(st
);
537 for ( int st
= 0; st
< redFsm
->nextStateId
; st
++ ) {
538 /* Write any eof action. */
540 if ( st
< numStates
-1 ) {
542 if ( (st
+1) % IALL
== 0 )
551 std::ostream
&RbxGotoCodeGen::FINISH_CASES()
553 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ ) {
554 /* States that are final and have an out action need a case. */
555 if ( st
->eofAction
!= 0 ) {
556 /* Write the case label. */
557 out
<< "\t\twhen " << st
->id
<< " then\n";
559 /* Write the goto func. */
560 rbxGoto(out
, label("f", st
->eofAction
->actListId
)) << "\n";
567 void RbxGotoCodeGen::GOTO( ostream
&ret
, int gotoDest
, bool inFinish
)
569 ret
<< "begin\n" << CS() << " = " << gotoDest
<< " ";
570 rbxGoto(ret
, "_again") <<
574 void RbxGotoCodeGen::GOTO_EXPR( ostream
&ret
, GenInlineItem
*ilItem
, bool inFinish
)
576 ret
<< "begin\n" << CS() << " = (";
577 INLINE_LIST( ret
, ilItem
->children
, 0, inFinish
);
579 rbxGoto(ret
, "_again") <<
583 void RbxGotoCodeGen::CURS( ostream
&ret
, bool inFinish
)
588 void RbxGotoCodeGen::TARGS( ostream
&ret
, bool inFinish
, int targState
)
590 ret
<< "(" << CS() << ")";
593 void RbxGotoCodeGen::NEXT( ostream
&ret
, int nextDest
, bool inFinish
)
595 ret
<< CS() << " = " << nextDest
<< ";";
598 void RbxGotoCodeGen::NEXT_EXPR( ostream
&ret
, GenInlineItem
*ilItem
, bool inFinish
)
600 ret
<< CS() << " = (";
601 INLINE_LIST( ret
, ilItem
->children
, 0, inFinish
);
605 void RbxGotoCodeGen::CALL( ostream
&ret
, int callDest
, int targState
, bool inFinish
)
607 if ( prePushExpr
!= 0 ) {
609 INLINE_LIST( ret
, prePushExpr
, 0, false );
613 << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = " <<
615 rbxGoto(ret
, "_again") <<
618 if ( prePushExpr
!= 0 )
622 void RbxGotoCodeGen::CALL_EXPR( ostream
&ret
, GenInlineItem
*ilItem
, int targState
, bool inFinish
)
624 if ( prePushExpr
!= 0 ) {
626 INLINE_LIST( ret
, prePushExpr
, 0, false );
629 ret
<< "begin\n" << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = (";
630 INLINE_LIST( ret
, ilItem
->children
, targState
, inFinish
);
632 rbxGoto(ret
, "_again") <<
635 if ( prePushExpr
!= 0 )
639 void RbxGotoCodeGen::RET( ostream
&ret
, bool inFinish
)
641 ret
<< "begin\n" << CS() << " = " << STACK() << "[--" << TOP() << "]; " ;
643 if ( postPopExpr
!= 0 ) {
645 INLINE_LIST( ret
, postPopExpr
, 0, false );
649 rbxGoto(ret
, "_again") <<
653 void RbxGotoCodeGen::BREAK( ostream
&ret
, int targState
)
659 " " << P() << " += 1\n"
660 " " << rbxGoto(ret
, "_out") << "\n"
664 void RbxGotoCodeGen::writeData()
666 if ( redFsm
->anyActions() ) {
667 OPEN_ARRAY( ARRAY_TYPE(redFsm
->maxActArrItem
), A() );
673 if ( redFsm
->anyToStateActions() ) {
674 OPEN_ARRAY( ARRAY_TYPE(redFsm
->maxActionLoc
), TSA() );
680 if ( redFsm
->anyFromStateActions() ) {
681 OPEN_ARRAY( ARRAY_TYPE(redFsm
->maxActionLoc
), FSA() );
682 FROM_STATE_ACTIONS();
687 if ( redFsm
->anyEofActions() ) {
688 OPEN_ARRAY( ARRAY_TYPE(redFsm
->maxActionLoc
), EA() );
697 void RbxGotoCodeGen::writeExec()
699 outLabelUsed
= false;
703 out
<< " Rubinius.asm { @labels = Hash.new { |h,k| h[k] = new_label } }\n";
705 if ( redFsm
->anyRegCurStateRef() )
706 out
<< " _ps = 0;\n";
708 if ( redFsm
->anyToStateActions() || redFsm
->anyRegActions()
709 || redFsm
->anyFromStateActions() )
711 out
<< " _acts, _nacts = nil\n";
714 if ( redFsm
->anyConditions() )
715 out
<< " _widec = nil\n";
722 " if ( " << P() << " == " << PE() << " )\n";
723 rbxGoto(out
<< " ", "_out") << "\n" <<
727 if ( redFsm
->errState
!= 0 ) {
730 " if ( " << CS() << " == " << redFsm
->errState
->id
<< " )\n";
731 rbxGoto(out
<< " ", "_out") << "\n" <<
735 rbxLabel(out
, "_resume") << "\n";
737 if ( redFsm
->anyFromStateActions() ) {
740 " _acts = " << ARR_OFF( A(), FSA() + "[" + CS() + "]" ) << ";\n"
741 " _nacts = " << " *_acts++;\n"
742 " while ( _nacts-- > 0 ) {\n"
743 " switch ( *_acts++ ) {\n";
744 FROM_STATE_ACTION_SWITCH();
752 " case ( " << CS() << " )\n";
760 if ( redFsm
->anyRegActions() )
761 EXEC_FUNCS() << "\n";
764 rbxLabel(out
, "_again") << "\n";
766 if ( redFsm
->anyToStateActions() ) {
768 " _acts = " << ARR_OFF( A(), TSA() + "[" + CS() + "]" ) << ";\n"
769 " _nacts = " << " *_acts++;\n"
770 " while ( _nacts-- > 0 ) {\n"
771 " switch ( *_acts++ ) {\n";
772 TO_STATE_ACTION_SWITCH();
779 if ( redFsm
->errState
!= 0 ) {
782 " if ( " << CS() << " == " << redFsm
->errState
->id
<< " )\n";
783 rbxGoto(out
<< " ", "_out") << "\n" <<
788 out
<< " " << P() << " += 1\n"
789 " if ( " << P() << " != " << PE() << " )\n";
790 rbxGoto(out
<< " ", "_resume") << "\n" <<
795 " " << P() << " += 1;\n";
796 rbxGoto(out
<< " ", "_resume") << "\n";
800 rbxLabel(out
, "_out") << "\n";
805 void RbxGotoCodeGen::writeEOF()
807 if ( redFsm
->anyEofActions() ) {
811 ARR_OFF( A(), EA() + "[" + CS() + "]" ) << ";\n"
812 " " << " _nacts = " << " *_acts++;\n"
813 " while ( _nacts-- > 0 ) {\n"
814 " switch ( *_acts++ ) {\n";
827 * indent-tabs-mode: 1
828 * c-file-style: "bsd"