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