Started on the move back to a single executable. The backend programs are now a
[ragel.git] / rlgen-ruby / rbx-gotocodegen.cpp
blob4bcf0dfb814e054f3a9b5a430d818745f4c206ed
1 /*
2 * Copyright 2007 Victor Hugo Borja <vic@rubyforge.org>
3 * 2006-2007 Adrian Thurston <thurston@cs.queensu.ca>
4 */
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 <stdio.h>
24 #include <string>
25 #include "rlgen-ruby.h"
26 #include "rbx-gotocodegen.h"
27 #include "redfsm.h"
28 #include "bstmap.h"
29 #include "gendata.h"
31 using std::ostream;
32 using std::string;
34 inline string label(string a, int i)
36 return a + itoa(i);
39 ostream &RbxGotoCodeGen::rbxLabel(ostream &out, string label)
41 out << "Rubinius.asm { @labels[:_" << FSM_NAME() << "_" << label << "].set! }\n";
42 return out;
45 ostream &RbxGotoCodeGen::rbxGoto(ostream &out, string label)
47 out << "Rubinius.asm { goto @labels[:_" << FSM_NAME() << "_" << label << "] }\n";
48 return out;
51 /* Emit the goto to take for a given transition. */
52 std::ostream &RbxGotoCodeGen::TRANS_GOTO( RedTransAp *trans, int level )
54 out << TABS(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 );
71 return 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 );
87 return 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 );
103 return 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 );
119 return 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";
143 out << "end\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. */
156 out << "\tend\n";
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. */
194 if ( limitHigh ) {
195 out << TABS(level) << "else\n";
196 TRANS_GOTO(data[mid].value, level+1) << "\n";
198 else {
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. */
213 if ( limitLow ) {
214 out << TABS(level) << "else\n";
215 TRANS_GOTO(data[mid].value, level+1) << "\n";
217 else {
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";
224 else {
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";
246 else {
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. */
256 outLabelUsed = true;
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. */
311 if ( limitHigh ) {
312 out << TABS(level) << "else\n";
313 COND_TRANSLATE(data[mid], level+1);
315 else {
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. */
331 if ( limitLow ) {
332 out << TABS(level) << "else\n";
333 COND_TRANSLATE(data[mid], level+1);
335 else {
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";
342 else {
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";
364 else {
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 )
375 STATE_GOTO_ERROR();
376 else {
377 /* Writing code above state gotos. */
378 GOTO_HEADER( st );
380 if ( st->stateCondVect.length() > 0 ) {
381 out << " _widec = " << GET_KEY() << ";\n";
382 emitCondBSearch( st, 1, 0, st->stateCondVect.length() - 1 );
385 /* Try singles. */
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";
397 return out;
400 std::ostream &RbxGotoCodeGen::TRANSITIONS()
402 /* Emit any transitions that have functions and that go to
403 * this state. */
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";
417 else {
418 /* No code to execute, just loop around. */
419 rbxGoto(out, "_again") << "\n";
422 return out;
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") <<
437 "\n"
438 " _nacts = " << A() << "[_acts]\n"
439 " _acts += 1\n"
440 " while ( _nacts > 0 ) \n"
441 " _nacts -= 1\n"
442 " _acts += 1\n"
443 " case ( "<< A() << "[_acts-1] ) \n";
444 ACTION_SWITCH();
445 out <<
446 " end\n"
447 " end \n";
448 rbxGoto(out, "_again");
449 return out;
452 int RbxGotoCodeGen::TO_STATE_ACTION( RedStateAp *state )
454 int act = 0;
455 if ( state->toStateAction != 0 )
456 act = state->toStateAction->location+1;
457 return act;
460 int RbxGotoCodeGen::FROM_STATE_ACTION( RedStateAp *state )
462 int act = 0;
463 if ( state->fromStateAction != 0 )
464 act = state->fromStateAction->location+1;
465 return act;
468 int RbxGotoCodeGen::EOF_ACTION( RedStateAp *state )
470 int act = 0;
471 if ( state->eofAction != 0 )
472 act = state->eofAction->location+1;
473 return act;
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);
486 out << "\t";
487 for ( int st = 0; st < redFsm->nextStateId; st++ ) {
488 /* Write any eof action. */
489 out << vals[st];
490 if ( st < numStates-1 ) {
491 out << ", ";
492 if ( (st+1) % IALL == 0 )
493 out << "\n\t";
496 out << "\n";
497 delete[] vals;
498 return out;
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);
511 out << "\t";
512 for ( int st = 0; st < redFsm->nextStateId; st++ ) {
513 /* Write any eof action. */
514 out << vals[st];
515 if ( st < numStates-1 ) {
516 out << ", ";
517 if ( (st+1) % IALL == 0 )
518 out << "\n\t";
521 out << "\n";
522 delete[] vals;
523 return out;
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);
536 out << "\t";
537 for ( int st = 0; st < redFsm->nextStateId; st++ ) {
538 /* Write any eof action. */
539 out << vals[st];
540 if ( st < numStates-1 ) {
541 out << ", ";
542 if ( (st+1) % IALL == 0 )
543 out << "\n\t";
546 out << "\n";
547 delete[] vals;
548 return out;
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";
564 return out;
567 void RbxGotoCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
569 ret << "begin\n" << CS() << " = " << gotoDest << " ";
570 rbxGoto(ret, "_again") <<
571 "\nend\n";
574 void RbxGotoCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
576 ret << "begin\n" << CS() << " = (";
577 INLINE_LIST( ret, ilItem->children, 0, inFinish );
578 ret << ")";
579 rbxGoto(ret, "_again") <<
580 "\nend\n";
583 void RbxGotoCodeGen::CURS( ostream &ret, bool inFinish )
585 ret << "(_ps)";
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 );
602 ret << ");";
605 void RbxGotoCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
607 if ( prePushExpr != 0 ) {
608 ret << "{";
609 INLINE_LIST( ret, prePushExpr, 0, false );
612 ret << "begin\n"
613 << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = " <<
614 callDest << "; ";
615 rbxGoto(ret, "_again") <<
616 "\nend\n";
618 if ( prePushExpr != 0 )
619 ret << "}";
622 void RbxGotoCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish )
624 if ( prePushExpr != 0 ) {
625 ret << "{";
626 INLINE_LIST( ret, prePushExpr, 0, false );
629 ret << "begin\n" << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = (";
630 INLINE_LIST( ret, ilItem->children, targState, inFinish );
631 ret << "); ";
632 rbxGoto(ret, "_again") <<
633 "\nend\n";
635 if ( prePushExpr != 0 )
636 ret << "}";
639 void RbxGotoCodeGen::RET( ostream &ret, bool inFinish )
641 ret << "begin\n" << CS() << " = " << STACK() << "[--" << TOP() << "]; " ;
643 if ( postPopExpr != 0 ) {
644 ret << "{";
645 INLINE_LIST( ret, postPopExpr, 0, false );
646 ret << "}";
649 rbxGoto(ret, "_again") <<
650 "\nend\n";
653 void RbxGotoCodeGen::BREAK( ostream &ret, int targState )
655 outLabelUsed = true;
657 out <<
658 " begin\n"
659 " " << P() << " += 1\n"
660 " " << rbxGoto(ret, "_out") << "\n"
661 " end\n";
664 void RbxGotoCodeGen::writeData()
666 if ( redFsm->anyActions() ) {
667 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
668 ACTIONS_ARRAY();
669 CLOSE_ARRAY() <<
670 "\n";
673 if ( redFsm->anyToStateActions() ) {
674 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
675 TO_STATE_ACTIONS();
676 CLOSE_ARRAY() <<
677 "\n";
680 if ( redFsm->anyFromStateActions() ) {
681 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
682 FROM_STATE_ACTIONS();
683 CLOSE_ARRAY() <<
684 "\n";
687 if ( redFsm->anyEofActions() ) {
688 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
689 EOF_ACTIONS();
690 CLOSE_ARRAY() <<
691 "\n";
694 STATE_IDS();
697 void RbxGotoCodeGen::writeExec()
699 outLabelUsed = false;
701 out << " begin\n";
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";
717 out << "\n";
719 if ( hasEnd ) {
720 outLabelUsed = true;
721 out <<
722 " if ( " << P() << " == " << PE() << " )\n";
723 rbxGoto(out << " ", "_out") << "\n" <<
724 " end\n";
727 if ( redFsm->errState != 0 ) {
728 outLabelUsed = true;
729 out <<
730 " if ( " << CS() << " == " << redFsm->errState->id << " )\n";
731 rbxGoto(out << " ", "_out") << "\n" <<
732 " end\n";
735 rbxLabel(out, "_resume") << "\n";
737 if ( redFsm->anyFromStateActions() ) {
738 out <<
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();
745 out <<
746 " }\n"
747 " }\n"
748 "\n";
751 out <<
752 " case ( " << CS() << " )\n";
753 STATE_GOTOS();
754 out <<
755 " end # case\n"
756 "\n";
757 TRANSITIONS() <<
758 "\n";
760 if ( redFsm->anyRegActions() )
761 EXEC_FUNCS() << "\n";
764 rbxLabel(out, "_again") << "\n";
766 if ( redFsm->anyToStateActions() ) {
767 out <<
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();
773 out <<
774 " }\n"
775 " }\n"
776 "\n";
779 if ( redFsm->errState != 0 ) {
780 outLabelUsed = true;
781 out <<
782 " if ( " << CS() << " == " << redFsm->errState->id << " )\n";
783 rbxGoto(out << " ", "_out") << "\n" <<
784 " end" << "\n";
787 if ( hasEnd ) {
788 out << " " << P() << " += 1\n"
789 " if ( " << P() << " != " << PE() << " )\n";
790 rbxGoto(out << " ", "_resume") << "\n" <<
791 " end" << "\n";
793 else {
794 out <<
795 " " << P() << " += 1;\n";
796 rbxGoto(out << " ", "_resume") << "\n";
799 if ( outLabelUsed )
800 rbxLabel(out, "_out") << "\n";
802 out << " end\n";
805 void RbxGotoCodeGen::writeEOF()
807 if ( redFsm->anyEofActions() ) {
808 out <<
809 " {\n"
810 " _acts = " <<
811 ARR_OFF( A(), EA() + "[" + CS() + "]" ) << ";\n"
812 " " << " _nacts = " << " *_acts++;\n"
813 " while ( _nacts-- > 0 ) {\n"
814 " switch ( *_acts++ ) {\n";
815 EOF_ACTION_SWITCH();
816 out <<
817 " }\n"
818 " }\n"
819 " }\n"
820 "\n";
825 * Local Variables:
826 * mode: c++
827 * indent-tabs-mode: 1
828 * c-file-style: "bsd"
829 * End: