1 /*
2  *  Copyright 2004-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 "goflat.h"
26 #include "redfsm.h"
27 #include "gendata.h"
28 
29 using std::endl;
30 
TO_STATE_ACTION(RedStateAp * state)31 std::ostream &GoFlatCodeGen::TO_STATE_ACTION( RedStateAp *state )
32 {
33 	int act = 0;
34 	if ( state->toStateAction != 0 )
35 		act = state->toStateAction->location+1;
36 	out << act;
37 	return out;
38 }
39 
FROM_STATE_ACTION(RedStateAp * state)40 std::ostream &GoFlatCodeGen::FROM_STATE_ACTION( RedStateAp *state )
41 {
42 	int act = 0;
43 	if ( state->fromStateAction != 0 )
44 		act = state->fromStateAction->location+1;
45 	out << act;
46 	return out;
47 }
48 
EOF_ACTION(RedStateAp * state)49 std::ostream &GoFlatCodeGen::EOF_ACTION( RedStateAp *state )
50 {
51 	int act = 0;
52 	if ( state->eofAction != 0 )
53 		act = state->eofAction->location+1;
54 	out << act;
55 	return out;
56 }
57 
TRANS_ACTION(RedTransAp * trans)58 std::ostream &GoFlatCodeGen::TRANS_ACTION( RedTransAp *trans )
59 {
60 	/* If there are actions, emit them. Otherwise emit zero. */
61 	int act = 0;
62 	if ( trans->action != 0 )
63 		act = trans->action->location+1;
64 	out << act;
65 	return out;
66 }
67 
TO_STATE_ACTION_SWITCH(int level)68 std::ostream &GoFlatCodeGen::TO_STATE_ACTION_SWITCH( int level )
69 {
70 	/* Walk the list of functions, printing the cases. */
71 	for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
72 		/* Write out referenced actions. */
73 		if ( act->numToStateRefs > 0 ) {
74 			/* Write the case label, the action and the case break */
75 			out << TABS(level) << "case " << act->actionId << ":" << endl;
76 			ACTION( out, act, 0, false, false );
77 		}
78 	}
79 
80 	genLineDirective( out );
81 	return out;
82 }
83 
FROM_STATE_ACTION_SWITCH(int level)84 std::ostream &GoFlatCodeGen::FROM_STATE_ACTION_SWITCH( int level )
85 {
86 	/* Walk the list of functions, printing the cases. */
87 	for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
88 		/* Write out referenced actions. */
89 		if ( act->numFromStateRefs > 0 ) {
90 			/* Write the case label, the action and the case break */
91 			out << TABS(level) << "case " << act->actionId << ":" << endl;
92 			ACTION( out, act, 0, false, false );
93 		}
94 	}
95 
96 	genLineDirective( out );
97 	return out;
98 }
99 
EOF_ACTION_SWITCH(int level)100 std::ostream &GoFlatCodeGen::EOF_ACTION_SWITCH( int level )
101 {
102 	/* Walk the list of functions, printing the cases. */
103 	for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
104 		/* Write out referenced actions. */
105 		if ( act->numEofRefs > 0 ) {
106 			/* Write the case label, the action and the case break */
107 			out << TABS(level) << "case " << act->actionId << ":" << endl;
108 			ACTION( out, act, 0, true, false );
109 		}
110 	}
111 
112 	genLineDirective( out );
113 	return out;
114 }
115 
116 
ACTION_SWITCH(int level)117 std::ostream &GoFlatCodeGen::ACTION_SWITCH( int level )
118 {
119 	/* Walk the list of functions, printing the cases. */
120 	for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
121 		/* Write out referenced actions. */
122 		if ( act->numTransRefs > 0 ) {
123 			/* Write the case label, the action and the case break */
124 			out << TABS(level) << "case " << act->actionId << ":" << endl;
125 			ACTION( out, act, 0, false, false );
126 		}
127 	}
128 
129 	genLineDirective( out );
130 	return out;
131 }
132 
133 
FLAT_INDEX_OFFSET()134 std::ostream &GoFlatCodeGen::FLAT_INDEX_OFFSET()
135 {
136 	out << "	";
137 	int totalStateNum = 0, curIndOffset = 0;
138 	for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
139 		/* Write the index offset. */
140 		out << curIndOffset << ", ";
141 		if ( !st.last() ) {
142 			if ( ++totalStateNum % IALL == 0 )
143 				out << endl << "	";
144 		}
145 
146 		/* Move the index offset ahead. */
147 		if ( st->transList != 0 )
148 			curIndOffset += keyOps->span( st->lowKey, st->highKey );
149 
150 		if ( st->defTrans != 0 )
151 			curIndOffset += 1;
152 	}
153 	out << endl;
154 	return out;
155 }
156 
KEY_SPANS()157 std::ostream &GoFlatCodeGen::KEY_SPANS()
158 {
159 	out << "	";
160 	int totalStateNum = 0;
161 	for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
162 		/* Write singles length. */
163 		unsigned long long span = 0;
164 		if ( st->transList != 0 )
165 			span = keyOps->span( st->lowKey, st->highKey );
166 		out << span << ", ";
167 		if ( !st.last() ) {
168 			if ( ++totalStateNum % IALL == 0 )
169 				out << endl << "	";
170 		}
171 	}
172 	out << endl;
173 	return out;
174 }
175 
TO_STATE_ACTIONS()176 std::ostream &GoFlatCodeGen::TO_STATE_ACTIONS()
177 {
178 	out << "	";
179 	int totalStateNum = 0;
180 	for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
181 		/* Write any eof action. */
182 		TO_STATE_ACTION(st);
183 		out << ", ";
184 		if ( !st.last() ) {
185 			if ( ++totalStateNum % IALL == 0 )
186 				out << endl << "	";
187 		}
188 	}
189 	out << endl;
190 	return out;
191 }
192 
FROM_STATE_ACTIONS()193 std::ostream &GoFlatCodeGen::FROM_STATE_ACTIONS()
194 {
195 	out << "	";
196 	int totalStateNum = 0;
197 	for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
198 		/* Write any eof action. */
199 		FROM_STATE_ACTION(st);
200 		out << ", ";
201 		if ( !st.last() ) {
202 			if ( ++totalStateNum % IALL == 0 )
203 				out << endl << "	";
204 		}
205 	}
206 	out << endl;
207 	return out;
208 }
209 
EOF_ACTIONS()210 std::ostream &GoFlatCodeGen::EOF_ACTIONS()
211 {
212 	out << "	";
213 	int totalStateNum = 0;
214 	for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
215 		/* Write any eof action. */
216 		EOF_ACTION(st);
217 		out << ", ";
218 		if ( !st.last() ) {
219 			if ( ++totalStateNum % IALL == 0 )
220 				out << endl << "	";
221 		}
222 	}
223 	out << endl;
224 	return out;
225 }
226 
EOF_TRANS()227 std::ostream &GoFlatCodeGen::EOF_TRANS()
228 {
229 	out << "	";
230 	int totalStateNum = 0;
231 	for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
232 		/* Write any eof action. */
233 
234 		long trans = 0;
235 		if ( st->eofTrans != 0 ) {
236 			assert( st->eofTrans->pos >= 0 );
237 			trans = st->eofTrans->pos+1;
238 		}
239 		out << trans << ", ";
240 
241 		if ( !st.last() ) {
242 			if ( ++totalStateNum % IALL == 0 )
243 				out << endl << "	";
244 		}
245 	}
246 	out << endl;
247 	return out;
248 }
249 
250 
COND_KEYS()251 std::ostream &GoFlatCodeGen::COND_KEYS()
252 {
253 	out << "	";
254 	int totalStateNum = 0;
255 	for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
256 		/* Emit just cond low key and cond high key. */
257 		out << KEY( st->condLowKey ) << ", ";
258 		out << KEY( st->condHighKey ) << ", ";
259 		if ( !st.last() ) {
260 			if ( ++totalStateNum % IALL == 0 )
261 				out << endl << "	";
262 		}
263 	}
264 
265 	out << endl;
266 	return out;
267 }
268 
COND_KEY_SPANS()269 std::ostream &GoFlatCodeGen::COND_KEY_SPANS()
270 {
271 	out << "	";
272 	int totalStateNum = 0;
273 	for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
274 		/* Write singles length. */
275 		unsigned long long span = 0;
276 		if ( st->condList != 0 )
277 			span = keyOps->span( st->condLowKey, st->condHighKey );
278 		out << span << ", ";
279 		if ( !st.last() ) {
280 			if ( ++totalStateNum % IALL == 0 )
281 				out << endl << "	";
282 		}
283 	}
284 	out << endl;
285 	return out;
286 }
287 
CONDS()288 std::ostream &GoFlatCodeGen::CONDS()
289 {
290 	out << "	";
291 	int totalStateNum = 0;
292 	for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
293 		if ( st->condList != 0 ) {
294 			/* Walk the singles. */
295 			unsigned long long span = keyOps->span( st->condLowKey, st->condHighKey );
296 			for ( unsigned long long pos = 0; pos < span; pos++ ) {
297 				if ( st->condList[pos] != 0 )
298 					out << st->condList[pos]->condSpaceId + 1 << ", ";
299 				else
300 					out << "0, ";
301 				if ( !st.last() ) {
302 					if ( ++totalStateNum % IALL == 0 )
303 						out << endl << "	";
304 				}
305 			}
306 		}
307 	}
308 
309 	out << endl;
310 	return out;
311 }
312 
COND_INDEX_OFFSET()313 std::ostream &GoFlatCodeGen::COND_INDEX_OFFSET()
314 {
315 	out << "	";
316 	int totalStateNum = 0;
317 	int curIndOffset = 0;
318 	for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
319 		/* Write the index offset. */
320 		out << curIndOffset << ", ";
321 		if ( !st.last() ) {
322 			if ( ++totalStateNum % IALL == 0 )
323 				out << endl << "	";
324 		}
325 
326 		/* Move the index offset ahead. */
327 		if ( st->condList != 0 )
328 			curIndOffset += keyOps->span( st->condLowKey, st->condHighKey );
329 	}
330 	out << endl;
331 	return out;
332 }
333 
334 
KEYS()335 std::ostream &GoFlatCodeGen::KEYS()
336 {
337 	out << "	";
338 	int totalStateNum = 0;
339 	for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
340 		/* Emit just low key and high key. */
341 		out << KEY( st->lowKey ) << ", ";
342 		out << KEY( st->highKey ) << ", ";
343 		if ( !st.last() ) {
344 			if ( ++totalStateNum % IALL == 0 )
345 				out << endl << "	";
346 		}
347 	}
348 
349 	out << endl;
350 	return out;
351 }
352 
INDICIES()353 std::ostream &GoFlatCodeGen::INDICIES()
354 {
355 	out << "	";
356 	int totalStateNum = 0;
357 	for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
358 		if ( st->transList != 0 ) {
359 			/* Walk the singles. */
360 			unsigned long long span = keyOps->span( st->lowKey, st->highKey );
361 			for ( unsigned long long pos = 0; pos < span; pos++ ) {
362 				out << st->transList[pos]->id << ", ";
363 				if ( ++totalStateNum % IALL == 0 )
364 					out << endl << "	";
365 			}
366 		}
367 
368 		/* The state's default index goes next. */
369 		if ( st->defTrans != 0 ) {
370 			out << st->defTrans->id << ", ";
371 			if ( ++totalStateNum % IALL == 0 )
372 				out << endl << "	";
373 		}
374 	}
375 
376 	out << endl;
377 	return out;
378 }
379 
TRANS_TARGS()380 std::ostream &GoFlatCodeGen::TRANS_TARGS()
381 {
382 	/* Transitions must be written ordered by their id. */
383 	RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
384 	for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
385 		transPtrs[trans->id] = trans;
386 
387 	/* Keep a count of the num of items in the array written. */
388 	out << "	";
389 	int totalStates = 0;
390 	for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
391 		/* Save the position. Needed for eofTargs. */
392 		RedTransAp *trans = transPtrs[t];
393 		trans->pos = t;
394 
395 		/* Write out the target state. */
396 		out << trans->targ->id << ", ";
397 		if ( t < redFsm->transSet.length()-1 ) {
398 			if ( ++totalStates % IALL == 0 )
399 				out << endl << "	";
400 		}
401 	}
402 	out << endl;
403 	delete[] transPtrs;
404 	return out;
405 }
406 
407 
TRANS_ACTIONS()408 std::ostream &GoFlatCodeGen::TRANS_ACTIONS()
409 {
410 	/* Transitions must be written ordered by their id. */
411 	RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
412 	for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
413 		transPtrs[trans->id] = trans;
414 
415 	/* Keep a count of the num of items in the array written. */
416 	out << "	";
417 	int totalAct = 0;
418 	for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
419 		/* Write the function for the transition. */
420 		RedTransAp *trans = transPtrs[t];
421 		TRANS_ACTION( trans );
422 		out << ", ";
423 		if ( t < redFsm->transSet.length()-1 ) {
424 			if ( ++totalAct % IALL == 0 )
425 				out << endl << "	";
426 		}
427 	}
428 	out << endl;
429 	delete[] transPtrs;
430 	return out;
431 }
432 
LOCATE_TRANS()433 void GoFlatCodeGen::LOCATE_TRANS()
434 {
435 	out <<
436 		"	_keys = " << CAST(INT(), vCS() + " << 1") << endl <<
437 		"	_inds = " << CAST(INT(), IO() + "[" + vCS() + "]") << endl <<
438 		endl <<
439 		"	_slen = " << CAST(INT(), SP() + "[" + vCS() + "]") << endl <<
440 		"	if _slen > 0 && " << K() << "[_keys] <= " << GET_WIDE_KEY() << " && " <<
441 			GET_WIDE_KEY() << " <= " << K() << "[_keys + 1]" << " {" << endl <<
442 		"		_trans = " << CAST(INT(), I() + "[_inds + " + CAST(INT(), GET_WIDE_KEY() + " - " + K() + "[_keys]") + "]") << endl <<
443 		"	} else {" << endl <<
444 		"		_trans = " << CAST(INT(), I() + "[_inds + _slen]") << endl <<
445 		"	}" << endl <<
446 		endl;
447 }
448 
writeData()449 void GoFlatCodeGen::writeData()
450 {
451 	/* If there are any transtion functions then output the array. If there
452 	 * are none, don't bother emitting an empty array that won't be used. */
453 	if ( redFsm->anyActions() ) {
454 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
455 		ACTIONS_ARRAY();
456 		CLOSE_ARRAY() <<
457 		endl;
458 	}
459 
460 	if ( redFsm->anyConditions() ) {
461 		OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
462 		COND_KEYS();
463 		CLOSE_ARRAY() <<
464 		endl;
465 
466 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpan), CSP() );
467 		COND_KEY_SPANS();
468 		CLOSE_ARRAY() <<
469 		endl;
470 
471 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCond), C() );
472 		CONDS();
473 		CLOSE_ARRAY() <<
474 		endl;
475 
476 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondIndexOffset), CO() );
477 		COND_INDEX_OFFSET();
478 		CLOSE_ARRAY() <<
479 		endl;
480 	}
481 
482 	OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
483 	KEYS();
484 	CLOSE_ARRAY() <<
485 	endl;
486 
487 	OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSpan), SP() );
488 	KEY_SPANS();
489 	CLOSE_ARRAY() <<
490 	endl;
491 
492 	OPEN_ARRAY( ARRAY_TYPE(redFsm->maxFlatIndexOffset), IO() );
493 	FLAT_INDEX_OFFSET();
494 	CLOSE_ARRAY() <<
495 	endl;
496 
497 	OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
498 	INDICIES();
499 	CLOSE_ARRAY() <<
500 	endl;
501 
502 	OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
503 	TRANS_TARGS();
504 	CLOSE_ARRAY() <<
505 	endl;
506 
507 	if ( redFsm->anyActions() ) {
508 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
509 		TRANS_ACTIONS();
510 		CLOSE_ARRAY() <<
511 		endl;
512 	}
513 
514 	if ( redFsm->anyToStateActions() ) {
515 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
516 		TO_STATE_ACTIONS();
517 		CLOSE_ARRAY() <<
518 		endl;
519 	}
520 
521 	if ( redFsm->anyFromStateActions() ) {
522 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
523 		FROM_STATE_ACTIONS();
524 		CLOSE_ARRAY() <<
525 		endl;
526 	}
527 
528 	if ( redFsm->anyEofActions() ) {
529 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
530 		EOF_ACTIONS();
531 		CLOSE_ARRAY() <<
532 		endl;
533 	}
534 
535 	if ( redFsm->anyEofTrans() ) {
536 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset+1), ET() );
537 		EOF_TRANS();
538 		CLOSE_ARRAY() <<
539 		endl;
540 	}
541 
542 	STATE_IDS();
543 }
544 
COND_TRANSLATE()545 void GoFlatCodeGen::COND_TRANSLATE()
546 {
547 	out <<
548 		"	_widec = " << CAST(WIDE_ALPH_TYPE(), GET_KEY()) << endl;
549 
550 	out <<
551 		"	_keys = " << CAST(INT(), vCS() + " << 1") << endl <<
552 		"	_conds = " << CAST(INT(), CO() + "[" + vCS() + "]") << endl <<
553 		endl <<
554 		"	_slen = " << CAST(INT(), CSP() + "[" + vCS() + "]") << endl <<
555 		"	if _slen > 0 && " << CK() << "[_keys]" << " <= " << GET_WIDE_KEY() << " && " <<
556 				GET_WIDE_KEY() << " <= " << CK() << "[_keys + 1] {" << endl <<
557 		"		_cond = " << CAST(INT(), C() + "[_conds + " + CAST(INT(), GET_WIDE_KEY() + " - " + CK() + "[_keys]") + "]") << endl <<
558 		"	} else {" << endl <<
559 		"		_cond = 0" << endl <<
560 		"	}" << endl <<
561 		endl;
562 
563 	out <<
564 		"	switch _cond {" << endl;
565 	for ( CondSpaceList::Iter csi = condSpaceList; csi.lte(); csi++ ) {
566 		GenCondSpace *condSpace = csi;
567 		out << "	case " << condSpace->condSpaceId + 1 << ":" << endl;
568 		out << TABS(2) << "_widec = " <<
569 				KEY(condSpace->baseKey) << " + (" << CAST(WIDE_ALPH_TYPE(), GET_KEY()) <<
570 				" - " << KEY(keyOps->minKey) << ")" << endl;
571 
572 		for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
573 			out << TABS(2) << "if ";
574 			CONDITION( out, *csi );
575 			Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize());
576 			out << " {" << endl <<
577 				"			_widec += " << condValOffset << endl <<
578 				"		}" << endl;
579 		}
580 	}
581 
582 	out <<
583 		"	}" << endl;
584 }
585 
writeExec()586 void GoFlatCodeGen::writeExec()
587 {
588 	testEofUsed = false;
589 	outLabelUsed = false;
590 
591 	out <<
592 		"	{" << endl <<
593 		"	var _slen " << INT() << endl;
594 
595 	if ( redFsm->anyRegCurStateRef() )
596 		out << "	var _ps " << INT() << endl;
597 
598 	out <<
599 		"	var _trans " << INT() << endl;
600 
601 	if ( redFsm->anyConditions() )
602 		out << "	var _cond " << INT() << endl;
603 
604 	if ( redFsm->anyToStateActions() ||
605 			redFsm->anyRegActions() || redFsm->anyFromStateActions() )
606 	{
607 		out <<
608 			"	var _acts " << INT() << endl <<
609 			"	var _nacts " << UINT() << endl;
610 	}
611 
612 	out <<
613 		"	var _keys " << INT() << endl <<
614 		"	var _inds " << INT() << endl;
615 
616 	if ( redFsm->anyConditions() ) {
617 		out <<
618 			"	var _conds " << INT() << endl <<
619 			"	var _widec " << WIDE_ALPH_TYPE() << endl;
620 	}
621 
622 	out << endl;
623 
624 	if ( !noEnd ) {
625 		testEofUsed = true;
626 		out <<
627 			"	if " << P() << " == " << PE() << " {" << endl <<
628 			"		goto _test_eof" << endl <<
629 			"	}" << endl;
630 	}
631 
632 	if ( redFsm->errState != 0 ) {
633 		outLabelUsed = true;
634 		out <<
635 			"	if " << vCS() << " == " << redFsm->errState->id << " {" << endl <<
636 			"		goto _out" << endl <<
637 			"	}" << endl;
638 	}
639 
640 	out << "_resume:" << endl;
641 
642 	if ( redFsm->anyFromStateActions() ) {
643 		out <<
644 			"	_acts = " << CAST(INT(), FSA() + "[" + vCS() + "]") << endl <<
645 			"	_nacts = " << CAST(UINT(), A() + "[_acts]") << "; _acts++" << endl <<
646 			"	for ; _nacts > 0; _nacts-- {" << endl <<
647 			"		_acts++" << endl <<
648 			"		switch " << A() << "[_acts - 1]" << " {" << endl;
649 			FROM_STATE_ACTION_SWITCH(2);
650 			out <<
651 			"		}" << endl <<
652 			"	}" << endl <<
653 			endl;
654 	}
655 
656 	if ( redFsm->anyConditions() )
657 		COND_TRANSLATE();
658 
659 	LOCATE_TRANS();
660 
661 	if ( redFsm->anyEofTrans() )
662 		out << "_eof_trans:" << endl;
663 
664 	if ( redFsm->anyRegCurStateRef() )
665 		out << "	_ps = " << vCS() << endl;
666 
667 	out <<
668 		"	" << vCS() << " = " << CAST(INT(), TT() + "[_trans]") << endl <<
669 		endl;
670 
671 	if ( redFsm->anyRegActions() ) {
672 		out <<
673 			"	if " << TA() << "[_trans] == 0 {" << endl <<
674 			"		goto _again" << endl <<
675 			"	}" << endl <<
676 			endl <<
677 			"	_acts = " << CAST(INT(), TA() + "[_trans]") << endl <<
678 			"	_nacts = " << CAST(UINT(), A() + "[_acts]") << "; _acts++" << endl <<
679 			"	for ; _nacts > 0; _nacts-- {" << endl <<
680 			"		_acts++" << endl <<
681 			"		switch " << A() << "[_acts - 1]" << " {" << endl;
682 			ACTION_SWITCH(2);
683 			out <<
684 			"		}" << endl <<
685 			"	}" << endl <<
686 			endl;
687 	}
688 
689 	if ( redFsm->anyRegActions() || redFsm->anyActionGotos() ||
690 			redFsm->anyActionCalls() || redFsm->anyActionRets() )
691 		out << "_again:" << endl;
692 
693 	if ( redFsm->anyToStateActions() ) {
694 		out <<
695 			"	_acts = " << CAST(INT(), TSA() + "[" + vCS() + "]") << endl <<
696 			"	_nacts = " << CAST(UINT(), A() + "[_acts]") << "; _acts++" << endl <<
697 			"	for ; _nacts > 0; _nacts-- {" << endl <<
698 			"		_acts++" << endl <<
699 			"		switch " << A() << "[_acts - 1]" << " {" << endl;
700 			TO_STATE_ACTION_SWITCH(2);
701 			out <<
702 			"		}" << endl <<
703 			"	}" << endl <<
704 			endl;
705 	}
706 
707 	if ( redFsm->errState != 0 ) {
708 		outLabelUsed = true;
709 		out <<
710 			"	if " << vCS() << " == " << redFsm->errState->id << " {" << endl <<
711 			"		goto _out" << endl <<
712 			"	}" << endl;
713 	}
714 
715 	if ( !noEnd ) {
716 		out <<
717 			"	if " << P() << "++; " << P() << " != " << PE() << " {" << endl <<
718 			"		goto _resume" << endl <<
719 			"	}" << endl;
720 	}
721 	else {
722 		out <<
723 			"	" << P() << "++" << endl <<
724 			"	goto _resume" << endl;
725 	}
726 
727 	if ( testEofUsed )
728 		out << "	_test_eof: {}" << endl;
729 
730 	if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
731 		out <<
732 			"	if " << P() << " == " << vEOF() << " {" << endl;
733 
734 		if ( redFsm->anyEofTrans() ) {
735 			out <<
736 				"		if " << ET() << "[" << vCS() << "] > 0 {" << endl <<
737 				"			_trans = " << CAST(INT(), ET() + "[" + vCS() + "] - 1") << endl <<
738 				"			goto _eof_trans" << endl <<
739 				"		}" << endl;
740 		}
741 
742 		if ( redFsm->anyEofActions() ) {
743 			out <<
744 				"		__acts := " << CAST(INT(), EA() + "[" + vCS() + "]") << endl <<
745 				"		__nacts := " << CAST(UINT(), A() + "[__acts]") << "; __acts++" << endl <<
746 				"		for ; __nacts > 0; __nacts-- {" << endl <<
747 				"			__acts++" << endl <<
748 				"			switch " << A() << "[__acts - 1]" << " {" << endl;
749 				EOF_ACTION_SWITCH(3);
750 				out <<
751 				"			}" << endl <<
752 				"		}" << endl;
753 		}
754 
755 		out <<
756 			"	}" << endl <<
757 			endl;
758 	}
759 
760 	if ( outLabelUsed )
761 		out << "	_out: {}" << endl;
762 
763 	out << "	}" << endl;
764 }
765