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