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