tizen 2.3.1 release
[external/ragel.git] / ragel / rbxgoto.cpp
1 /*
2  *  Copyright 2007 Victor Hugo Borja <vic@rubyforge.org>
3  *            2006-2007 Adrian Thurston <thurston@complang.org>
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
26 #include "rbxgoto.h"
27 #include "ragel.h"
28 #include "redfsm.h"
29 #include "bstmap.h"
30 #include "gendata.h"
31
32 using std::ostream;
33 using std::string;
34
35 inline string label(string a, int i)
36 {
37         return a + itoa(i);
38 }
39
40 ostream &RbxGotoCodeGen::rbxLabel(ostream &out, string label)
41 {
42         out << "Rubinius.asm { @labels[:_" << FSM_NAME() << "_" << label << "].set! }\n";
43         return out;
44 }
45
46 ostream &RbxGotoCodeGen::rbxGoto(ostream &out, string label)
47 {
48         out << "Rubinius.asm { goto @labels[:_" << FSM_NAME() << "_" << label << "] }\n";
49         return out;
50 }
51
52 /* Emit the goto to take for a given transition. */
53 std::ostream &RbxGotoCodeGen::TRANS_GOTO( RedTransAp *trans, int level )
54 {
55         out << TABS(level);
56         return rbxGoto(out, label("tr",trans->id));
57 }
58
59 std::ostream &RbxGotoCodeGen::TO_STATE_ACTION_SWITCH()
60 {
61         /* Walk the list of functions, printing the cases. */
62         for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
63                 /* Write out referenced actions. */
64                 if ( act->numToStateRefs > 0 ) {
65                         /* Write the case label, the action and the case break. */
66                         out << "\twhen " << act->actionId << " then\n";
67                         ACTION( out, act, 0, false );
68                 }
69         }
70
71         genLineDirective( out );
72         return out;
73 }
74
75 std::ostream &RbxGotoCodeGen::FROM_STATE_ACTION_SWITCH()
76 {
77         /* Walk the list of functions, printing the cases. */
78         for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
79                 /* Write out referenced actions. */
80                 if ( act->numFromStateRefs > 0 ) {
81                         /* Write the case label, the action and the case break. */
82                         out << "\twhen " << act->actionId << " then\n";
83                         ACTION( out, act, 0, false );
84                 }
85         }
86
87         genLineDirective( out );
88         return out;
89 }
90
91 std::ostream &RbxGotoCodeGen::EOF_ACTION_SWITCH()
92 {
93         /* Walk the list of functions, printing the cases. */
94         for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
95                 /* Write out referenced actions. */
96                 if ( act->numEofRefs > 0 ) {
97                         /* Write the case label, the action and the case break. */
98                         out << "\twhen " << act->actionId << " then\n";
99                         ACTION( out, act, 0, true );
100                 }
101         }
102
103         genLineDirective( out );
104         return out;
105 }
106
107 std::ostream &RbxGotoCodeGen::ACTION_SWITCH()
108 {
109         /* Walk the list of functions, printing the cases. */
110         for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
111                 /* Write out referenced actions. */
112                 if ( act->numTransRefs > 0 ) {
113                         /* Write the case label, the action and the case break. */
114                         out << "\twhen " << act->actionId << " then\n";
115                         ACTION( out, act, 0, false );
116                 }
117         }
118
119         genLineDirective( out );
120         return out;
121 }
122
123 void RbxGotoCodeGen::GOTO_HEADER( RedStateAp *state )
124 {
125         /* Label the state. */
126         out << "when " << state->id << " then\n";
127 }
128
129
130 void RbxGotoCodeGen::emitSingleSwitch( RedStateAp *state )
131 {
132         /* Load up the singles. */
133         int numSingles = state->outSingle.length();
134         RedTransEl *data = state->outSingle.data;
135
136         if ( numSingles == 1 ) {
137                 /* If there is a single single key then write it out as an if. */
138                 out << "\tif " << GET_WIDE_KEY(state) << " == " << 
139                         KEY(data[0].lowKey) << " \n\t\t"; 
140
141                 /* Virtual function for writing the target of the transition. */
142                 TRANS_GOTO(data[0].value, 0) << "\n";
143
144                 out << "end\n";
145         }
146         else if ( numSingles > 1 ) {
147                 /* Write out single keys in a switch if there is more than one. */
148                 out << "\tcase  " << GET_WIDE_KEY(state) << "\n";
149
150                 /* Write out the single indicies. */
151                 for ( int j = 0; j < numSingles; j++ ) {
152                         out << "\t\twhen " << KEY(data[j].lowKey) << " then\n";
153                         TRANS_GOTO(data[j].value, 0) << "\n";
154                 }
155                 
156                 /* Close off the transition switch. */
157                 out << "\tend\n";
158         }
159 }
160
161 void RbxGotoCodeGen::emitRangeBSearch( RedStateAp *state, int level, int low, int high )
162 {
163         /* Get the mid position, staying on the lower end of the range. */
164         int mid = (low + high) >> 1;
165         RedTransEl *data = state->outRange.data;
166
167         /* Determine if we need to look higher or lower. */
168         bool anyLower = mid > low;
169         bool anyHigher = mid < high;
170
171         /* Determine if the keys at mid are the limits of the alphabet. */
172         bool limitLow = data[mid].lowKey == keyOps->minKey;
173         bool limitHigh = data[mid].highKey == keyOps->maxKey;
174
175         if ( anyLower && anyHigher ) {
176                 /* Can go lower and higher than mid. */
177                 out << TABS(level) << "if " << GET_WIDE_KEY(state) << " < " << 
178                         KEY(data[mid].lowKey) << " \n";
179                 emitRangeBSearch( state, level+1, low, mid-1 );
180                 out << TABS(level) << "elsif " << GET_WIDE_KEY(state) << " > " << 
181                         KEY(data[mid].highKey) << " \n";
182                 emitRangeBSearch( state, level+1, mid+1, high );
183                 out << TABS(level) << "else\n";
184                 TRANS_GOTO(data[mid].value, level+1) << "\n";
185                 out << TABS(level) << "end\n";
186         }
187         else if ( anyLower && !anyHigher ) {
188                 /* Can go lower than mid but not higher. */
189                 out << TABS(level) << "if " << GET_WIDE_KEY(state) << " < " << 
190                         KEY(data[mid].lowKey) << " then\n";
191                 emitRangeBSearch( state, level+1, low, mid-1 );
192
193                 /* if the higher is the highest in the alphabet then there is no
194                  * sense testing it. */
195                 if ( limitHigh ) {
196                         out << TABS(level) << "else\n";
197                         TRANS_GOTO(data[mid].value, level+1) << "\n";
198                 }
199                 else {
200                         out << TABS(level) << "elsif" << GET_WIDE_KEY(state) << " <= " << 
201                                 KEY(data[mid].highKey) << " )\n";
202                         TRANS_GOTO(data[mid].value, level+1) << "\n";
203                 }
204                 out << TABS(level) << "end\n";
205         }
206         else if ( !anyLower && anyHigher ) {
207                 /* Can go higher than mid but not lower. */
208                 out << TABS(level) << "if " << GET_WIDE_KEY(state) << " > " << 
209                         KEY(data[mid].highKey) << " \n";
210                 emitRangeBSearch( state, level+1, mid+1, high );
211
212                 /* If the lower end is the lowest in the alphabet then there is no
213                  * sense testing it. */
214                 if ( limitLow ) {
215                         out << TABS(level) << "else\n";
216                         TRANS_GOTO(data[mid].value, level+1) << "\n";
217                 }
218                 else {
219                         out << TABS(level) << "elsif " << GET_WIDE_KEY(state) << " >= " << 
220                                 KEY(data[mid].lowKey) << " then\n";
221                         TRANS_GOTO(data[mid].value, level+1) << "\n";
222                 }
223                 out << TABS(level) << "end\n";
224         }
225         else {
226                 /* Cannot go higher or lower than mid. It's mid or bust. What
227                  * tests to do depends on limits of alphabet. */
228                 if ( !limitLow && !limitHigh ) {
229                         out << TABS(level) << "if " << KEY(data[mid].lowKey) << " <= " << 
230                                 GET_WIDE_KEY(state) << " && " << GET_WIDE_KEY(state) << " <= " << 
231                                 KEY(data[mid].highKey) << " \n";
232                         TRANS_GOTO(data[mid].value, level+1) << "\n";
233                         out << TABS(level) << "end\n";
234                 }
235                 else if ( limitLow && !limitHigh ) {
236                         out << TABS(level) << "if " << GET_WIDE_KEY(state) << " <= " << 
237                                 KEY(data[mid].highKey) << " \n";
238                         TRANS_GOTO(data[mid].value, level+1) << "\n";
239                         out << TABS(level) << "end\n";
240                 }
241                 else if ( !limitLow && limitHigh ) {
242                         out << TABS(level) << "if " << KEY(data[mid].lowKey) << " <= " << 
243                                 GET_WIDE_KEY(state) << " \n";
244                         TRANS_GOTO(data[mid].value, level+1) << "\n";
245                         out << TABS(level) << "end\n";
246                 }
247                 else {
248                         /* Both high and low are at the limit. No tests to do. */
249                         TRANS_GOTO(data[mid].value, level+1) << "\n";
250                 }
251         }
252 }
253
254 void RbxGotoCodeGen::STATE_GOTO_ERROR()
255 {
256         /* Label the state and bail immediately. */
257         outLabelUsed = true;
258         RedStateAp *state = redFsm->errState;
259         out << "when " << state->id << " then\n";
260         rbxGoto(out << "        ", "_out") << "\n";
261 }
262
263 void RbxGotoCodeGen::COND_TRANSLATE( GenStateCond *stateCond, int level )
264 {
265         GenCondSpace *condSpace = stateCond->condSpace;
266         out << TABS(level) << "_widec = " <<
267                 KEY(condSpace->baseKey) << " + (" << GET_KEY() << 
268                 " - " << KEY(keyOps->minKey) << ");\n";
269
270         for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
271                 out << TABS(level) << "if ";
272                 CONDITION( out, *csi );
273                 Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize());
274                 out << "\n _widec += " << condValOffset << ";\n end";
275         }
276 }
277
278 void RbxGotoCodeGen::emitCondBSearch( RedStateAp *state, int level, int low, int high )
279 {
280         /* Get the mid position, staying on the lower end of the range. */
281         int mid = (low + high) >> 1;
282         GenStateCond **data = state->stateCondVect.data;
283
284         /* Determine if we need to look higher or lower. */
285         bool anyLower = mid > low;
286         bool anyHigher = mid < high;
287
288         /* Determine if the keys at mid are the limits of the alphabet. */
289         bool limitLow = data[mid]->lowKey == keyOps->minKey;
290         bool limitHigh = data[mid]->highKey == keyOps->maxKey;
291
292         if ( anyLower && anyHigher ) {
293                 /* Can go lower and higher than mid. */
294                 out << TABS(level) << "if " << GET_KEY() << " < " << 
295                         KEY(data[mid]->lowKey) << " \n";
296                 emitCondBSearch( state, level+1, low, mid-1 );
297                 out << TABS(level) << "elsif " << GET_KEY() << " > " << 
298                         KEY(data[mid]->highKey) << " \n";
299                 emitCondBSearch( state, level+1, mid+1, high );
300                 out << TABS(level) << "else\n";
301                 COND_TRANSLATE(data[mid], level+1);
302                 out << TABS(level) << "end\n";
303         }
304         else if ( anyLower && !anyHigher ) {
305                 /* Can go lower than mid but not higher. */
306                 out << TABS(level) << "if " << GET_KEY() << " < " << 
307                         KEY(data[mid]->lowKey) << " \n";
308                 emitCondBSearch( state, level+1, low, mid-1 );
309
310                 /* if the higher is the highest in the alphabet then there is no
311                  * sense testing it. */
312                 if ( limitHigh ) {
313                         out << TABS(level) << "else\n";
314                         COND_TRANSLATE(data[mid], level+1);
315                 }
316                 else {
317                         out << TABS(level) << "elsif " << GET_KEY() << " <= " << 
318                                 KEY(data[mid]->highKey) << " then\n";
319                         COND_TRANSLATE(data[mid], level+1);
320                 }
321                 out << TABS(level) << "end\n";
322
323         }
324         else if ( !anyLower && anyHigher ) {
325                 /* Can go higher than mid but not lower. */
326                 out << TABS(level) << "if " << GET_KEY() << " > " << 
327                         KEY(data[mid]->highKey) << " \n";
328                 emitCondBSearch( state, level+1, mid+1, high );
329
330                 /* If the lower end is the lowest in the alphabet then there is no
331                  * sense testing it. */
332                 if ( limitLow ) {
333                         out << TABS(level) << "else\n";
334                         COND_TRANSLATE(data[mid], level+1);
335                 }
336                 else {
337                         out << TABS(level) << "elsif " << GET_KEY() << " >= " << 
338                                 KEY(data[mid]->lowKey) << " then\n";
339                         COND_TRANSLATE(data[mid], level+1);
340                 }
341                 out << TABS(level) << "end\n";
342         }
343         else {
344                 /* Cannot go higher or lower than mid. It's mid or bust. What
345                  * tests to do depends on limits of alphabet. */
346                 if ( !limitLow && !limitHigh ) {
347                         out << TABS(level) << "if " << KEY(data[mid]->lowKey) << " <= " << 
348                                 GET_KEY() << " && " << GET_KEY() << " <= " << 
349                                 KEY(data[mid]->highKey) << " then\n";
350                         COND_TRANSLATE(data[mid], level+1);
351                         out << TABS(level) << "end\n";
352                 }
353                 else if ( limitLow && !limitHigh ) {
354                         out << TABS(level) << "if " << GET_KEY() << " <= " << 
355                                 KEY(data[mid]->highKey) << " then\n";
356                         COND_TRANSLATE(data[mid], level+1);
357                         out << TABS(level) << "end\n";
358                 }
359                 else if ( !limitLow && limitHigh ) {
360                         out << TABS(level) << "if " << KEY(data[mid]->lowKey) << " <= " << 
361                                 GET_KEY() << " then\n";
362                         COND_TRANSLATE(data[mid], level+1);
363                         out << TABS(level) << "end\n";
364                 }
365                 else {
366                         /* Both high and low are at the limit. No tests to do. */
367                         COND_TRANSLATE(data[mid], level);
368                 }
369         }
370 }
371
372 std::ostream &RbxGotoCodeGen::STATE_GOTOS()
373 {
374         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
375                 if ( st == redFsm->errState )
376                         STATE_GOTO_ERROR();
377                 else {
378                         /* Writing code above state gotos. */
379                         GOTO_HEADER( st );
380
381                         if ( st->stateCondVect.length() > 0 ) {
382                                 out << "        _widec = " << GET_KEY() << ";\n";
383                                 emitCondBSearch( st, 1, 0, st->stateCondVect.length() - 1 );
384                         }
385
386                         /* Try singles. */
387                         if ( st->outSingle.length() > 0 )
388                                 emitSingleSwitch( st );
389
390                         /* Default case is to binary search for the ranges, if that fails then */
391                         if ( st->outRange.length() > 0 )
392                                 emitRangeBSearch( st, 1, 0, st->outRange.length() - 1 );
393
394                         /* Write the default transition. */
395                         TRANS_GOTO( st->defTrans, 1 ) << "\n";
396                 }
397         }
398         return out;
399 }
400
401 std::ostream &RbxGotoCodeGen::TRANSITIONS()
402 {
403         /* Emit any transitions that have functions and that go to 
404          * this state. */
405         for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) {
406                 /* Write the label for the transition so it can be jumped to. */
407                 rbxLabel(out << "       ", label("tr", trans->id)) << "\n";
408
409                 /* Destination state. */
410                 if ( trans->action != 0 && trans->action->anyCurStateRef() )
411                         out << "_ps = " << vCS() << "'n";
412                 out << vCS() << " = " << trans->targ->id << "\n";
413
414                 if ( trans->action != 0 ) {
415                         /* Write out the transition func. */
416                         rbxGoto(out, label("f", trans->action->actListId)) << "\n";
417                 }
418                 else {
419                         /* No code to execute, just loop around. */
420                         rbxGoto(out, "_again") << "\n";
421                 }
422         }
423         return out;
424 }
425
426 std::ostream &RbxGotoCodeGen::EXEC_FUNCS()
427 {
428         /* Make labels that set acts and jump to execFuncs. Loop func indicies. */
429         for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
430                 if ( redAct->numTransRefs > 0 ) {
431                         rbxLabel(out, label("f", redAct->actListId)) << "\n" <<
432                                 "_acts = " << itoa( redAct->location+1 ) << "\n";
433                         rbxGoto(out, "execFuncs") << "\n";
434                 }
435         }
436
437         rbxLabel(out, "execFuncs") <<
438                 "\n"
439                 "       _nacts = " << A() << "[_acts]\n"
440                 "       _acts += 1\n"
441                 "       while ( _nacts > 0 ) \n"
442                 "               _nacts -= 1\n"
443                 "               _acts += 1\n"
444                 "               case ( "<< A() << "[_acts-1] ) \n";
445         ACTION_SWITCH();
446         out <<
447                 "               end\n"
448                 "       end \n";
449         rbxGoto(out, "_again");
450         return out;
451 }
452
453 int RbxGotoCodeGen::TO_STATE_ACTION( RedStateAp *state )
454 {
455         int act = 0;
456         if ( state->toStateAction != 0 )
457                 act = state->toStateAction->location+1;
458         return act;
459 }
460
461 int RbxGotoCodeGen::FROM_STATE_ACTION( RedStateAp *state )
462 {
463         int act = 0;
464         if ( state->fromStateAction != 0 )
465                 act = state->fromStateAction->location+1;
466         return act;
467 }
468
469 int RbxGotoCodeGen::EOF_ACTION( RedStateAp *state )
470 {
471         int act = 0;
472         if ( state->eofAction != 0 )
473                 act = state->eofAction->location+1;
474         return act;
475 }
476
477 std::ostream &RbxGotoCodeGen::TO_STATE_ACTIONS()
478 {
479         /* Take one off for the psuedo start state. */
480         int numStates = redFsm->stateList.length();
481         unsigned int *vals = new unsigned int[numStates];
482         memset( vals, 0, sizeof(unsigned int)*numStates );
483
484         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
485                 vals[st->id] = TO_STATE_ACTION(st);
486
487         out << "\t";
488         for ( int st = 0; st < redFsm->nextStateId; st++ ) {
489                 /* Write any eof action. */
490                 out << vals[st];
491                 if ( st < numStates-1 ) {
492                         out << ", ";
493                         if ( (st+1) % IALL == 0 )
494                                 out << "\n\t";
495                 }
496         }
497         out << "\n";
498         delete[] vals;
499         return out;
500 }
501
502 std::ostream &RbxGotoCodeGen::FROM_STATE_ACTIONS()
503 {
504         /* Take one off for the psuedo start state. */
505         int numStates = redFsm->stateList.length();
506         unsigned int *vals = new unsigned int[numStates];
507         memset( vals, 0, sizeof(unsigned int)*numStates );
508
509         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
510                 vals[st->id] = FROM_STATE_ACTION(st);
511
512         out << "\t";
513         for ( int st = 0; st < redFsm->nextStateId; st++ ) {
514                 /* Write any eof action. */
515                 out << vals[st];
516                 if ( st < numStates-1 ) {
517                         out << ", ";
518                         if ( (st+1) % IALL == 0 )
519                                 out << "\n\t";
520                 }
521         }
522         out << "\n";
523         delete[] vals;
524         return out;
525 }
526
527 std::ostream &RbxGotoCodeGen::EOF_ACTIONS()
528 {
529         /* Take one off for the psuedo start state. */
530         int numStates = redFsm->stateList.length();
531         unsigned int *vals = new unsigned int[numStates];
532         memset( vals, 0, sizeof(unsigned int)*numStates );
533
534         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
535                 vals[st->id] = EOF_ACTION(st);
536
537         out << "\t";
538         for ( int st = 0; st < redFsm->nextStateId; st++ ) {
539                 /* Write any eof action. */
540                 out << vals[st];
541                 if ( st < numStates-1 ) {
542                         out << ", ";
543                         if ( (st+1) % IALL == 0 )
544                                 out << "\n\t";
545                 }
546         }
547         out << "\n";
548         delete[] vals;
549         return out;
550 }
551
552 std::ostream &RbxGotoCodeGen::FINISH_CASES()
553 {
554         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
555                 /* States that are final and have an out action need a case. */
556                 if ( st->eofAction != 0 ) {
557                         /* Write the case label. */
558                         out << "\t\twhen " << st->id << " then\n";
559
560                         /* Write the goto func. */
561                         rbxGoto(out, label("f", st->eofAction->actListId)) << "\n";
562                 }
563         }
564         
565         return out;
566 }
567
568 void RbxGotoCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
569 {
570         ret << "begin\n" << vCS() << " = " << gotoDest << " ";
571         rbxGoto(ret, "_again") << 
572                 "\nend\n";
573 }
574
575 void RbxGotoCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
576 {
577         ret << "begin\n" << vCS() << " = (";
578         INLINE_LIST( ret, ilItem->children, 0, inFinish );
579         ret << ")";
580         rbxGoto(ret, "_again") << 
581                 "\nend\n";
582 }
583
584 void RbxGotoCodeGen::CURS( ostream &ret, bool inFinish )
585 {
586         ret << "(_ps)";
587 }
588
589 void RbxGotoCodeGen::TARGS( ostream &ret, bool inFinish, int targState )
590 {
591         ret << "(" << vCS() << ")";
592 }
593
594 void RbxGotoCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
595 {
596         ret << vCS() << " = " << nextDest << ";";
597 }
598
599 void RbxGotoCodeGen::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
600 {
601         ret << vCS() << " = (";
602         INLINE_LIST( ret, ilItem->children, 0, inFinish );
603         ret << ");";
604 }
605
606 void RbxGotoCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
607 {
608         if ( prePushExpr != 0 ) {
609                 ret << "{";
610                 INLINE_LIST( ret, prePushExpr, 0, false );
611         }
612
613         ret << "begin\n" 
614             << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = " << 
615                 callDest << "; ";
616         rbxGoto(ret, "_again") << 
617                 "\nend\n";
618
619         if ( prePushExpr != 0 )
620                 ret << "}";
621 }
622
623 void RbxGotoCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish )
624 {
625         if ( prePushExpr != 0 ) {
626                 ret << "{";
627                 INLINE_LIST( ret, prePushExpr, 0, false );
628         }
629
630         ret << "begin\n" << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = (";
631         INLINE_LIST( ret, ilItem->children, targState, inFinish );
632         ret << "); ";
633         rbxGoto(ret, "_again") << 
634                 "\nend\n";
635
636         if ( prePushExpr != 0 )
637                 ret << "}";
638 }
639
640 void RbxGotoCodeGen::RET( ostream &ret, bool inFinish )
641 {
642         ret << "begin\n" << vCS() << " = " << STACK() << "[--" << TOP() << "]; " ;
643
644         if ( postPopExpr != 0 ) {
645                 ret << "{";
646                 INLINE_LIST( ret, postPopExpr, 0, false );
647                 ret << "}";
648         }
649
650         rbxGoto(ret, "_again") << 
651                 "\nend\n";
652 }
653
654 void RbxGotoCodeGen::BREAK( ostream &ret, int targState )
655 {
656         outLabelUsed = true;
657
658         out <<
659                 "       begin\n"
660                 "               " << P() << " += 1\n"
661                 "               " << rbxGoto(ret, "_out") << "\n" 
662                 "       end\n";
663 }
664
665 void RbxGotoCodeGen::writeData()
666 {
667         if ( redFsm->anyActions() ) {
668                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
669                 ACTIONS_ARRAY();
670                 CLOSE_ARRAY() <<
671                         "\n";
672         }
673
674         if ( redFsm->anyToStateActions() ) {
675                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
676                 TO_STATE_ACTIONS();
677                 CLOSE_ARRAY() <<
678                         "\n";
679         }
680
681         if ( redFsm->anyFromStateActions() ) {
682                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
683                 FROM_STATE_ACTIONS();
684                 CLOSE_ARRAY() <<
685                         "\n";
686         }
687
688         if ( redFsm->anyEofActions() ) {
689                 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
690                 EOF_ACTIONS();
691                 CLOSE_ARRAY() <<
692                         "\n";
693         }
694
695         STATE_IDS();
696 }
697
698 void RbxGotoCodeGen::writeExec()
699 {
700         outLabelUsed = false;
701
702         out << "        begin\n";
703
704         out << "        Rubinius.asm { @labels = Hash.new { |h,k| h[k] = new_label } }\n";
705
706         if ( redFsm->anyRegCurStateRef() )
707                 out << "        _ps = 0;\n";
708
709         if ( redFsm->anyToStateActions() || redFsm->anyRegActions() 
710              || redFsm->anyFromStateActions() )
711         {
712                 out <<  " _acts, _nacts = nil\n";
713         }
714
715         if ( redFsm->anyConditions() )
716                 out << "        _widec = nil\n";
717
718         out << "\n";
719
720         if ( !noEnd ) {
721                 outLabelUsed = true;
722                 out << 
723                         "       if ( " << P() << " == " << PE() << " )\n";
724                 rbxGoto(out << "                ", "_out") << "\n" <<
725                         "       end\n";
726         }
727
728         if ( redFsm->errState != 0 ) {
729                 outLabelUsed = true;
730                 out << 
731                         "       if ( " << vCS() << " == " << redFsm->errState->id << " )\n";
732                 rbxGoto(out << "                ", "_out") << "\n" <<
733                         "       end\n";
734         }
735
736         rbxLabel(out, "_resume") << "\n";
737
738         if ( redFsm->anyFromStateActions() ) {
739                 out <<
740
741                         "       _acts = " << ARR_OFF( A(), FSA() + "[" + vCS() + "]" ) << ";\n"
742                         "       _nacts = " << " *_acts++;\n"
743                         "       while ( _nacts-- > 0 ) {\n"
744                         "               switch ( *_acts++ ) {\n";
745                 FROM_STATE_ACTION_SWITCH();
746                 out <<
747                         "               }\n"
748                         "       }\n"
749                         "\n";
750         }
751
752         out <<
753                 "       case ( " << vCS() << " )\n";
754         STATE_GOTOS();
755         out <<
756                 "       end # case\n"
757                 "\n";
758         TRANSITIONS() <<
759                 "\n";
760
761         if ( redFsm->anyRegActions() )
762                 EXEC_FUNCS() << "\n";
763
764
765         rbxLabel(out, "_again") << "\n";
766
767         if ( redFsm->anyToStateActions() ) {
768                 out <<
769                         "       _acts = " << ARR_OFF( A(), TSA() + "[" + vCS() + "]" ) << ";\n"
770                         "       _nacts = " << " *_acts++;\n"
771                         "       while ( _nacts-- > 0 ) {\n"
772                         "               switch ( *_acts++ ) {\n";
773                 TO_STATE_ACTION_SWITCH();
774                 out <<
775                         "               }\n"
776                         "       }\n"
777                         "\n";
778         }
779
780         if ( redFsm->errState != 0 ) {
781                 outLabelUsed = true;
782                 out << 
783                         "       if ( " << vCS() << " == " << redFsm->errState->id << " )\n";
784                 rbxGoto(out << "                ", "_out") << "\n" <<
785                         "       end" << "\n";
786         }
787
788         if ( !noEnd ) {
789                 out <<  "       "  << P() << " += 1\n"
790                         "       if ( " << P() << " != " << PE() << " )\n";
791                 rbxGoto(out << "                ", "_resume") << "\n" <<
792                         "       end" << "\n";
793         }
794         else {
795                 out << 
796                         "       " << P() << " += 1;\n";
797                 rbxGoto(out << "        ", "_resume") << "\n";
798         }
799
800         if ( outLabelUsed )
801                 rbxLabel(out, "_out") << "\n";
802
803         out << "        end\n";
804 }
805
806 void RbxGotoCodeGen::writeEOF()
807 {
808         if ( redFsm->anyEofActions() ) {
809                 out << 
810                         "       {\n"
811                         "        _acts = " << 
812                         ARR_OFF( A(), EA() + "[" + vCS() + "]" ) << ";\n"
813                         "       " << " _nacts = " << " *_acts++;\n"
814                         "       while ( _nacts-- > 0 ) {\n"
815                         "               switch ( *_acts++ ) {\n";
816                 EOF_ACTION_SWITCH();
817                 out <<
818                         "               }\n"
819                         "       }\n"
820                         "       }\n"
821                         "\n";
822         }
823 }
824
825 /*
826  * Local Variables:
827  * mode: c++
828  * indent-tabs-mode: 1
829  * c-file-style: "bsd"
830  * End:
831  */