More fixes for ruby 1.9.
[external/ragel.git] / rlgen-ruby / rbx-gotocodegen.cpp
1 /*
2  *  Copyright 2007 Victor Hugo Borja <vic@rubyforge.org>
3  *            2006-2007 Adrian Thurston <thurston@cs.queensu.ca>
4  */
5
6 /*  This file is part of Ragel.
7  *
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.
12  * 
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.
17  * 
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 
21  */
22
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"
30
31 using std::ostream;
32 using std::string;
33
34 inline string label(string a, int i)
35 {
36         return a + itoa(i);
37 }
38
39 ostream &RbxGotoCodeGen::rbxLabel(ostream &out, string label) {
40         return out << "Ruby.asm \"_" << FSM_NAME() << "_" << label << ":\"";
41 }
42
43 ostream &RbxGotoCodeGen::rbxGoto(ostream &out, string label) {
44         return out << "Ruby.asm \"goto _" << FSM_NAME() << "_" << label << "\"";
45 }
46
47 /* Emit the goto to take for a given transition. */
48 std::ostream &RbxGotoCodeGen::TRANS_GOTO( RedTransAp *trans, int level )
49 {
50         out << TABS(level);
51         return rbxGoto(out, label("tr",trans->id));
52 }
53
54 std::ostream &RbxGotoCodeGen::TO_STATE_ACTION_SWITCH()
55 {
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 );
63                 }
64         }
65
66         genLineDirective( out );
67         return out;
68 }
69
70 std::ostream &RbxGotoCodeGen::FROM_STATE_ACTION_SWITCH()
71 {
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 );
79                 }
80         }
81
82         genLineDirective( out );
83         return out;
84 }
85
86 std::ostream &RbxGotoCodeGen::EOF_ACTION_SWITCH()
87 {
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 );
95                 }
96         }
97
98         genLineDirective( out );
99         return out;
100 }
101
102 std::ostream &RbxGotoCodeGen::ACTION_SWITCH()
103 {
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 );
111                 }
112         }
113
114         genLineDirective( out );
115         return out;
116 }
117
118 void RbxGotoCodeGen::GOTO_HEADER( RedStateAp *state )
119 {
120         /* Label the state. */
121         out << "when " << state->id << " then\n";
122 }
123
124
125 void RbxGotoCodeGen::emitSingleSwitch( RedStateAp *state )
126 {
127         /* Load up the singles. */
128         int numSingles = state->outSingle.length();
129         RedTransEl *data = state->outSingle.data;
130
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"; 
135
136                 /* Virtual function for writing the target of the transition. */
137                 TRANS_GOTO(data[0].value, 0) << "\n";
138
139                 out << "end\n";
140         }
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";
144
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";
149                 }
150                 
151                 /* Close off the transition switch. */
152                 out << "\tend\n";
153         }
154 }
155
156 void RbxGotoCodeGen::emitRangeBSearch( RedStateAp *state, int level, int low, int high )
157 {
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;
161
162         /* Determine if we need to look higher or lower. */
163         bool anyLower = mid > low;
164         bool anyHigher = mid < high;
165
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;
169
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";
181         }
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 );
187
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";
193                 }
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";
198                 }
199                 out << TABS(level) << "end\n";
200         }
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 );
206
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";
212                 }
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";
217                 }
218                 out << TABS(level) << "end\n";
219         }
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";
229                 }
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";
235                 }
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";
241                 }
242                 else {
243                         /* Both high and low are at the limit. No tests to do. */
244                         TRANS_GOTO(data[mid].value, level+1) << "\n";
245                 }
246         }
247 }
248
249 void RbxGotoCodeGen::STATE_GOTO_ERROR()
250 {
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";
256 }
257
258 void RbxGotoCodeGen::COND_TRANSLATE( StateCond *stateCond, int level )
259 {
260         CondSpace *condSpace = stateCond->condSpace;
261         out << TABS(level) << "_widec = " <<
262                 KEY(condSpace->baseKey) << " + (" << GET_KEY() << 
263                 " - " << KEY(keyOps->minKey) << ");\n";
264
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";
270         }
271 }
272
273 void RbxGotoCodeGen::emitCondBSearch( RedStateAp *state, int level, int low, int high )
274 {
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;
278
279         /* Determine if we need to look higher or lower. */
280         bool anyLower = mid > low;
281         bool anyHigher = mid < high;
282
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;
286
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";
298         }
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 );
304
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);
310                 }
311                 else {
312                         out << TABS(level) << "elsif " << GET_KEY() << " <= " << 
313                                 KEY(data[mid]->highKey) << " then\n";
314                         COND_TRANSLATE(data[mid], level+1);
315                 }
316                 out << TABS(level) << "end\n";
317
318         }
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 );
324
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);
330                 }
331                 else {
332                         out << TABS(level) << "elsif " << GET_KEY() << " >= " << 
333                                 KEY(data[mid]->lowKey) << " then\n";
334                         COND_TRANSLATE(data[mid], level+1);
335                 }
336                 out << TABS(level) << "end\n";
337         }
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";
347                 }
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";
353                 }
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";
359                 }
360                 else {
361                         /* Both high and low are at the limit. No tests to do. */
362                         COND_TRANSLATE(data[mid], level);
363                 }
364         }
365 }
366
367 std::ostream &RbxGotoCodeGen::STATE_GOTOS()
368 {
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 );
375
376                         if ( st->stateCondVect.length() > 0 ) {
377                                 out << "        _widec = " << GET_KEY() << ";\n";
378                                 emitCondBSearch( st, 1, 0, st->stateCondVect.length() - 1 );
379                         }
380
381                         /* Try singles. */
382                         if ( st->outSingle.length() > 0 )
383                                 emitSingleSwitch( st );
384
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 );
388
389                         /* Write the default transition. */
390                         TRANS_GOTO( st->defTrans, 1 ) << "\n";
391                 }
392         }
393         return out;
394 }
395
396 std::ostream &RbxGotoCodeGen::TRANSITIONS()
397 {
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";
403
404                 /* Destination state. */
405                 if ( trans->action != 0 && trans->action->anyCurStateRef() )
406                         out << "_ps = " << CS() << "'n";
407                 out << CS() << " = " << trans->targ->id << "\n";
408
409                 if ( trans->action != 0 ) {
410                         /* Write out the transition func. */
411                         rbxGoto(out, label("f", trans->action->actListId)) << "\n";
412                 }
413                 else {
414                         /* No code to execute, just loop around. */
415                         rbxGoto(out, "_again") << "\n";
416                 }
417         }
418         return out;
419 }
420
421 std::ostream &RbxGotoCodeGen::EXEC_FUNCS()
422 {
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";
429                 }
430         }
431
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;
446 }
447
448 int RbxGotoCodeGen::TO_STATE_ACTION( RedStateAp *state )
449 {
450         int act = 0;
451         if ( state->toStateAction != 0 )
452                 act = state->toStateAction->location+1;
453         return act;
454 }
455
456 int RbxGotoCodeGen::FROM_STATE_ACTION( RedStateAp *state )
457 {
458         int act = 0;
459         if ( state->fromStateAction != 0 )
460                 act = state->fromStateAction->location+1;
461         return act;
462 }
463
464 int RbxGotoCodeGen::EOF_ACTION( RedStateAp *state )
465 {
466         int act = 0;
467         if ( state->eofAction != 0 )
468                 act = state->eofAction->location+1;
469         return act;
470 }
471
472 std::ostream &RbxGotoCodeGen::TO_STATE_ACTIONS()
473 {
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 );
478
479         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
480                 vals[st->id] = TO_STATE_ACTION(st);
481
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";
490                 }
491         }
492         out << "\n";
493         delete[] vals;
494         return out;
495 }
496
497 std::ostream &RbxGotoCodeGen::FROM_STATE_ACTIONS()
498 {
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 );
503
504         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
505                 vals[st->id] = FROM_STATE_ACTION(st);
506
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";
515                 }
516         }
517         out << "\n";
518         delete[] vals;
519         return out;
520 }
521
522 std::ostream &RbxGotoCodeGen::EOF_ACTIONS()
523 {
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 );
528
529         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
530                 vals[st->id] = EOF_ACTION(st);
531
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";
540                 }
541         }
542         out << "\n";
543         delete[] vals;
544         return out;
545 }
546
547 std::ostream &RbxGotoCodeGen::FINISH_CASES()
548 {
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";
554
555                         /* Write the goto func. */
556                         rbxGoto(out, label("f", st->eofAction->actListId)) << "\n";
557                 }
558         }
559         
560         return out;
561 }
562
563 void RbxGotoCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
564 {
565         ret << "begin\n" << CS() << " = " << gotoDest << " ";
566         rbxGoto(ret, "_again") << 
567                 "\nend\n";
568 }
569
570 void RbxGotoCodeGen::GOTO_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish )
571 {
572         ret << "begin\n" << CS() << " = (";
573         INLINE_LIST( ret, ilItem->children, 0, inFinish );
574         ret << ")";
575         rbxGoto(ret, "_again") << 
576                 "\nend\n";
577 }
578
579 void RbxGotoCodeGen::CURS( ostream &ret, bool inFinish )
580 {
581         ret << "(_ps)";
582 }
583
584 void RbxGotoCodeGen::TARGS( ostream &ret, bool inFinish, int targState )
585 {
586         ret << "(" << CS() << ")";
587 }
588
589 void RbxGotoCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
590 {
591         ret << CS() << " = " << nextDest << ";";
592 }
593
594 void RbxGotoCodeGen::NEXT_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish )
595 {
596         ret << CS() << " = (";
597         INLINE_LIST( ret, ilItem->children, 0, inFinish );
598         ret << ");";
599 }
600
601 void RbxGotoCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
602 {
603         if ( prePushExpr != 0 ) {
604                 ret << "{";
605                 INLINE_LIST( ret, prePushExpr, 0, false );
606         }
607
608         ret << "begin\n" 
609             << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = " << 
610                 callDest << "; ";
611         rbxGoto(ret, "_again") << 
612                 "\nend\n";
613
614         if ( prePushExpr != 0 )
615                 ret << "}";
616 }
617
618 void RbxGotoCodeGen::CALL_EXPR( ostream &ret, InlineItem *ilItem, int targState, bool inFinish )
619 {
620         if ( prePushExpr != 0 ) {
621                 ret << "{";
622                 INLINE_LIST( ret, prePushExpr, 0, false );
623         }
624
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";
630
631         if ( prePushExpr != 0 )
632                 ret << "}";
633 }
634
635 void RbxGotoCodeGen::RET( ostream &ret, bool inFinish )
636 {
637         ret << "begin\n" << CS() << " = " << STACK() << "[--" << TOP() << "]; " ;
638
639         if ( postPopExpr != 0 ) {
640                 ret << "{";
641                 INLINE_LIST( ret, postPopExpr, 0, false );
642                 ret << "}";
643         }
644
645         rbxGoto(ret, "_again") << 
646                 "\nend\n";
647 }
648
649 void RbxGotoCodeGen::BREAK( ostream &ret, int targState )
650 {
651         outLabelUsed = true;
652         rbxGoto(ret, "_out") << "\n";
653 }
654
655 void RbxGotoCodeGen::writeData()
656 {
657         if ( redFsm->anyActions() ) {
658                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
659                 ACTIONS_ARRAY();
660                 CLOSE_ARRAY() <<
661                         "\n";
662         }
663
664         if ( redFsm->anyToStateActions() ) {
665                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
666                 TO_STATE_ACTIONS();
667                 CLOSE_ARRAY() <<
668                         "\n";
669         }
670
671         if ( redFsm->anyFromStateActions() ) {
672                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
673                 FROM_STATE_ACTIONS();
674                 CLOSE_ARRAY() <<
675                         "\n";
676         }
677
678         if ( redFsm->anyEofActions() ) {
679                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
680                 EOF_ACTIONS();
681                 CLOSE_ARRAY() <<
682                         "\n";
683         }
684
685         STATE_IDS();
686 }
687
688 void RbxGotoCodeGen::writeExec()
689 {
690         outLabelUsed = false;
691
692         out << "        begin\n";
693
694         if ( redFsm->anyRegCurStateRef() )
695                 out << "        _ps = 0;\n";
696
697         if ( redFsm->anyToStateActions() || redFsm->anyRegActions() 
698              || redFsm->anyFromStateActions() )
699         {
700                 out <<  " _acts, _nacts = nil\n";
701         }
702
703         if ( redFsm->anyConditions() )
704                 out << "        _widec = nil\n";
705
706         out << "\n";
707
708         if ( hasEnd ) {
709                 outLabelUsed = true;
710                 out << 
711                         "       if ( " << P() << " == " << PE() << " )\n";
712                 rbxGoto(out << "                ", "_out") << "\n" <<
713                         "       end\n";
714         }
715
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";
722         }
723
724         rbxLabel(out, "_resume") << "\n";
725
726         if ( redFsm->anyFromStateActions() ) {
727                 out <<
728
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";
738         }
739
740         out <<
741                 "       case ( " << CS() << " )\n";
742         STATE_GOTOS();
743         out <<
744                 "       end # case\n"
745                 "\n";
746         TRANSITIONS() <<
747                 "\n";
748
749         if ( redFsm->anyRegActions() )
750                 EXEC_FUNCS() << "\n";
751
752
753         rbxLabel(out, "_again") << "\n";
754
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";
766         }
767
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";
774         }
775
776         if ( hasEnd ) {
777                 out <<  "       "  << P() << " += 1\n"
778                         "       if ( " << P() << " != " << PE() << " )\n";
779                 rbxGoto(out << "                ", "_resume") << "\n" <<
780                         "       end" << "\n";
781         }
782         else {
783                 out << 
784                         "       " << P() << " += 1;\n";
785                 rbxGoto(out << "        ", "_resume") << "\n";
786         }
787
788         if ( outLabelUsed )
789                 rbxLabel(out, "_out") << "\n";
790
791         out << "        end\n";
792 }
793
794 void RbxGotoCodeGen::writeEOF()
795 {
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";
810         }
811 }
812
813 /*
814  * Local Variables:
815  * mode: c++
816  * indent-tabs-mode: 1
817  * c-file-style: "bsd"
818  * End:
819  */