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