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 "cdgoto.h"
26 #include "redfsm.h"
27 #include "bstmap.h"
28 #include "gendata.h"
29
30 /* Emit the goto to take for a given transition. */
TRANS_GOTO(RedTransAp * trans,int level)31 std::ostream &GotoCodeGen::TRANS_GOTO( RedTransAp *trans, int level )
32 {
33 out << TABS(level) << "goto tr" << trans->id << ";";
34 return out;
35 }
36
TO_STATE_ACTION_SWITCH()37 std::ostream &GotoCodeGen::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, false );
46 out << "\tbreak;\n";
47 }
48 }
49
50 genLineDirective( out );
51 return out;
52 }
53
FROM_STATE_ACTION_SWITCH()54 std::ostream &GotoCodeGen::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, false );
63 out << "\tbreak;\n";
64 }
65 }
66
67 genLineDirective( out );
68 return out;
69 }
70
EOF_ACTION_SWITCH()71 std::ostream &GotoCodeGen::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, false );
80 out << "\tbreak;\n";
81 }
82 }
83
84 genLineDirective( out );
85 return out;
86 }
87
ACTION_SWITCH()88 std::ostream &GotoCodeGen::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, false );
97 out << "\tbreak;\n";
98 }
99 }
100
101 genLineDirective( out );
102 return out;
103 }
104
GOTO_HEADER(RedStateAp * state)105 void GotoCodeGen::GOTO_HEADER( RedStateAp *state )
106 {
107 /* Label the state. */
108 out << "case " << state->id << ":\n";
109 }
110
111
emitSingleSwitch(RedStateAp * state)112 void GotoCodeGen::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 WIDE_KEY(state, 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 " << WIDE_KEY(state, 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
emitRangeBSearch(RedStateAp * state,int level,int low,int high)144 void GotoCodeGen::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 WIDE_KEY(state, data[mid].lowKey) << " ) {\n";
162 emitRangeBSearch( state, level+1, low, mid-1 );
163 out << TABS(level) << "} else if ( " << GET_WIDE_KEY(state) << " > " <<
164 WIDE_KEY(state, 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 WIDE_KEY(state, 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 WIDE_KEY(state, 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 WIDE_KEY(state, 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 WIDE_KEY(state, 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 ( " << WIDE_KEY(state, data[mid].lowKey) << " <= " <<
210 GET_WIDE_KEY(state) << " && " << GET_WIDE_KEY(state) << " <= " <<
211 WIDE_KEY(state, 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 WIDE_KEY(state, data[mid].highKey) << " )\n";
217 TRANS_GOTO(data[mid].value, level+1) << "\n";
218 }
219 else if ( !limitLow && limitHigh ) {
220 out << TABS(level) << "if ( " << WIDE_KEY(state, 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
STATE_GOTO_ERROR()231 void GotoCodeGen::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
COND_TRANSLATE(GenStateCond * stateCond,int level)240 void GotoCodeGen::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
emitCondBSearch(RedStateAp * state,int level,int low,int high)255 void GotoCodeGen::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
STATE_GOTOS()350 std::ostream &GotoCodeGen::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
TRANSITIONS()379 std::ostream &GotoCodeGen::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
EXEC_FUNCS()404 std::ostream &GotoCodeGen::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 = " << ARR_OFF(A(), itoa( redAct->location+1 ) ) << ";"
411 " goto execFuncs;\n";
412 }
413 }
414
415 out <<
416 "\n"
417 "execFuncs:\n"
418 " _nacts = *_acts++;\n"
419 " while ( _nacts-- > 0 ) {\n"
420 " switch ( *_acts++ ) {\n";
421 ACTION_SWITCH();
422 SWITCH_DEFAULT() <<
423 " }\n"
424 " }\n"
425 " goto _again;\n";
426 return out;
427 }
428
TO_STATE_ACTION(RedStateAp * state)429 unsigned int GotoCodeGen::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
FROM_STATE_ACTION(RedStateAp * state)437 unsigned int GotoCodeGen::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
EOF_ACTION(RedStateAp * state)445 unsigned int GotoCodeGen::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
TO_STATE_ACTIONS()453 std::ostream &GotoCodeGen::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
FROM_STATE_ACTIONS()478 std::ostream &GotoCodeGen::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
EOF_ACTIONS()503 std::ostream &GotoCodeGen::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
FINISH_CASES()528 std::ostream &GotoCodeGen::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
GOTO(ostream & ret,int gotoDest,bool inFinish)544 void GotoCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
545 {
546 ret << "{";
547
548 ret << vCS() << " = " << gotoDest << ";";
549
550 if ( inFinish && !noEnd )
551 EOF_CHECK( ret );
552
553 ret << CTRL_FLOW() << "goto _again;";
554
555 ret << "}";
556 }
557
GOTO_EXPR(ostream & ret,GenInlineItem * ilItem,bool inFinish)558 void GotoCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
559 {
560 ret << "{";
561
562 ret << vCS() << " = (";
563 INLINE_LIST( ret, ilItem->children, 0, inFinish, false );
564 ret << ");";
565
566 if ( inFinish && !noEnd )
567 EOF_CHECK( ret );
568
569 ret << CTRL_FLOW() << "goto _again;";
570
571 ret << "}";
572 }
573
CURS(ostream & ret,bool inFinish)574 void GotoCodeGen::CURS( ostream &ret, bool inFinish )
575 {
576 ret << "(_ps)";
577 }
578
TARGS(ostream & ret,bool inFinish,int targState)579 void GotoCodeGen::TARGS( ostream &ret, bool inFinish, int targState )
580 {
581 ret << "(" << vCS() << ")";
582 }
583
NEXT(ostream & ret,int nextDest,bool inFinish)584 void GotoCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
585 {
586 ret << vCS() << " = " << nextDest << ";";
587 }
588
NEXT_EXPR(ostream & ret,GenInlineItem * ilItem,bool inFinish)589 void GotoCodeGen::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
590 {
591 ret << vCS() << " = (";
592 INLINE_LIST( ret, ilItem->children, 0, inFinish, false );
593 ret << ");";
594 }
595
CALL(ostream & ret,int callDest,int targState,bool inFinish)596 void GotoCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
597 {
598 if ( prePushExpr != 0 ) {
599 ret << "{";
600 INLINE_LIST( ret, prePushExpr, 0, false, false );
601 }
602
603 ret << "{";
604
605 ret << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = " << callDest << ";";
606
607 if ( inFinish && !noEnd )
608 EOF_CHECK( ret );
609
610 ret << CTRL_FLOW() << "goto _again;";
611
612 ret << "}";
613
614 if ( prePushExpr != 0 )
615 ret << "}";
616 }
617
CALL_EXPR(ostream & ret,GenInlineItem * ilItem,int targState,bool inFinish)618 void GotoCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish )
619 {
620 if ( prePushExpr != 0 ) {
621 ret << "{";
622 INLINE_LIST( ret, prePushExpr, 0, false, false );
623 }
624
625 ret << "{";
626
627 ret << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = (";
628 INLINE_LIST( ret, ilItem->children, targState, inFinish, false );
629 ret << ");";
630
631 if ( inFinish && !noEnd )
632 EOF_CHECK( ret );
633
634 ret << CTRL_FLOW() << "goto _again;";
635
636 ret << "}";
637
638 if ( prePushExpr != 0 )
639 ret << "}";
640 }
641
RET(ostream & ret,bool inFinish)642 void GotoCodeGen::RET( ostream &ret, bool inFinish )
643 {
644 ret << "{" << vCS() << " = " << STACK() << "[--" << TOP() << "];";
645
646 if ( postPopExpr != 0 ) {
647 ret << "{";
648 INLINE_LIST( ret, postPopExpr, 0, false, false );
649 ret << "}";
650 }
651
652 if ( inFinish && !noEnd )
653 EOF_CHECK( ret );
654
655 ret << CTRL_FLOW() << "goto _again;";
656 ret << "}";
657 }
658
BREAK(ostream & ret,int targState,bool csForced)659 void GotoCodeGen::BREAK( ostream &ret, int targState, bool csForced )
660 {
661 outLabelUsed = true;
662 ret << "{" << P() << "++; " << CTRL_FLOW() << "goto _out; }";
663 }
664
writeData()665 void GotoCodeGen::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
writeExec()698 void GotoCodeGen::writeExec()
699 {
700 testEofUsed = false;
701 outLabelUsed = false;
702
703 out << " {\n";
704
705 if ( redFsm->anyRegCurStateRef() )
706 out << " int _ps = 0;\n";
707
708 if ( redFsm->anyToStateActions() || redFsm->anyRegActions()
709 || redFsm->anyFromStateActions() )
710 {
711 out <<
712 " " << PTR_CONST() << ARRAY_TYPE(redFsm->maxActArrItem) << PTR_CONST_END() << POINTER() << "_acts;\n"
713 " " << UINT() << " _nacts;\n";
714 }
715
716 if ( redFsm->anyConditions() )
717 out << " " << WIDE_ALPH_TYPE() << " _widec;\n";
718
719 out << "\n";
720
721 if ( !noEnd ) {
722 testEofUsed = true;
723 out <<
724 " if ( " << P() << " == " << PE() << " )\n"
725 " goto _test_eof;\n";
726 }
727
728 if ( redFsm->errState != 0 ) {
729 outLabelUsed = true;
730 out <<
731 " if ( " << vCS() << " == " << redFsm->errState->id << " )\n"
732 " goto _out;\n";
733 }
734
735 out << "_resume:\n";
736
737 if ( redFsm->anyFromStateActions() ) {
738 out <<
739 " _acts = " << ARR_OFF( A(), FSA() + "[" + vCS() + "]" ) << ";\n"
740 " _nacts = " << CAST(UINT()) << " *_acts++;\n"
741 " while ( _nacts-- > 0 ) {\n"
742 " switch ( *_acts++ ) {\n";
743 FROM_STATE_ACTION_SWITCH();
744 SWITCH_DEFAULT() <<
745 " }\n"
746 " }\n"
747 "\n";
748 }
749
750 out <<
751 " switch ( " << vCS() << " ) {\n";
752 STATE_GOTOS();
753 SWITCH_DEFAULT() <<
754 " }\n"
755 "\n";
756 TRANSITIONS() <<
757 "\n";
758
759 if ( redFsm->anyRegActions() )
760 EXEC_FUNCS() << "\n";
761
762 out << "_again:\n";
763
764 if ( redFsm->anyToStateActions() ) {
765 out <<
766 " _acts = " << ARR_OFF( A(), TSA() + "[" + vCS() + "]" ) << ";\n"
767 " _nacts = " << CAST(UINT()) << " *_acts++;\n"
768 " while ( _nacts-- > 0 ) {\n"
769 " switch ( *_acts++ ) {\n";
770 TO_STATE_ACTION_SWITCH();
771 SWITCH_DEFAULT() <<
772 " }\n"
773 " }\n"
774 "\n";
775 }
776
777 if ( redFsm->errState != 0 ) {
778 outLabelUsed = true;
779 out <<
780 " if ( " << vCS() << " == " << redFsm->errState->id << " )\n"
781 " goto _out;\n";
782 }
783
784 if ( !noEnd ) {
785 out <<
786 " if ( ++" << P() << " != " << PE() << " )\n"
787 " goto _resume;\n";
788 }
789 else {
790 out <<
791 " " << P() << " += 1;\n"
792 " goto _resume;\n";
793 }
794
795 if ( testEofUsed )
796 out << " _test_eof: {}\n";
797
798 if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
799 out <<
800 " if ( " << P() << " == " << vEOF() << " )\n"
801 " {\n";
802
803 if ( redFsm->anyEofTrans() ) {
804 out <<
805 " switch ( " << vCS() << " ) {\n";
806
807 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
808 if ( st->eofTrans != 0 )
809 out << " case " << st->id << ": goto tr" << st->eofTrans->id << ";\n";
810 }
811
812 SWITCH_DEFAULT() <<
813 " }\n";
814 }
815
816 if ( redFsm->anyEofActions() ) {
817 out <<
818 " " << PTR_CONST() << ARRAY_TYPE(redFsm->maxActArrItem) << PTR_CONST_END() <<
819 POINTER() << "__acts = " <<
820 ARR_OFF( A(), EA() + "[" + vCS() + "]" ) << ";\n"
821 " " << UINT() << " __nacts = " << CAST(UINT()) << " *__acts++;\n"
822 " while ( __nacts-- > 0 ) {\n"
823 " switch ( *__acts++ ) {\n";
824 EOF_ACTION_SWITCH();
825 SWITCH_DEFAULT() <<
826 " }\n"
827 " }\n";
828 }
829
830 out <<
831 " }\n"
832 "\n";
833 }
834
835 if ( outLabelUsed )
836 out << " _out: {}\n";
837
838 out << " }\n";
839 }
840