1 /*
2  *  2007 Victor Hugo Borja <vic@rubyforge.org>
3  *  Copyright 2001-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 "rubyfflat.h"
24 
GOTO(ostream & out,int gotoDest,bool inFinish)25 void RubyFFlatCodeGen::GOTO( ostream &out, int gotoDest, bool inFinish )
26 {
27 	out <<
28 		"	begin\n"
29 		"		" << vCS() << " = " << gotoDest << "\n"
30 		"		_goto_level = _again\n"
31 		"		next\n"
32 		"	end\n";
33 }
34 
GOTO_EXPR(ostream & out,GenInlineItem * ilItem,bool inFinish)35 void RubyFFlatCodeGen::GOTO_EXPR( ostream &out, GenInlineItem *ilItem, bool inFinish )
36 {
37 	out <<
38 		"	begin\n"
39 		"		" << vCS() << " = (";
40 	INLINE_LIST( out, ilItem->children, 0, inFinish );
41 	out << ")\n";
42 	out <<
43 		"		_goto_level = _again\n"
44 		"		next\n"
45 		"	end\n";
46 }
47 
CALL(ostream & out,int callDest,int targState,bool inFinish)48 void RubyFFlatCodeGen::CALL( ostream &out, int callDest, int targState, bool inFinish )
49 {
50 	if ( prePushExpr != 0 ) {
51 		out << "begin\n";
52 		INLINE_LIST( out, prePushExpr, 0, false );
53 	}
54 
55 	out <<
56 		"	begin\n"
57 		"		" << STACK() << "[" << TOP() << "] = " << vCS() << "\n"
58 		"		" << TOP() << "+= 1\n"
59 		"		" << vCS() << " = " << callDest << "\n"
60 		"		_goto_level = _again\n"
61 		"		next\n"
62 		"	end\n";
63 
64 	if ( prePushExpr != 0 )
65 		out << "end\n";
66 }
67 
CALL_EXPR(ostream & out,GenInlineItem * ilItem,int targState,bool inFinish)68 void RubyFFlatCodeGen::CALL_EXPR(ostream &out, GenInlineItem *ilItem,
69 		int targState, bool inFinish )
70 {
71 	if ( prePushExpr != 0 ) {
72 		out << "begin\n";
73 		INLINE_LIST( out, prePushExpr, 0, false );
74 	}
75 
76 	out <<
77 		"	begin\n"
78 		"		" << STACK() << "[" << TOP() << "] = " << vCS() << "\n"
79 		"		" << TOP() << " += 1\n"
80 		"		" << vCS() << " = (";
81 	INLINE_LIST( out, ilItem->children, targState, inFinish );
82 	out << ")\n";
83 
84 	out <<
85 		"		_goto_level = _again\n"
86 		"		next\n"
87 		"	end\n";
88 
89 	if ( prePushExpr != 0 )
90 		out << "end\n";
91 }
92 
RET(ostream & out,bool inFinish)93 void RubyFFlatCodeGen::RET( ostream &out, bool inFinish )
94 {
95 	out <<
96 		"	begin\n"
97 		"		" << TOP() << " -= 1\n"
98 		"		" << vCS() << " = " << STACK() << "[" << TOP() << "]\n";
99 
100 	if ( postPopExpr != 0 ) {
101 		out << "begin\n";
102 		INLINE_LIST( out, postPopExpr, 0, false );
103 		out << "end\n";
104 	}
105 
106 	out <<
107 		"		_goto_level = _again\n"
108 		"		next\n"
109 		"	end\n";
110 }
111 
BREAK(ostream & out,int targState)112 void RubyFFlatCodeGen::BREAK( ostream &out, int targState )
113 {
114 	out <<
115 		"	begin\n"
116 		"		" << P() << " += 1\n"
117 		"		_goto_level = _out\n"
118 		"		next\n"
119 		"	end\n";
120 }
121 
122 
TO_STATE_ACTION(RedStateAp * state)123 int RubyFFlatCodeGen::TO_STATE_ACTION( RedStateAp *state )
124 {
125 	int act = 0;
126 	if ( state->toStateAction != 0 )
127 		act = state->toStateAction->actListId+1;
128 	return act;
129 }
130 
FROM_STATE_ACTION(RedStateAp * state)131 int RubyFFlatCodeGen::FROM_STATE_ACTION( RedStateAp *state )
132 {
133 	int act = 0;
134 	if ( state->fromStateAction != 0 )
135 		act = state->fromStateAction->actListId+1;
136 	return act;
137 }
138 
EOF_ACTION(RedStateAp * state)139 int RubyFFlatCodeGen::EOF_ACTION( RedStateAp *state )
140 {
141 	int act = 0;
142 	if ( state->eofAction != 0 )
143 		act = state->eofAction->actListId+1;
144 	return act;
145 }
146 
147 /* Write out the function for a transition. */
TRANS_ACTION(RedTransAp * trans)148 int RubyFFlatCodeGen::TRANS_ACTION( RedTransAp *trans )
149 {
150 	int action = 0;
151 	if ( trans->action != 0 )
152 		action = trans->action->actListId+1;
153 	return action;
154 }
155 
156 /* Write out the function switch. This switch is keyed on the values
157  * of the func index. */
TO_STATE_ACTION_SWITCH()158 std::ostream &RubyFFlatCodeGen::TO_STATE_ACTION_SWITCH()
159 {
160 	/* Loop the actions. */
161 	for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
162 		if ( redAct->numToStateRefs > 0 ) {
163 			/* Write the entry label. */
164 			out << "\twhen " << redAct->actListId+1 << " then\n";
165 
166 			/* Write each action in the list of action items. */
167 			for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
168 				ACTION( out, item->value, 0, false );
169 		}
170 	}
171 
172 	genLineDirective( out );
173 	return out;
174 }
175 
176 /* Write out the function switch. This switch is keyed on the values
177  * of the func index. */
FROM_STATE_ACTION_SWITCH()178 std::ostream &RubyFFlatCodeGen::FROM_STATE_ACTION_SWITCH()
179 {
180 	/* Loop the actions. */
181 	for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
182 		if ( redAct->numFromStateRefs > 0 ) {
183 			/* Write the entry label. */
184 			out << "\twhen " << redAct->actListId+1 << " then\n";
185 
186 			/* Write each action in the list of action items. */
187 			for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
188 				ACTION( out, item->value, 0, false );
189 		}
190 	}
191 
192 	genLineDirective( out );
193 	return out;
194 }
195 
EOF_ACTION_SWITCH()196 std::ostream &RubyFFlatCodeGen::EOF_ACTION_SWITCH()
197 {
198 	/* Loop the actions. */
199 	for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
200 		if ( redAct->numEofRefs > 0 ) {
201 			/* Write the entry label. */
202 			out << "\twhen " << redAct->actListId+1 << " then\n";
203 
204 			/* Write each action in the list of action items. */
205 			for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
206 				ACTION( out, item->value, 0, true );
207 		}
208 	}
209 
210 	genLineDirective( out );
211 	return out;
212 }
213 
214 /* Write out the function switch. This switch is keyed on the values
215  * of the func index. */
ACTION_SWITCH()216 std::ostream &RubyFFlatCodeGen::ACTION_SWITCH()
217 {
218 	/* Loop the actions. */
219 	for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
220 		if ( redAct->numTransRefs > 0 ) {
221 			/* Write the entry label. */
222 			out << "\twhen " << redAct->actListId+1 << " then\n";
223 
224 			/* Write each action in the list of action items. */
225 			for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
226 				ACTION( out, item->value, 0, false );
227 
228 		}
229 	}
230 
231 	genLineDirective( out );
232 	return out;
233 }
234 
writeData()235 void RubyFFlatCodeGen::writeData()
236 {
237 	if ( redFsm->anyConditions() ) {
238 		OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
239 		COND_KEYS();
240 		CLOSE_ARRAY() <<
241 		"\n";
242 
243 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpan), CSP() );
244 		COND_KEY_SPANS();
245 		CLOSE_ARRAY() <<
246 		"\n";
247 
248 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCond), C() );
249 		CONDS();
250 		CLOSE_ARRAY() <<
251 		"\n";
252 
253 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondIndexOffset), CO() );
254 		COND_INDEX_OFFSET();
255 		CLOSE_ARRAY() <<
256 		"\n";
257 	}
258 
259 	OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
260 	KEYS();
261 	CLOSE_ARRAY() <<
262 	"\n";
263 
264 	OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSpan), SP() );
265 	KEY_SPANS();
266 	CLOSE_ARRAY() <<
267 	"\n";
268 
269 	OPEN_ARRAY( ARRAY_TYPE(redFsm->maxFlatIndexOffset), IO() );
270 	FLAT_INDEX_OFFSET();
271 	CLOSE_ARRAY() <<
272 	"\n";
273 
274 	OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
275 	INDICIES();
276 	CLOSE_ARRAY() <<
277 	"\n";
278 
279 	OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
280 	TRANS_TARGS();
281 	CLOSE_ARRAY() <<
282 	"\n";
283 
284 	if ( redFsm->anyActions() ) {
285 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), TA() );
286 		TRANS_ACTIONS();
287 		CLOSE_ARRAY() <<
288 		"\n";
289 	}
290 
291 	if ( redFsm->anyToStateActions() ) {
292 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc),  TSA() );
293 		TO_STATE_ACTIONS();
294 		CLOSE_ARRAY() <<
295 		"\n";
296 	}
297 
298 	if ( redFsm->anyFromStateActions() ) {
299 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
300 		FROM_STATE_ACTIONS();
301 		CLOSE_ARRAY() <<
302 		"\n";
303 	}
304 
305 	if ( redFsm->anyEofActions() ) {
306 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), EA() );
307 		EOF_ACTIONS();
308 		CLOSE_ARRAY() <<
309 		"\n";
310 	}
311 
312 	if ( redFsm->anyEofTrans() ) {
313 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset+1), ET() );
314 		EOF_TRANS();
315 		CLOSE_ARRAY() <<
316 		"\n";
317 	}
318 
319 	STATE_IDS();
320 }
321 
writeExec()322 void RubyFFlatCodeGen::writeExec()
323 {
324 	out <<
325 		"begin\n"
326 		"	testEof = false\n"
327 		"	_slen, _trans, _keys, _inds";
328 	if ( redFsm->anyRegCurStateRef() )
329 		out << ", _ps";
330 	if ( redFsm->anyConditions() )
331 		out << ", _cond, _conds, _widec";
332 	if ( redFsm->anyToStateActions() || redFsm->anyRegActions()
333 			|| redFsm->anyFromStateActions() )
334 		out << ", _acts, _nacts";
335 
336 	out << " = nil\n";
337 
338 	out <<
339 		"	_goto_level = 0\n"
340 		"	_resume = 10\n"
341 		"	_eof_trans = 15\n"
342 		"	_again = 20\n"
343 		"	_test_eof = 30\n"
344 		"	_out = 40\n";
345 
346 	out <<
347 		"	while true\n"
348 		"	if _goto_level <= 0\n";
349 
350 	if ( !noEnd ) {
351 		out <<
352 			"	if " << P() << " == " << PE() << "\n"
353 			"		_goto_level = _test_eof\n"
354 			"		next\n"
355 			"	end\n";
356 	}
357 
358 	if ( redFsm->errState != 0 ) {
359 		out <<
360 			"	if " << vCS() << " == " << redFsm->errState->id << "\n"
361 			"		_goto_level = _out\n"
362 			"		next\n"
363 			"	end\n";
364 	}
365 
366 	/* The resume label. */
367 	out <<
368 		"	end\n"
369 		"	if _goto_level <= _resume\n";
370 
371 	if ( redFsm->anyFromStateActions() ) {
372 		out <<
373 			"	case " << FSA() << "[" << vCS() << "] \n";
374 			FROM_STATE_ACTION_SWITCH() <<
375 			"	end\n";
376 	}
377 
378 	if ( redFsm->anyConditions() )
379 		COND_TRANSLATE();
380 
381 	LOCATE_TRANS();
382 
383 	if ( redFsm->anyEofTrans() ) {
384 		out <<
385 			"	end\n"
386 			"	if _goto_level <= _eof_trans\n";
387 	}
388 
389 	if ( redFsm->anyRegCurStateRef() )
390 		out << "	_ps = " << vCS() << "\n";
391 
392 	out << "	" << vCS() << " = " << TT() << "[_trans]\n";
393 
394 	if ( redFsm->anyRegActions() ) {
395 		/* break _again */
396 		out <<
397 			"	if " << TA() << "[_trans] != 0\n"
398 			"	case " << TA() << "[_trans]" << "\n";
399 			ACTION_SWITCH() <<
400 			"	end\n"
401 			"	end\n";
402 	}
403 
404 	/* The again label. */
405 	out <<
406 		"	end\n"
407 		"	if _goto_level <= _again\n";
408 
409 	if ( redFsm->anyToStateActions() ) {
410 		out <<
411 			"	case " << TSA() << "[" << vCS() << "] \n";
412 			TO_STATE_ACTION_SWITCH() <<
413 			"	end\n"
414 			"\n";
415 	}
416 
417 	if ( redFsm->errState != 0 ) {
418 		out <<
419 			"	if " << vCS() << " == " << redFsm->errState->id << "\n"
420 			"		_goto_level = _out\n"
421 			"		next\n"
422 			"	end\n";
423 	}
424 
425 	out << "	" << P() << " += 1\n";
426 
427 	if ( !noEnd ) {
428 		out <<
429 			"	if " << P() << " != " << PE() << "\n"
430 			"		_goto_level = _resume\n"
431 			"		next\n"
432 			"	end\n";
433 	}
434 	else {
435 		out <<
436 			"	_goto_level = _resume\n"
437 			"	next\n";
438 	}
439 
440 	/* The test eof label. */
441 	out <<
442 		"	end\n"
443 		"	if _goto_level <= _test_eof\n";
444 
445 	if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
446 		out <<
447 			"	if " << P() << " == " << vEOF() << "\n";
448 
449 		if ( redFsm->anyEofTrans() ) {
450 			out <<
451 				"	if " << ET() << "[" << vCS() << "] > 0\n"
452 				"		_trans = " << ET() << "[" << vCS() << "] - 1;\n"
453 				"		_goto_level = _eof_trans\n"
454 				"		next;\n"
455 				"	end\n";
456 		}
457 
458 		if ( redFsm->anyEofActions() ) {
459 			out <<
460 				"	  case " << EA() << "[" << vCS() << "]\n";
461 				EOF_ACTION_SWITCH() <<
462 				"	  end\n";
463 		}
464 
465 		out <<
466 			"	end\n"
467 			"\n";
468 	}
469 
470 	out <<
471 		"	end\n"
472 		"	if _goto_level <= _out\n"
473 		"		break\n"
474 		"	end\n"
475 		"end\n";
476 
477 	/* Wrapping the execute block. */
478 	out << "	end\n";
479 }
480 
481 /*
482  * Local Variables:
483  * mode: c++
484  * indent-tabs-mode: 1
485  * c-file-style: "bsd"
486  * End:
487  */
488 
489