Patch from Victor Hugo Borja <vic@rubyforge.org>
[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 << "\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 << "\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 << "\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 << "\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 << "\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) << "\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 << "\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 << "\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         ret << "begin\n" 
604             << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = " << 
605                 callDest << "; ";
606         rbxGoto(ret, "_again") << 
607                 "\nend\n";
608 }
609
610 void RbxGotoCodeGen::CALL_EXPR( ostream &ret, InlineItem *ilItem, int targState, bool inFinish )
611 {
612         ret << "begin\n" << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = (";
613         INLINE_LIST( ret, ilItem->children, targState, inFinish );
614         ret << "); ";
615         rbxGoto(ret, "_again") << 
616                 "\nend\n";
617 }
618
619 void RbxGotoCodeGen::RET( ostream &ret, bool inFinish )
620 {
621         ret << "begin\n" << CS() << " = " << STACK() << "[--" << TOP() << "]; " ;
622         rbxGoto(ret, "_again") << 
623                 "\nend\n";
624 }
625
626 void RbxGotoCodeGen::BREAK( ostream &ret, int targState )
627 {
628         outLabelUsed = true;
629         rbxGoto(ret, "_out") << "\n";
630 }
631
632 void RbxGotoCodeGen::writeData()
633 {
634         if ( redFsm->anyActions() ) {
635                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
636                 ACTIONS_ARRAY();
637                 CLOSE_ARRAY() <<
638                         "\n";
639         }
640
641         if ( redFsm->anyToStateActions() ) {
642                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
643                 TO_STATE_ACTIONS();
644                 CLOSE_ARRAY() <<
645                         "\n";
646         }
647
648         if ( redFsm->anyFromStateActions() ) {
649                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
650                 FROM_STATE_ACTIONS();
651                 CLOSE_ARRAY() <<
652                         "\n";
653         }
654
655         if ( redFsm->anyEofActions() ) {
656                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
657                 EOF_ACTIONS();
658                 CLOSE_ARRAY() <<
659                         "\n";
660         }
661
662         STATE_IDS();
663 }
664
665 void RbxGotoCodeGen::writeExec()
666 {
667         outLabelUsed = false;
668
669         out << "        begin\n";
670
671         if ( redFsm->anyRegCurStateRef() )
672                 out << "        _ps = 0;\n";
673
674         if ( redFsm->anyToStateActions() || redFsm->anyRegActions() 
675              || redFsm->anyFromStateActions() )
676         {
677                 out <<  " _acts, _nacts = nil\n";
678         }
679
680         if ( redFsm->anyConditions() )
681                 out << "        _widec = nil\n";
682
683         out << "\n";
684
685         if ( hasEnd ) {
686                 outLabelUsed = true;
687                 out << 
688                         "       if ( " << P() << " == " << PE() << " )\n";
689                 rbxGoto(out << "                ", "_out") << "\n" <<
690                         "       end\n";
691         }
692
693         if ( redFsm->errState != 0 ) {
694                 outLabelUsed = true;
695                 out << 
696                         "       if ( " << CS() << " == " << redFsm->errState->id << " )\n";
697                 rbxGoto(out << "                ", "_out") << "\n" <<
698                         "       end\n";
699         }
700
701         rbxLabel(out, "_resume") << "\n";
702
703         if ( redFsm->anyFromStateActions() ) {
704                 out <<
705
706                         "       _acts = " << ARR_OFF( A(), FSA() + "[" + CS() + "]" ) << ";\n"
707                         "       _nacts = " << " *_acts++;\n"
708                         "       while ( _nacts-- > 0 ) {\n"
709                         "               switch ( *_acts++ ) {\n";
710                 FROM_STATE_ACTION_SWITCH();
711                 out <<
712                         "               }\n"
713                         "       }\n"
714                         "\n";
715         }
716
717         out <<
718                 "       case ( " << CS() << " )\n";
719         STATE_GOTOS();
720         out <<
721                 "       end # case\n"
722                 "\n";
723         TRANSITIONS() <<
724                 "\n";
725
726         if ( redFsm->anyRegActions() )
727                 EXEC_FUNCS() << "\n";
728
729
730         rbxLabel(out, "_again") << "\n";
731
732         if ( redFsm->anyToStateActions() ) {
733                 out <<
734                         "       _acts = " << ARR_OFF( A(), TSA() + "[" + CS() + "]" ) << ";\n"
735                         "       _nacts = " << " *_acts++;\n"
736                         "       while ( _nacts-- > 0 ) {\n"
737                         "               switch ( *_acts++ ) {\n";
738                 TO_STATE_ACTION_SWITCH();
739                 out <<
740                         "               }\n"
741                         "       }\n"
742                         "\n";
743         }
744
745         if ( redFsm->errState != 0 ) {
746                 outLabelUsed = true;
747                 out << 
748                         "       if ( " << CS() << " == " << redFsm->errState->id << " )\n";
749                 rbxGoto(out << "                ", "_out") << "\n" <<
750                         "       end" << "\n";
751         }
752
753         if ( hasEnd ) {
754                 out <<  "       "  << P() << " += 1\n"
755                         "       if ( " << P() << " != " << PE() << " )\n";
756                 rbxGoto(out << "                ", "_resume") << "\n" <<
757                         "       end" << "\n";
758         }
759         else {
760                 out << 
761                         "       " << P() << " += 1;\n";
762                 rbxGoto(out << "        ", "_resume") << "\n";
763         }
764
765         if ( outLabelUsed )
766                 rbxLabel(out, "_out") << "\n";
767
768         out << "        end\n";
769 }
770
771 void RbxGotoCodeGen::writeEOF()
772 {
773         if ( redFsm->anyEofActions() ) {
774                 out << 
775                         "       {\n"
776                         "        _acts = " << 
777                         ARR_OFF( A(), EA() + "[" + CS() + "]" ) << ";\n"
778                         "       " << " _nacts = " << " *_acts++;\n"
779                         "       while ( _nacts-- > 0 ) {\n"
780                         "               switch ( *_acts++ ) {\n";
781                 EOF_ACTION_SWITCH();
782                 out <<
783                         "               }\n"
784                         "       }\n"
785                         "       }\n"
786                         "\n";
787         }
788 }
789
790 /*
791  * Local Variables:
792  * mode: c++
793  * indent-tabs-mode: 1
794  * c-file-style: "bsd"
795  * End:
796  */