More fixes for ruby 1.9.
[ragel.git] / rlgen-ruby / rbx-gotocodegen.cpp
blobecb965a603a67936c0f2162eaa35cd65ee6af6d8
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) {
40 return out << "Ruby.asm \"_" << FSM_NAME() << "_" << label << ":\"";
43 ostream &RbxGotoCodeGen::rbxGoto(ostream &out, string label) {
44 return out << "Ruby.asm \"goto _" << FSM_NAME() << "_" << label << "\"";
47 /* Emit the goto to take for a given transition. */
48 std::ostream &RbxGotoCodeGen::TRANS_GOTO( RedTransAp *trans, int level )
50 out << TABS(level);
51 return rbxGoto(out, label("tr",trans->id));
54 std::ostream &RbxGotoCodeGen::TO_STATE_ACTION_SWITCH()
56 /* Walk the list of functions, printing the cases. */
57 for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
58 /* Write out referenced actions. */
59 if ( act->numToStateRefs > 0 ) {
60 /* Write the case label, the action and the case break. */
61 out << "\twhen " << act->actionId << " then\n";
62 ACTION( out, act, 0, false );
66 genLineDirective( out );
67 return out;
70 std::ostream &RbxGotoCodeGen::FROM_STATE_ACTION_SWITCH()
72 /* Walk the list of functions, printing the cases. */
73 for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
74 /* Write out referenced actions. */
75 if ( act->numFromStateRefs > 0 ) {
76 /* Write the case label, the action and the case break. */
77 out << "\twhen " << act->actionId << " then\n";
78 ACTION( out, act, 0, false );
82 genLineDirective( out );
83 return out;
86 std::ostream &RbxGotoCodeGen::EOF_ACTION_SWITCH()
88 /* Walk the list of functions, printing the cases. */
89 for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
90 /* Write out referenced actions. */
91 if ( act->numEofRefs > 0 ) {
92 /* Write the case label, the action and the case break. */
93 out << "\twhen " << act->actionId << " then\n";
94 ACTION( out, act, 0, true );
98 genLineDirective( out );
99 return out;
102 std::ostream &RbxGotoCodeGen::ACTION_SWITCH()
104 /* Walk the list of functions, printing the cases. */
105 for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
106 /* Write out referenced actions. */
107 if ( act->numTransRefs > 0 ) {
108 /* Write the case label, the action and the case break. */
109 out << "\twhen " << act->actionId << " then\n";
110 ACTION( out, act, 0, false );
114 genLineDirective( out );
115 return out;
118 void RbxGotoCodeGen::GOTO_HEADER( RedStateAp *state )
120 /* Label the state. */
121 out << "when " << state->id << " then\n";
125 void RbxGotoCodeGen::emitSingleSwitch( RedStateAp *state )
127 /* Load up the singles. */
128 int numSingles = state->outSingle.length();
129 RedTransEl *data = state->outSingle.data;
131 if ( numSingles == 1 ) {
132 /* If there is a single single key then write it out as an if. */
133 out << "\tif " << GET_WIDE_KEY(state) << " == " <<
134 KEY(data[0].lowKey) << " \n\t\t";
136 /* Virtual function for writing the target of the transition. */
137 TRANS_GOTO(data[0].value, 0) << "\n";
139 out << "end\n";
141 else if ( numSingles > 1 ) {
142 /* Write out single keys in a switch if there is more than one. */
143 out << "\tcase " << GET_WIDE_KEY(state) << "\n";
145 /* Write out the single indicies. */
146 for ( int j = 0; j < numSingles; j++ ) {
147 out << "\t\twhen " << KEY(data[j].lowKey) << " then\n";
148 TRANS_GOTO(data[j].value, 0) << "\n";
151 /* Close off the transition switch. */
152 out << "\tend\n";
156 void RbxGotoCodeGen::emitRangeBSearch( RedStateAp *state, int level, int low, int high )
158 /* Get the mid position, staying on the lower end of the range. */
159 int mid = (low + high) >> 1;
160 RedTransEl *data = state->outRange.data;
162 /* Determine if we need to look higher or lower. */
163 bool anyLower = mid > low;
164 bool anyHigher = mid < high;
166 /* Determine if the keys at mid are the limits of the alphabet. */
167 bool limitLow = data[mid].lowKey == keyOps->minKey;
168 bool limitHigh = data[mid].highKey == keyOps->maxKey;
170 if ( anyLower && anyHigher ) {
171 /* Can go lower and higher than mid. */
172 out << TABS(level) << "if " << GET_WIDE_KEY(state) << " < " <<
173 KEY(data[mid].lowKey) << " \n";
174 emitRangeBSearch( state, level+1, low, mid-1 );
175 out << TABS(level) << "elsif " << GET_WIDE_KEY(state) << " > " <<
176 KEY(data[mid].highKey) << " \n";
177 emitRangeBSearch( state, level+1, mid+1, high );
178 out << TABS(level) << "else\n";
179 TRANS_GOTO(data[mid].value, level+1) << "\n";
180 out << TABS(level) << "end\n";
182 else if ( anyLower && !anyHigher ) {
183 /* Can go lower than mid but not higher. */
184 out << TABS(level) << "if " << GET_WIDE_KEY(state) << " < " <<
185 KEY(data[mid].lowKey) << " then\n";
186 emitRangeBSearch( state, level+1, low, mid-1 );
188 /* if the higher is the highest in the alphabet then there is no
189 * sense testing it. */
190 if ( limitHigh ) {
191 out << TABS(level) << "else\n";
192 TRANS_GOTO(data[mid].value, level+1) << "\n";
194 else {
195 out << TABS(level) << "elsif" << GET_WIDE_KEY(state) << " <= " <<
196 KEY(data[mid].highKey) << " )\n";
197 TRANS_GOTO(data[mid].value, level+1) << "\n";
199 out << TABS(level) << "end\n";
201 else if ( !anyLower && anyHigher ) {
202 /* Can go higher than mid but not lower. */
203 out << TABS(level) << "if " << GET_WIDE_KEY(state) << " > " <<
204 KEY(data[mid].highKey) << " \n";
205 emitRangeBSearch( state, level+1, mid+1, high );
207 /* If the lower end is the lowest in the alphabet then there is no
208 * sense testing it. */
209 if ( limitLow ) {
210 out << TABS(level) << "else\n";
211 TRANS_GOTO(data[mid].value, level+1) << "\n";
213 else {
214 out << TABS(level) << "elsif " << GET_WIDE_KEY(state) << " >= " <<
215 KEY(data[mid].lowKey) << " then\n";
216 TRANS_GOTO(data[mid].value, level+1) << "\n";
218 out << TABS(level) << "end\n";
220 else {
221 /* Cannot go higher or lower than mid. It's mid or bust. What
222 * tests to do depends on limits of alphabet. */
223 if ( !limitLow && !limitHigh ) {
224 out << TABS(level) << "if " << KEY(data[mid].lowKey) << " <= " <<
225 GET_WIDE_KEY(state) << " && " << GET_WIDE_KEY(state) << " <= " <<
226 KEY(data[mid].highKey) << " \n";
227 TRANS_GOTO(data[mid].value, level+1) << "\n";
228 out << TABS(level) << "end\n";
230 else if ( limitLow && !limitHigh ) {
231 out << TABS(level) << "if " << GET_WIDE_KEY(state) << " <= " <<
232 KEY(data[mid].highKey) << " \n";
233 TRANS_GOTO(data[mid].value, level+1) << "\n";
234 out << TABS(level) << "end\n";
236 else if ( !limitLow && limitHigh ) {
237 out << TABS(level) << "if " << KEY(data[mid].lowKey) << " <= " <<
238 GET_WIDE_KEY(state) << " \n";
239 TRANS_GOTO(data[mid].value, level+1) << "\n";
240 out << TABS(level) << "end\n";
242 else {
243 /* Both high and low are at the limit. No tests to do. */
244 TRANS_GOTO(data[mid].value, level+1) << "\n";
249 void RbxGotoCodeGen::STATE_GOTO_ERROR()
251 /* Label the state and bail immediately. */
252 outLabelUsed = true;
253 RedStateAp *state = redFsm->errState;
254 out << "when " << state->id << " then\n";
255 rbxGoto(out << " ", "_out") << "\n";
258 void RbxGotoCodeGen::COND_TRANSLATE( StateCond *stateCond, int level )
260 CondSpace *condSpace = stateCond->condSpace;
261 out << TABS(level) << "_widec = " <<
262 KEY(condSpace->baseKey) << " + (" << GET_KEY() <<
263 " - " << KEY(keyOps->minKey) << ");\n";
265 for ( CondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
266 out << TABS(level) << "if ";
267 CONDITION( out, *csi );
268 Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize());
269 out << "\n _widec += " << condValOffset << ";\n end";
273 void RbxGotoCodeGen::emitCondBSearch( RedStateAp *state, int level, int low, int high )
275 /* Get the mid position, staying on the lower end of the range. */
276 int mid = (low + high) >> 1;
277 StateCond **data = state->stateCondVect.data;
279 /* Determine if we need to look higher or lower. */
280 bool anyLower = mid > low;
281 bool anyHigher = mid < high;
283 /* Determine if the keys at mid are the limits of the alphabet. */
284 bool limitLow = data[mid]->lowKey == keyOps->minKey;
285 bool limitHigh = data[mid]->highKey == keyOps->maxKey;
287 if ( anyLower && anyHigher ) {
288 /* Can go lower and higher than mid. */
289 out << TABS(level) << "if " << GET_KEY() << " < " <<
290 KEY(data[mid]->lowKey) << " \n";
291 emitCondBSearch( state, level+1, low, mid-1 );
292 out << TABS(level) << "elsif " << GET_KEY() << " > " <<
293 KEY(data[mid]->highKey) << " \n";
294 emitCondBSearch( state, level+1, mid+1, high );
295 out << TABS(level) << "else\n";
296 COND_TRANSLATE(data[mid], level+1);
297 out << TABS(level) << "end\n";
299 else if ( anyLower && !anyHigher ) {
300 /* Can go lower than mid but not higher. */
301 out << TABS(level) << "if " << GET_KEY() << " < " <<
302 KEY(data[mid]->lowKey) << " \n";
303 emitCondBSearch( state, level+1, low, mid-1 );
305 /* if the higher is the highest in the alphabet then there is no
306 * sense testing it. */
307 if ( limitHigh ) {
308 out << TABS(level) << "else\n";
309 COND_TRANSLATE(data[mid], level+1);
311 else {
312 out << TABS(level) << "elsif " << GET_KEY() << " <= " <<
313 KEY(data[mid]->highKey) << " then\n";
314 COND_TRANSLATE(data[mid], level+1);
316 out << TABS(level) << "end\n";
319 else if ( !anyLower && anyHigher ) {
320 /* Can go higher than mid but not lower. */
321 out << TABS(level) << "if " << GET_KEY() << " > " <<
322 KEY(data[mid]->highKey) << " \n";
323 emitCondBSearch( state, level+1, mid+1, high );
325 /* If the lower end is the lowest in the alphabet then there is no
326 * sense testing it. */
327 if ( limitLow ) {
328 out << TABS(level) << "else\n";
329 COND_TRANSLATE(data[mid], level+1);
331 else {
332 out << TABS(level) << "elsif " << GET_KEY() << " >= " <<
333 KEY(data[mid]->lowKey) << " then\n";
334 COND_TRANSLATE(data[mid], level+1);
336 out << TABS(level) << "end\n";
338 else {
339 /* Cannot go higher or lower than mid. It's mid or bust. What
340 * tests to do depends on limits of alphabet. */
341 if ( !limitLow && !limitHigh ) {
342 out << TABS(level) << "if " << KEY(data[mid]->lowKey) << " <= " <<
343 GET_KEY() << " && " << GET_KEY() << " <= " <<
344 KEY(data[mid]->highKey) << " then\n";
345 COND_TRANSLATE(data[mid], level+1);
346 out << TABS(level) << "end\n";
348 else if ( limitLow && !limitHigh ) {
349 out << TABS(level) << "if " << GET_KEY() << " <= " <<
350 KEY(data[mid]->highKey) << " then\n";
351 COND_TRANSLATE(data[mid], level+1);
352 out << TABS(level) << "end\n";
354 else if ( !limitLow && limitHigh ) {
355 out << TABS(level) << "if " << KEY(data[mid]->lowKey) << " <= " <<
356 GET_KEY() << " then\n";
357 COND_TRANSLATE(data[mid], level+1);
358 out << TABS(level) << "end\n";
360 else {
361 /* Both high and low are at the limit. No tests to do. */
362 COND_TRANSLATE(data[mid], level);
367 std::ostream &RbxGotoCodeGen::STATE_GOTOS()
369 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
370 if ( st == redFsm->errState )
371 STATE_GOTO_ERROR();
372 else {
373 /* Writing code above state gotos. */
374 GOTO_HEADER( st );
376 if ( st->stateCondVect.length() > 0 ) {
377 out << " _widec = " << GET_KEY() << ";\n";
378 emitCondBSearch( st, 1, 0, st->stateCondVect.length() - 1 );
381 /* Try singles. */
382 if ( st->outSingle.length() > 0 )
383 emitSingleSwitch( st );
385 /* Default case is to binary search for the ranges, if that fails then */
386 if ( st->outRange.length() > 0 )
387 emitRangeBSearch( st, 1, 0, st->outRange.length() - 1 );
389 /* Write the default transition. */
390 TRANS_GOTO( st->defTrans, 1 ) << "\n";
393 return out;
396 std::ostream &RbxGotoCodeGen::TRANSITIONS()
398 /* Emit any transitions that have functions and that go to
399 * this state. */
400 for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) {
401 /* Write the label for the transition so it can be jumped to. */
402 rbxLabel(out << " ", label("tr", trans->id)) << "\n";
404 /* Destination state. */
405 if ( trans->action != 0 && trans->action->anyCurStateRef() )
406 out << "_ps = " << CS() << "'n";
407 out << CS() << " = " << trans->targ->id << "\n";
409 if ( trans->action != 0 ) {
410 /* Write out the transition func. */
411 rbxGoto(out, label("f", trans->action->actListId)) << "\n";
413 else {
414 /* No code to execute, just loop around. */
415 rbxGoto(out, "_again") << "\n";
418 return out;
421 std::ostream &RbxGotoCodeGen::EXEC_FUNCS()
423 /* Make labels that set acts and jump to execFuncs. Loop func indicies. */
424 for ( ActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
425 if ( redAct->numTransRefs > 0 ) {
426 rbxLabel(out, label("f", redAct->actListId)) << "\n" <<
427 "_acts = " << itoa( redAct->location+1 ) << "\n";
428 rbxGoto(out, "execFuncs") << "\n";
432 rbxLabel(out, "execFuncs") <<
433 "\n"
434 " _nacts = " << A() << "[_acts]\n"
435 " _acts += 1\n"
436 " while ( _nacts > 0 ) \n"
437 " _nacts -= 1\n"
438 " _acts += 1\n"
439 " case ( "<< A() << "[_acts-1] ) \n";
440 ACTION_SWITCH();
441 out <<
442 " end\n"
443 " end \n";
444 rbxGoto(out, "_again");
445 return out;
448 int RbxGotoCodeGen::TO_STATE_ACTION( RedStateAp *state )
450 int act = 0;
451 if ( state->toStateAction != 0 )
452 act = state->toStateAction->location+1;
453 return act;
456 int RbxGotoCodeGen::FROM_STATE_ACTION( RedStateAp *state )
458 int act = 0;
459 if ( state->fromStateAction != 0 )
460 act = state->fromStateAction->location+1;
461 return act;
464 int RbxGotoCodeGen::EOF_ACTION( RedStateAp *state )
466 int act = 0;
467 if ( state->eofAction != 0 )
468 act = state->eofAction->location+1;
469 return act;
472 std::ostream &RbxGotoCodeGen::TO_STATE_ACTIONS()
474 /* Take one off for the psuedo start state. */
475 int numStates = redFsm->stateList.length();
476 unsigned int *vals = new unsigned int[numStates];
477 memset( vals, 0, sizeof(unsigned int)*numStates );
479 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
480 vals[st->id] = TO_STATE_ACTION(st);
482 out << "\t";
483 for ( int st = 0; st < redFsm->nextStateId; st++ ) {
484 /* Write any eof action. */
485 out << vals[st];
486 if ( st < numStates-1 ) {
487 out << ", ";
488 if ( (st+1) % IALL == 0 )
489 out << "\n\t";
492 out << "\n";
493 delete[] vals;
494 return out;
497 std::ostream &RbxGotoCodeGen::FROM_STATE_ACTIONS()
499 /* Take one off for the psuedo start state. */
500 int numStates = redFsm->stateList.length();
501 unsigned int *vals = new unsigned int[numStates];
502 memset( vals, 0, sizeof(unsigned int)*numStates );
504 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
505 vals[st->id] = FROM_STATE_ACTION(st);
507 out << "\t";
508 for ( int st = 0; st < redFsm->nextStateId; st++ ) {
509 /* Write any eof action. */
510 out << vals[st];
511 if ( st < numStates-1 ) {
512 out << ", ";
513 if ( (st+1) % IALL == 0 )
514 out << "\n\t";
517 out << "\n";
518 delete[] vals;
519 return out;
522 std::ostream &RbxGotoCodeGen::EOF_ACTIONS()
524 /* Take one off for the psuedo start state. */
525 int numStates = redFsm->stateList.length();
526 unsigned int *vals = new unsigned int[numStates];
527 memset( vals, 0, sizeof(unsigned int)*numStates );
529 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
530 vals[st->id] = EOF_ACTION(st);
532 out << "\t";
533 for ( int st = 0; st < redFsm->nextStateId; st++ ) {
534 /* Write any eof action. */
535 out << vals[st];
536 if ( st < numStates-1 ) {
537 out << ", ";
538 if ( (st+1) % IALL == 0 )
539 out << "\n\t";
542 out << "\n";
543 delete[] vals;
544 return out;
547 std::ostream &RbxGotoCodeGen::FINISH_CASES()
549 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
550 /* States that are final and have an out action need a case. */
551 if ( st->eofAction != 0 ) {
552 /* Write the case label. */
553 out << "\t\twhen " << st->id << " then\n";
555 /* Write the goto func. */
556 rbxGoto(out, label("f", st->eofAction->actListId)) << "\n";
560 return out;
563 void RbxGotoCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
565 ret << "begin\n" << CS() << " = " << gotoDest << " ";
566 rbxGoto(ret, "_again") <<
567 "\nend\n";
570 void RbxGotoCodeGen::GOTO_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish )
572 ret << "begin\n" << CS() << " = (";
573 INLINE_LIST( ret, ilItem->children, 0, inFinish );
574 ret << ")";
575 rbxGoto(ret, "_again") <<
576 "\nend\n";
579 void RbxGotoCodeGen::CURS( ostream &ret, bool inFinish )
581 ret << "(_ps)";
584 void RbxGotoCodeGen::TARGS( ostream &ret, bool inFinish, int targState )
586 ret << "(" << CS() << ")";
589 void RbxGotoCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
591 ret << CS() << " = " << nextDest << ";";
594 void RbxGotoCodeGen::NEXT_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish )
596 ret << CS() << " = (";
597 INLINE_LIST( ret, ilItem->children, 0, inFinish );
598 ret << ");";
601 void RbxGotoCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
603 if ( prePushExpr != 0 ) {
604 ret << "{";
605 INLINE_LIST( ret, prePushExpr, 0, false );
608 ret << "begin\n"
609 << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = " <<
610 callDest << "; ";
611 rbxGoto(ret, "_again") <<
612 "\nend\n";
614 if ( prePushExpr != 0 )
615 ret << "}";
618 void RbxGotoCodeGen::CALL_EXPR( ostream &ret, InlineItem *ilItem, int targState, bool inFinish )
620 if ( prePushExpr != 0 ) {
621 ret << "{";
622 INLINE_LIST( ret, prePushExpr, 0, false );
625 ret << "begin\n" << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = (";
626 INLINE_LIST( ret, ilItem->children, targState, inFinish );
627 ret << "); ";
628 rbxGoto(ret, "_again") <<
629 "\nend\n";
631 if ( prePushExpr != 0 )
632 ret << "}";
635 void RbxGotoCodeGen::RET( ostream &ret, bool inFinish )
637 ret << "begin\n" << CS() << " = " << STACK() << "[--" << TOP() << "]; " ;
639 if ( postPopExpr != 0 ) {
640 ret << "{";
641 INLINE_LIST( ret, postPopExpr, 0, false );
642 ret << "}";
645 rbxGoto(ret, "_again") <<
646 "\nend\n";
649 void RbxGotoCodeGen::BREAK( ostream &ret, int targState )
651 outLabelUsed = true;
652 rbxGoto(ret, "_out") << "\n";
655 void RbxGotoCodeGen::writeData()
657 if ( redFsm->anyActions() ) {
658 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
659 ACTIONS_ARRAY();
660 CLOSE_ARRAY() <<
661 "\n";
664 if ( redFsm->anyToStateActions() ) {
665 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
666 TO_STATE_ACTIONS();
667 CLOSE_ARRAY() <<
668 "\n";
671 if ( redFsm->anyFromStateActions() ) {
672 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
673 FROM_STATE_ACTIONS();
674 CLOSE_ARRAY() <<
675 "\n";
678 if ( redFsm->anyEofActions() ) {
679 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
680 EOF_ACTIONS();
681 CLOSE_ARRAY() <<
682 "\n";
685 STATE_IDS();
688 void RbxGotoCodeGen::writeExec()
690 outLabelUsed = false;
692 out << " begin\n";
694 if ( redFsm->anyRegCurStateRef() )
695 out << " _ps = 0;\n";
697 if ( redFsm->anyToStateActions() || redFsm->anyRegActions()
698 || redFsm->anyFromStateActions() )
700 out << " _acts, _nacts = nil\n";
703 if ( redFsm->anyConditions() )
704 out << " _widec = nil\n";
706 out << "\n";
708 if ( hasEnd ) {
709 outLabelUsed = true;
710 out <<
711 " if ( " << P() << " == " << PE() << " )\n";
712 rbxGoto(out << " ", "_out") << "\n" <<
713 " end\n";
716 if ( redFsm->errState != 0 ) {
717 outLabelUsed = true;
718 out <<
719 " if ( " << CS() << " == " << redFsm->errState->id << " )\n";
720 rbxGoto(out << " ", "_out") << "\n" <<
721 " end\n";
724 rbxLabel(out, "_resume") << "\n";
726 if ( redFsm->anyFromStateActions() ) {
727 out <<
729 " _acts = " << ARR_OFF( A(), FSA() + "[" + CS() + "]" ) << ";\n"
730 " _nacts = " << " *_acts++;\n"
731 " while ( _nacts-- > 0 ) {\n"
732 " switch ( *_acts++ ) {\n";
733 FROM_STATE_ACTION_SWITCH();
734 out <<
735 " }\n"
736 " }\n"
737 "\n";
740 out <<
741 " case ( " << CS() << " )\n";
742 STATE_GOTOS();
743 out <<
744 " end # case\n"
745 "\n";
746 TRANSITIONS() <<
747 "\n";
749 if ( redFsm->anyRegActions() )
750 EXEC_FUNCS() << "\n";
753 rbxLabel(out, "_again") << "\n";
755 if ( redFsm->anyToStateActions() ) {
756 out <<
757 " _acts = " << ARR_OFF( A(), TSA() + "[" + CS() + "]" ) << ";\n"
758 " _nacts = " << " *_acts++;\n"
759 " while ( _nacts-- > 0 ) {\n"
760 " switch ( *_acts++ ) {\n";
761 TO_STATE_ACTION_SWITCH();
762 out <<
763 " }\n"
764 " }\n"
765 "\n";
768 if ( redFsm->errState != 0 ) {
769 outLabelUsed = true;
770 out <<
771 " if ( " << CS() << " == " << redFsm->errState->id << " )\n";
772 rbxGoto(out << " ", "_out") << "\n" <<
773 " end" << "\n";
776 if ( hasEnd ) {
777 out << " " << P() << " += 1\n"
778 " if ( " << P() << " != " << PE() << " )\n";
779 rbxGoto(out << " ", "_resume") << "\n" <<
780 " end" << "\n";
782 else {
783 out <<
784 " " << P() << " += 1;\n";
785 rbxGoto(out << " ", "_resume") << "\n";
788 if ( outLabelUsed )
789 rbxLabel(out, "_out") << "\n";
791 out << " end\n";
794 void RbxGotoCodeGen::writeEOF()
796 if ( redFsm->anyEofActions() ) {
797 out <<
798 " {\n"
799 " _acts = " <<
800 ARR_OFF( A(), EA() + "[" + CS() + "]" ) << ";\n"
801 " " << " _nacts = " << " *_acts++;\n"
802 " while ( _nacts-- > 0 ) {\n"
803 " switch ( *_acts++ ) {\n";
804 EOF_ACTION_SWITCH();
805 out <<
806 " }\n"
807 " }\n"
808 " }\n"
809 "\n";
814 * Local Variables:
815 * mode: c++
816 * indent-tabs-mode: 1
817 * c-file-style: "bsd"
818 * End: