1 /*
2  *  Copyright 2007 Victor Hugo Borja <vic@rubyforge.org>
3  *            2007 Adrian Thurston <thurston@complang.org>
4  */
5 
6 /*  This file is part of Ragel.
7  *
8  *  Ragel is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  Ragel is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with Ragel; if not, write to the Free Software
20  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22 
23 #include <iomanip>
24 #include <sstream>
25 #include "redfsm.h"
26 #include "gendata.h"
27 #include "ragel.h"
28 #include "rubytable.h"
29 
30 using std::ostream;
31 using std::ostringstream;
32 using std::string;
33 using std::cerr;
34 using std::endl;
35 
36 
37 
GOTO(ostream & out,int gotoDest,bool inFinish)38 void RubyTabCodeGen::GOTO( ostream &out, int gotoDest, bool inFinish )
39 {
40 	out <<
41 		"	begin\n"
42 		"		" << vCS() << " = " << gotoDest << "\n"
43 		"		_trigger_goto = true\n"
44 		"		_goto_level = _again\n"
45 		"		break\n"
46 		"	end\n";
47 }
48 
GOTO_EXPR(ostream & out,GenInlineItem * ilItem,bool inFinish)49 void RubyTabCodeGen::GOTO_EXPR( ostream &out, GenInlineItem *ilItem, bool inFinish )
50 {
51 	out <<
52 		"	begin\n"
53 		"		" << vCS() << " = (";
54 	INLINE_LIST( out, ilItem->children, 0, inFinish );
55 	out << ")\n";
56 	out <<
57 		"		_trigger_goto = true\n"
58 		"		_goto_level = _again\n"
59 		"		break\n"
60 		"	end\n";
61 }
62 
CALL(ostream & out,int callDest,int targState,bool inFinish)63 void RubyTabCodeGen::CALL( ostream &out, int callDest, int targState, bool inFinish )
64 {
65 	if ( prePushExpr != 0 ) {
66 		out << "begin\n";
67 		INLINE_LIST( out, prePushExpr, 0, false );
68 	}
69 
70 	out <<
71 		"	begin\n"
72 		"		" << STACK() << "[" << TOP() << "] = " << vCS() << "\n"
73 		"		" << TOP() << "+= 1\n"
74 		"		" << vCS() << " = " << callDest << "\n"
75 		"		_trigger_goto = true\n"
76 		"		_goto_level = _again\n"
77 		"		break\n"
78 		"	end\n";
79 
80 	if ( prePushExpr != 0 )
81 		out << "end\n";
82 }
83 
CALL_EXPR(ostream & out,GenInlineItem * ilItem,int targState,bool inFinish)84 void RubyTabCodeGen::CALL_EXPR(ostream &out, GenInlineItem *ilItem, int targState, bool inFinish )
85 {
86 	if ( prePushExpr != 0 ) {
87 		out << "begin\n";
88 		INLINE_LIST( out, prePushExpr, 0, false );
89 	}
90 
91 	out <<
92 		"	begin\n"
93 		"		" << STACK() << "[" << TOP() << "] = " << vCS() << "\n"
94 		"		" << TOP() << " += 1\n"
95 		"		" << vCS() << " = (";
96 	INLINE_LIST( out, ilItem->children, targState, inFinish );
97 	out << ")\n";
98 
99 	out <<
100 		"		_trigger_goto = true\n"
101 		"		_goto_level = _again\n"
102 		"		break\n"
103 		"	end\n";
104 
105 	if ( prePushExpr != 0 )
106 		out << "end\n";
107 }
108 
RET(ostream & out,bool inFinish)109 void RubyTabCodeGen::RET( ostream &out, bool inFinish )
110 {
111 	out <<
112 		"	begin\n"
113 		"		" << TOP() << " -= 1\n"
114 		"		" << vCS() << " = " << STACK() << "[" << TOP() << "]\n";
115 
116 	if ( postPopExpr != 0 ) {
117 		out << "begin\n";
118 		INLINE_LIST( out, postPopExpr, 0, false );
119 		out << "end\n";
120 	}
121 
122 	out <<
123 		"		_trigger_goto = true\n"
124 		"		_goto_level = _again\n"
125 		"		break\n"
126 		"	end\n";
127 }
128 
BREAK(ostream & out,int targState)129 void RubyTabCodeGen::BREAK( ostream &out, int targState )
130 {
131 	out <<
132 		"	begin\n"
133 		"		" << P() << " += 1\n"
134 		"		_trigger_goto = true\n"
135 		"		_goto_level = _out\n"
136 		"		break\n"
137 		"	end\n";
138 }
139 
COND_TRANSLATE()140 void RubyTabCodeGen::COND_TRANSLATE()
141 {
142 	out <<
143 		"	_widec = " << GET_KEY() << "\n"
144 		"	_keys = " << CO() << "[" << vCS() << "]*2\n"
145 		"	_klen = " << CL() << "[" << vCS() << "]\n"
146 		"	if _klen > 0\n"
147 		"		_lower = _keys\n"
148 		"		_upper = _keys + (_klen<<1) - 2\n"
149 		"		loop do\n"
150 		"			break if _upper < _lower\n"
151 		"			_mid = _lower + (((_upper-_lower) >> 1) & ~1)\n"
152 		"			if " << GET_WIDE_KEY() << " < " << CK() << "[_mid]\n"
153 		"				_upper = _mid - 2\n"
154 		"			elsif " << GET_WIDE_KEY() << " > " << CK() << "[_mid+1]\n"
155 		"				_lower = _mid + 2\n"
156 		"			else\n"
157 		"				case " << C() << "[" << CO() << "[" << vCS() << "]"
158 							" + ((_mid - _keys)>>1)]\n";
159 
160 	for ( CondSpaceList::Iter csi = condSpaceList; csi.lte(); csi++ ) {
161 		GenCondSpace *condSpace = csi;
162 		out << "	when " << condSpace->condSpaceId << " then" ;
163 		out << "	_widec = " << KEY(condSpace->baseKey) <<
164 				"+ (" << GET_KEY() << " - " << KEY(keyOps->minKey) << ")\n";
165 
166 		for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
167 			Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize());
168 			out << "	_widec += " << condValOffset << " if ( ";
169 			CONDITION( out, *csi );
170 			out << " )\n";
171 		}
172 	}
173 
174 	out <<
175 		"				end # case\n"
176 		"			end\n"
177 		"		end # loop\n"
178 		"	end\n";
179 }
180 
181 
LOCATE_TRANS()182 void RubyTabCodeGen::LOCATE_TRANS()
183 {
184 	out <<
185 		"	_keys = " << KO() << "[" << vCS() << "]\n"
186 		"	_trans = " << IO() << "[" << vCS() << "]\n"
187 		"	_klen = " << SL() << "[" << vCS() << "]\n"
188 		"	_break_match = false\n"
189 		"	\n"
190 		"	begin\n"
191 		"	  if _klen > 0\n"
192 		"	     _lower = _keys\n"
193 		"	     _upper = _keys + _klen - 1\n"
194 		"\n"
195 		"	     loop do\n"
196 		"	        break if _upper < _lower\n"
197 		"	        _mid = _lower + ( (_upper - _lower) >> 1 )\n"
198 		"\n"
199 		"	        if " << GET_WIDE_KEY() << " < " << K() << "[_mid]\n"
200 		"	           _upper = _mid - 1\n"
201 		"	        elsif " << GET_WIDE_KEY() << " > " << K() << "[_mid]\n"
202 		"	           _lower = _mid + 1\n"
203 		"	        else\n"
204 		"	           _trans += (_mid - _keys)\n"
205 		"	           _break_match = true\n"
206 		"	           break\n"
207 		"	        end\n"
208 		"	     end # loop\n"
209 		"	     break if _break_match\n"
210 		"	     _keys += _klen\n"
211 		"	     _trans += _klen\n"
212 		"	  end"
213 		"\n"
214 		"	  _klen = " << RL() << "[" << vCS() << "]\n"
215 		"	  if _klen > 0\n"
216 		"	     _lower = _keys\n"
217 		"	     _upper = _keys + (_klen << 1) - 2\n"
218 		"	     loop do\n"
219 		"	        break if _upper < _lower\n"
220 		"	        _mid = _lower + (((_upper-_lower) >> 1) & ~1)\n"
221 		"	        if " << GET_WIDE_KEY() << " < " << K() << "[_mid]\n"
222 		"	          _upper = _mid - 2\n"
223 		"	        elsif " << GET_WIDE_KEY() << " > " << K() << "[_mid+1]\n"
224 		"	          _lower = _mid + 2\n"
225 		"	        else\n"
226 		"	          _trans += ((_mid - _keys) >> 1)\n"
227 		"	          _break_match = true\n"
228 		"	          break\n"
229 		"	        end\n"
230 		"	     end # loop\n"
231 		"	     break if _break_match\n"
232 		"	     _trans += _klen\n"
233 		"	  end\n"
234 		"	end while false\n";
235 }
236 
writeExec()237 void RubyTabCodeGen::writeExec()
238 {
239 	out <<
240 		"begin\n"
241 		"	_klen, _trans, _keys";
242 
243 	if ( redFsm->anyRegCurStateRef() )
244 		out << ", _ps";
245 	if ( redFsm->anyConditions() )
246 		out << ", _widec";
247 	if ( redFsm->anyToStateActions() || redFsm->anyRegActions()
248 			|| redFsm->anyFromStateActions() )
249 		out << ", _acts, _nacts";
250 
251 	out << " = nil\n";
252 
253 	out <<
254 		"	_goto_level = 0\n"
255 		"	_resume = 10\n"
256 		"	_eof_trans = 15\n"
257 		"	_again = 20\n"
258 		"	_test_eof = 30\n"
259 		"	_out = 40\n";
260 
261 	out <<
262 		"	while true\n"
263 		"	_trigger_goto = false\n"
264 		"	if _goto_level <= 0\n";
265 
266 	if ( !noEnd ) {
267 		out <<
268 			"	if " << P() << " == " << PE() << "\n"
269 			"		_goto_level = _test_eof\n"
270 			"		next\n"
271 			"	end\n";
272 	}
273 
274 	if ( redFsm->errState != 0 ) {
275 		out <<
276 			"	if " << vCS() << " == " << redFsm->errState->id << "\n"
277 			"		_goto_level = _out\n"
278 			"		next\n"
279 			"	end\n";
280 	}
281 
282 	/* The resume label. */
283 	out <<
284 		"	end\n"
285 		"	if _goto_level <= _resume\n";
286 
287 	if ( redFsm->anyFromStateActions() ) {
288 		out <<
289 			"	_acts = " << FSA() << "[" << vCS() << "]\n"
290 			"	_nacts = " << A() << "[_acts]\n"
291 			"	_acts += 1\n"
292 			"	while _nacts > 0\n"
293 			"		_nacts -= 1\n"
294 			"		_acts += 1\n"
295 			"		case " << A() << "[_acts - 1]\n";
296 		FROM_STATE_ACTION_SWITCH();
297 		out <<
298 			"		end # from state action switch\n"
299 			"	end\n"
300 			"	if _trigger_goto\n"
301 			"		next\n"
302 			"	end\n";
303 	}
304 
305 	if ( redFsm->anyConditions() )
306 		COND_TRANSLATE();
307 
308 	LOCATE_TRANS();
309 
310 	if ( useIndicies )
311 		out << "	_trans = " << I() << "[_trans]\n";
312 
313 	if ( redFsm->anyEofTrans() ) {
314 		out <<
315 			"	end\n"
316 			"	if _goto_level <= _eof_trans\n";
317 	}
318 
319 	if ( redFsm->anyRegCurStateRef() )
320 		out << "	_ps = " << vCS() << "\n";
321 
322 	out << "	" << vCS() << " = " << TT() << "[_trans]\n";
323 
324 	if ( redFsm->anyRegActions() ) {
325 		out <<
326 			"	if " << TA() << "[_trans] != 0\n"
327 			"		_acts = " << TA() << "[_trans]\n"
328 			"		_nacts = " << A() << "[_acts]\n"
329 			"		_acts += 1\n"
330 			"		while _nacts > 0\n"
331 			"			_nacts -= 1\n"
332 			"			_acts += 1\n"
333 			"			case " << A() << "[_acts - 1]\n";
334 		ACTION_SWITCH();
335 		out <<
336 			"			end # action switch\n"
337 			"		end\n"
338 			"	end\n"
339 			"	if _trigger_goto\n"
340 			"		next\n"
341 			"	end\n";
342 	}
343 
344 	/* The again label. */
345 	out <<
346 		"	end\n"
347 		"	if _goto_level <= _again\n";
348 
349 	if ( redFsm->anyToStateActions() ) {
350 		out <<
351 			"	_acts = " << TSA() << "["  << vCS() << "]\n"
352 			"	_nacts = " << A() << "[_acts]\n"
353 			"	_acts += 1\n"
354 			"	while _nacts > 0\n"
355 			"		_nacts -= 1\n"
356 			"		_acts += 1\n"
357 			"		case " << A() << "[_acts - 1]\n";
358 		TO_STATE_ACTION_SWITCH();
359 		out <<
360 			"		end # to state action switch\n"
361 			"	end\n"
362 			"	if _trigger_goto\n"
363 			"		next\n"
364 			"	end\n";
365 	}
366 
367 	if ( redFsm->errState != 0 ) {
368 		out <<
369 			"	if " << vCS() << " == " << redFsm->errState->id << "\n"
370 			"		_goto_level = _out\n"
371 			"		next\n"
372 			"	end\n";
373 	}
374 
375 	out << "	" << P() << " += 1\n";
376 
377 	if ( !noEnd ) {
378 		out <<
379 			"	if " << P() << " != " << PE() << "\n"
380 			"		_goto_level = _resume\n"
381 			"		next\n"
382 			"	end\n";
383 	}
384 	else {
385 		out <<
386 			"	_goto_level = _resume\n"
387 			"	next\n";
388 	}
389 
390 	/* The test_eof label. */
391 	out <<
392 		"	end\n"
393 		"	if _goto_level <= _test_eof\n";
394 
395 	if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
396 		out <<
397 			"	if " << P() << " == " << vEOF() << "\n";
398 
399 		if ( redFsm->anyEofTrans() ) {
400 			out <<
401 				"	if " << ET() << "[" << vCS() << "] > 0\n"
402 				"		_trans = " << ET() << "[" << vCS() << "] - 1;\n"
403 				"		_goto_level = _eof_trans\n"
404 				"		next;\n"
405 				"	end\n";
406 		}
407 
408 		if ( redFsm->anyEofActions() ) {
409 			out <<
410 				"	__acts = " << EA() << "[" << vCS() << "]\n"
411 				"	__nacts = " << " " << A() << "[__acts]\n"
412 				"	__acts += 1\n"
413 				"	while __nacts > 0\n"
414 				"		__nacts -= 1\n"
415 				"		__acts += 1\n"
416 				"		case " << A() << "[__acts - 1]\n";
417 			EOF_ACTION_SWITCH() <<
418 				"		end # eof action switch\n"
419 				"	end\n"
420 				"	if _trigger_goto\n"
421 				"		next\n"
422 				"	end\n";
423 		}
424 
425 		out <<
426 			"end\n";
427 	}
428 
429 	out <<
430 		"	end\n"
431 		"	if _goto_level <= _out\n"
432 		"		break\n"
433 		"	end\n";
434 
435 	/* The loop for next. */
436 	out <<
437 		"	end\n";
438 
439 	/* Wrapping the execute block. */
440 	out <<
441 		"	end\n";
442 }
443 
FROM_STATE_ACTION_SWITCH()444 std::ostream &RubyTabCodeGen::FROM_STATE_ACTION_SWITCH()
445 {
446 	/* Walk the list of functions, printing the cases. */
447 	for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
448 		/* Write out referenced actions. */
449 		if ( act->numFromStateRefs > 0 ) {
450 			/* Write the case label, the action */
451 			out << "			when " << act->actionId << " then\n";
452 			ACTION( out, act, 0, false );
453 		}
454 	}
455 
456 	genLineDirective( out );
457 	return out;
458 }
459 
460 
TO_STATE_ACTION_SWITCH()461 std::ostream &RubyTabCodeGen::TO_STATE_ACTION_SWITCH()
462 {
463 	/* Walk the list of functions, printing the cases. */
464 	for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
465 		/* Write out referenced actions. */
466 		if ( act->numToStateRefs > 0 ) {
467 			/* Write the case label, the action and the case break. */
468 			out << "when " << act->actionId << " then\n";
469 			ACTION( out, act, 0, false );
470 		}
471 	}
472 
473 	genLineDirective( out );
474 	return out;
475 }
476 
EOF_ACTION_SWITCH()477 std::ostream &RubyTabCodeGen::EOF_ACTION_SWITCH()
478 {
479 	/* Walk the list of functions, printing the cases. */
480 	for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
481 		/* Write out referenced actions. */
482 		if ( act->numEofRefs > 0 ) {
483 			/* Write the case label, the action and the case break. */
484 			out << "when " << act->actionId << " then\n";
485 			ACTION( out, act, 0, true );
486 		}
487 	}
488 
489 	genLineDirective( out );
490 	return out;
491 }
492 
ACTION_SWITCH()493 std::ostream &RubyTabCodeGen::ACTION_SWITCH()
494 {
495 	/* Walk the list of functions, printing the cases. */
496 	for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
497 		/* Write out referenced actions. */
498 		if ( act->numTransRefs > 0 ) {
499 			/* Write the case label, the action and the case break. */
500 			out << "when " << act->actionId << " then\n";
501 			ACTION( out, act, 0, false );
502 		}
503 	}
504 
505 	genLineDirective( out );
506 	return out;
507 }
508 
509 
NEXT(ostream & ret,int nextDest,bool inFinish)510 void RubyTabCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
511 {
512 	ret << vCS() << " = " << nextDest << ";";
513 }
514 
NEXT_EXPR(ostream & ret,GenInlineItem * ilItem,bool inFinish)515 void RubyTabCodeGen::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
516 {
517 	ret << vCS() << " = (";
518 	INLINE_LIST( ret, ilItem->children, 0, inFinish );
519 	ret << ");";
520 }
521 
522 
TO_STATE_ACTION(RedStateAp * state)523 int RubyTabCodeGen::TO_STATE_ACTION( RedStateAp *state )
524 {
525 	int act = 0;
526 	if ( state->toStateAction != 0 )
527 		act = state->toStateAction->location+1;
528 	return act;
529 }
530 
FROM_STATE_ACTION(RedStateAp * state)531 int RubyTabCodeGen::FROM_STATE_ACTION( RedStateAp *state )
532 {
533 	int act = 0;
534 	if ( state->fromStateAction != 0 )
535 		act = state->fromStateAction->location+1;
536 	return act;
537 }
538 
EOF_ACTION(RedStateAp * state)539 int RubyTabCodeGen::EOF_ACTION( RedStateAp *state )
540 {
541 	int act = 0;
542 	if ( state->eofAction != 0 )
543 		act = state->eofAction->location+1;
544 	return act;
545 }
546 
547 
COND_OFFSETS()548 std::ostream &RubyTabCodeGen::COND_OFFSETS()
549 {
550 	START_ARRAY_LINE();
551 	int totalStateNum = 0, curKeyOffset = 0;
552 	for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
553 		/* Write the key offset. */
554 		ARRAY_ITEM( INT(curKeyOffset), ++totalStateNum, st.last() );
555 
556 		/* Move the key offset ahead. */
557 		curKeyOffset += st->stateCondList.length();
558 	}
559 	END_ARRAY_LINE();
560 	return out;
561 }
562 
KEY_OFFSETS()563 std::ostream &RubyTabCodeGen::KEY_OFFSETS()
564 {
565 	START_ARRAY_LINE();
566 	int totalStateNum = 0, curKeyOffset = 0;
567 	for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
568 		/* Write the key offset. */
569 		ARRAY_ITEM( INT(curKeyOffset), ++totalStateNum, st.last() );
570 
571 		/* Move the key offset ahead. */
572 		curKeyOffset += st->outSingle.length() + st->outRange.length()*2;
573 	}
574 	END_ARRAY_LINE();
575 	return out;
576 }
577 
578 
INDEX_OFFSETS()579 std::ostream &RubyTabCodeGen::INDEX_OFFSETS()
580 {
581 	START_ARRAY_LINE();
582 	int totalStateNum = 0, curIndOffset = 0;
583 	for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
584 		/* Write the index offset. */
585 		ARRAY_ITEM( INT(curIndOffset), ++totalStateNum, st.last() );
586 
587 		/* Move the index offset ahead. */
588 		curIndOffset += st->outSingle.length() + st->outRange.length();
589 		if ( st->defTrans != 0 )
590 			curIndOffset += 1;
591 	}
592 	END_ARRAY_LINE();
593 	return out;
594 }
595 
COND_LENS()596 std::ostream &RubyTabCodeGen::COND_LENS()
597 {
598 	START_ARRAY_LINE();
599 	int totalStateNum = 0;
600 	for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
601 		/* Write singles length. */
602 		ARRAY_ITEM( INT(st->stateCondList.length()), ++totalStateNum, st.last() );
603 	}
604 	END_ARRAY_LINE();
605 	return out;
606 }
607 
608 
SINGLE_LENS()609 std::ostream &RubyTabCodeGen::SINGLE_LENS()
610 {
611 	START_ARRAY_LINE();
612 	int totalStateNum = 0;
613 	for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
614 		/* Write singles length. */
615 		ARRAY_ITEM( INT(st->outSingle.length()), ++totalStateNum, st.last() );
616 	}
617 	END_ARRAY_LINE();
618 	return out;
619 }
620 
RANGE_LENS()621 std::ostream &RubyTabCodeGen::RANGE_LENS()
622 {
623 	START_ARRAY_LINE();
624 	int totalStateNum = 0;
625 	for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
626 		/* Emit length of range index. */
627 		ARRAY_ITEM( INT(st->outRange.length()), ++totalStateNum, st.last() );
628 	}
629 	END_ARRAY_LINE();
630 	return out;
631 }
632 
TO_STATE_ACTIONS()633 std::ostream &RubyTabCodeGen::TO_STATE_ACTIONS()
634 {
635 	START_ARRAY_LINE();
636 	int totalStateNum = 0;
637 	for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
638 		/* Write any eof action. */
639 		ARRAY_ITEM( INT(TO_STATE_ACTION(st)), ++totalStateNum, st.last() );
640 	}
641 	END_ARRAY_LINE();
642 	return out;
643 }
644 
FROM_STATE_ACTIONS()645 std::ostream &RubyTabCodeGen::FROM_STATE_ACTIONS()
646 {
647 	START_ARRAY_LINE();
648 	int totalStateNum = 0;
649 	for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
650 		/* Write any eof action. */
651 		ARRAY_ITEM( INT(FROM_STATE_ACTION(st)), ++totalStateNum, st.last() );
652 	}
653 	END_ARRAY_LINE();
654 	return out;
655 }
656 
EOF_ACTIONS()657 std::ostream &RubyTabCodeGen::EOF_ACTIONS()
658 {
659 	START_ARRAY_LINE();
660 	int totalStateNum = 0;
661 	for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
662 		/* Write any eof action. */
663 		ARRAY_ITEM( INT(EOF_ACTION(st)), ++totalStateNum, st.last() );
664 	}
665 	END_ARRAY_LINE();
666 	return out;
667 }
668 
EOF_TRANS()669 std::ostream &RubyTabCodeGen::EOF_TRANS()
670 {
671 	START_ARRAY_LINE();
672 	int totalStateNum = 0;
673 	for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
674 		/* Write any eof action. */
675 		long trans = 0;
676 		if ( st->eofTrans != 0 ) {
677 			assert( st->eofTrans->pos >= 0 );
678 			trans = st->eofTrans->pos+1;
679 		}
680 
681 		/* Write any eof action. */
682 		ARRAY_ITEM( INT(trans), ++totalStateNum, st.last() );
683 	}
684 	END_ARRAY_LINE();
685 	return out;
686 }
687 
COND_KEYS()688 std::ostream &RubyTabCodeGen::COND_KEYS()
689 {
690 	START_ARRAY_LINE();
691 	int totalTrans = 0;
692 	for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
693 		/* Loop the state's transitions. */
694 		for ( GenStateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
695 			/* Lower key. */
696 			ARRAY_ITEM( KEY( sc->lowKey ), ++totalTrans, false );
697 			ARRAY_ITEM( KEY( sc->highKey ), ++totalTrans, false );
698 		}
699 	}
700 
701 	/* Output one last number so we don't have to figure out when the last
702 	 * entry is and avoid writing a comma. */
703 	ARRAY_ITEM( INT(0), ++totalTrans, true );
704 	END_ARRAY_LINE();
705 	return out;
706 }
707 
COND_SPACES()708 std::ostream &RubyTabCodeGen::COND_SPACES()
709 {
710 	START_ARRAY_LINE();
711 	int totalTrans = 0;
712 	for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
713 		/* Loop the state's transitions. */
714 		for ( GenStateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
715 			/* Cond Space id. */
716 			ARRAY_ITEM( KEY( sc->condSpace->condSpaceId ), ++totalTrans, false );
717 		}
718 	}
719 
720 	/* Output one last number so we don't have to figure out when the last
721 	 * entry is and avoid writing a comma. */
722 	ARRAY_ITEM( INT(0), ++totalTrans, true );
723 	END_ARRAY_LINE();
724 	return out;
725 }
726 
KEYS()727 std::ostream &RubyTabCodeGen::KEYS()
728 {
729 	START_ARRAY_LINE();
730 	int totalTrans = 0;
731 	for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
732 		/* Loop the singles. */
733 		for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
734 			ARRAY_ITEM( KEY( stel->lowKey ), ++totalTrans, false );
735 		}
736 
737 		/* Loop the state's transitions. */
738 		for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
739 			/* Lower key. */
740 			ARRAY_ITEM( KEY( rtel->lowKey ), ++totalTrans, false );
741 
742 			/* Upper key. */
743 			ARRAY_ITEM( KEY( rtel->highKey ), ++totalTrans, false );
744 		}
745 	}
746 
747 	/* Output one last number so we don't have to figure out when the last
748 	 * entry is and avoid writing a comma. */
749 	ARRAY_ITEM( INT(0), ++totalTrans, true );
750 	END_ARRAY_LINE();
751 	return out;
752 }
753 
INDICIES()754 std::ostream &RubyTabCodeGen::INDICIES()
755 {
756 	int totalTrans = 0;
757 	START_ARRAY_LINE();
758 	for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
759 		/* Walk the singles. */
760 		for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
761 			ARRAY_ITEM( KEY( stel->value->id ), ++totalTrans, false );
762 		}
763 
764 		/* Walk the ranges. */
765 		for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
766 			ARRAY_ITEM( KEY( rtel->value->id ), ++totalTrans, false );
767 		}
768 
769 		/* The state's default index goes next. */
770 		if ( st->defTrans != 0 ) {
771 			ARRAY_ITEM( KEY( st->defTrans->id ), ++totalTrans, false );
772 		}
773 	}
774 
775 	/* Output one last number so we don't have to figure out when the last
776 	 * entry is and avoid writing a comma. */
777 	ARRAY_ITEM( INT(0), ++totalTrans, true );
778 	END_ARRAY_LINE();
779 	return out;
780 }
781 
TRANS_TARGS()782 std::ostream &RubyTabCodeGen::TRANS_TARGS()
783 {
784 	int totalTrans = 0;
785 	START_ARRAY_LINE();
786 	for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
787 		/* Walk the singles. */
788 		for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
789 			RedTransAp *trans = stel->value;
790 			ARRAY_ITEM( KEY( trans->targ->id ), ++totalTrans, false );
791 		}
792 
793 		/* Walk the ranges. */
794 		for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
795 			RedTransAp *trans = rtel->value;
796 			ARRAY_ITEM( KEY( trans->targ->id ), ++totalTrans, false );
797 		}
798 
799 		/* The state's default target state. */
800 		if ( st->defTrans != 0 ) {
801 			RedTransAp *trans = st->defTrans;
802 			ARRAY_ITEM( KEY( trans->targ->id ), ++totalTrans, false );
803 		}
804 	}
805 
806 	for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
807 		if ( st->eofTrans != 0 ) {
808 			RedTransAp *trans = st->eofTrans;
809 			trans->pos = totalTrans;
810 			ARRAY_ITEM( KEY( trans->targ->id ), ++totalTrans, false );
811 		}
812 	}
813 
814 	/* Output one last number so we don't have to figure out when the last
815 	 * entry is and avoid writing a comma. */
816 	ARRAY_ITEM( INT(0), ++totalTrans, true );
817 	END_ARRAY_LINE();
818 	return out;
819 }
820 
821 
TRANS_ACTIONS()822 std::ostream &RubyTabCodeGen::TRANS_ACTIONS()
823 {
824 	int totalTrans = 0;
825 	START_ARRAY_LINE();
826 	for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
827 		/* Walk the singles. */
828 		for ( RedTransList::Iter stel = st->outSingle; stel.lte(); stel++ ) {
829 			RedTransAp *trans = stel->value;
830 			ARRAY_ITEM( INT(TRANS_ACTION( trans )), ++totalTrans, false );
831 		}
832 
833 		/* Walk the ranges. */
834 		for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
835 			RedTransAp *trans = rtel->value;
836 			ARRAY_ITEM( INT(TRANS_ACTION( trans )), ++totalTrans, false );
837 		}
838 
839 		/* The state's default index goes next. */
840 		if ( st->defTrans != 0 ) {
841 			RedTransAp *trans = st->defTrans;
842 			ARRAY_ITEM( INT(TRANS_ACTION( trans )), ++totalTrans, false );
843 		}
844 	}
845 
846 	for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
847 		if ( st->eofTrans != 0 ) {
848 			RedTransAp *trans = st->eofTrans;
849 			ARRAY_ITEM( INT(TRANS_ACTION( trans )), ++totalTrans, false );
850 		}
851 	}
852 
853 	/* Output one last number so we don't have to figure out when the last
854 	 * entry is and avoid writing a comma. */
855 	ARRAY_ITEM( INT(0), ++totalTrans, true );
856 	END_ARRAY_LINE();
857 	return out;
858 }
859 
TRANS_TARGS_WI()860 std::ostream &RubyTabCodeGen::TRANS_TARGS_WI()
861 {
862 	/* Transitions must be written ordered by their id. */
863 	RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
864 	for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
865 		transPtrs[trans->id] = trans;
866 
867 	/* Keep a count of the num of items in the array written. */
868 	START_ARRAY_LINE();
869 	int totalStates = 0;
870 	for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
871 		/* Save the position. Needed for eofTargs. */
872 		RedTransAp *trans = transPtrs[t];
873 		trans->pos = t;
874 
875 		/* Write out the target state. */
876 		ARRAY_ITEM( INT(trans->targ->id), ++totalStates, ( t >= redFsm->transSet.length()-1 ) );
877 	}
878 	END_ARRAY_LINE();
879 	delete[] transPtrs;
880 	return out;
881 }
882 
883 
TRANS_ACTIONS_WI()884 std::ostream &RubyTabCodeGen::TRANS_ACTIONS_WI()
885 {
886 	/* Transitions must be written ordered by their id. */
887 	RedTransAp **transPtrs = new RedTransAp*[redFsm->transSet.length()];
888 	for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ )
889 		transPtrs[trans->id] = trans;
890 
891 	/* Keep a count of the num of items in the array written. */
892 	START_ARRAY_LINE();
893 	int totalAct = 0;
894 	for ( int t = 0; t < redFsm->transSet.length(); t++ ) {
895 		/* Write the function for the transition. */
896 		RedTransAp *trans = transPtrs[t];
897 		ARRAY_ITEM( INT(TRANS_ACTION( trans )), ++totalAct,
898 				( t >= redFsm->transSet.length()-1 ) );
899 	}
900 	END_ARRAY_LINE();
901 	delete[] transPtrs;
902 	return out;
903 }
904 
905 
writeData()906 void RubyTabCodeGen::writeData()
907 {
908 	/* If there are any transtion functions then output the array. If there
909 	 * are none, don't bother emitting an empty array that won't be used. */
910 	if ( redFsm->anyActions() ) {
911 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
912 		ACTIONS_ARRAY();
913 		CLOSE_ARRAY() <<
914 		"\n";
915 	}
916 
917 	if ( redFsm->anyConditions() ) {
918 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondOffset), CO() );
919 		COND_OFFSETS();
920 		CLOSE_ARRAY() <<
921 		"\n";
922 
923 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondLen), CL() );
924 		COND_LENS();
925 		CLOSE_ARRAY() <<
926 		"\n";
927 
928 		OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
929 		COND_KEYS();
930 		CLOSE_ARRAY() <<
931 		"\n";
932 
933 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpaceId), C() );
934 		COND_SPACES();
935 		CLOSE_ARRAY() <<
936 		"\n";
937 	}
938 
939 	OPEN_ARRAY( ARRAY_TYPE(redFsm->maxKeyOffset), KO() );
940 	KEY_OFFSETS();
941 	CLOSE_ARRAY() <<
942 	"\n";
943 
944 	OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
945 	KEYS();
946 	CLOSE_ARRAY() <<
947 	"\n";
948 
949 	OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSingleLen), SL() );
950 	SINGLE_LENS();
951 	CLOSE_ARRAY() <<
952 	"\n";
953 
954 	OPEN_ARRAY( ARRAY_TYPE(redFsm->maxRangeLen), RL() );
955 	RANGE_LENS();
956 	CLOSE_ARRAY() <<
957 	"\n";
958 
959 	OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset), IO() );
960 	INDEX_OFFSETS();
961 	CLOSE_ARRAY() <<
962 	"\n";
963 
964 	if ( useIndicies ) {
965 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
966 		INDICIES();
967 		CLOSE_ARRAY() <<
968 		"\n";
969 
970 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
971 		TRANS_TARGS_WI();
972 		CLOSE_ARRAY() <<
973 		"\n";
974 
975 		if ( redFsm->anyActions() ) {
976 			OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
977 			TRANS_ACTIONS_WI();
978 			CLOSE_ARRAY() <<
979 			"\n";
980 		}
981 	}
982 	else {
983 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
984 		TRANS_TARGS();
985 		CLOSE_ARRAY() <<
986 		"\n";
987 
988 		if ( redFsm->anyActions() ) {
989 			OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TA() );
990 			TRANS_ACTIONS();
991 			CLOSE_ARRAY() <<
992 			"\n";
993 		}
994 	}
995 
996 	if ( redFsm->anyToStateActions() ) {
997 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
998 		TO_STATE_ACTIONS();
999 		CLOSE_ARRAY() <<
1000 		"\n";
1001 	}
1002 
1003 	if ( redFsm->anyFromStateActions() ) {
1004 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
1005 		FROM_STATE_ACTIONS();
1006 		CLOSE_ARRAY() <<
1007 		"\n";
1008 	}
1009 
1010 	if ( redFsm->anyEofActions() ) {
1011 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
1012 		EOF_ACTIONS();
1013 		CLOSE_ARRAY() <<
1014 		"\n";
1015 	}
1016 
1017 	if ( redFsm->anyEofTrans() ) {
1018 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset+1), ET() );
1019 		EOF_TRANS();
1020 		CLOSE_ARRAY() <<
1021 		"\n";
1022 	}
1023 
1024 	STATE_IDS();
1025 }
1026 
1027 /*
1028  Local Variables:
1029  mode: c++
1030  indent-tabs-mode: 1
1031  c-file-style: "bsd"
1032  End:
1033  */
1034