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 "gofflat.h"
26 #include "redfsm.h"
27 #include "gendata.h"
28 
29 using std::endl;
30 
TO_STATE_ACTION(RedStateAp * state)31 std::ostream &GoFFlatCodeGen::TO_STATE_ACTION( RedStateAp *state )
32 {
33 	int act = 0;
34 	if ( state->toStateAction != 0 )
35 		act = state->toStateAction->actListId+1;
36 	out << act;
37 	return out;
38 }
39 
FROM_STATE_ACTION(RedStateAp * state)40 std::ostream &GoFFlatCodeGen::FROM_STATE_ACTION( RedStateAp *state )
41 {
42 	int act = 0;
43 	if ( state->fromStateAction != 0 )
44 		act = state->fromStateAction->actListId+1;
45 	out << act;
46 	return out;
47 }
48 
EOF_ACTION(RedStateAp * state)49 std::ostream &GoFFlatCodeGen::EOF_ACTION( RedStateAp *state )
50 {
51 	int act = 0;
52 	if ( state->eofAction != 0 )
53 		act = state->eofAction->actListId+1;
54 	out << act;
55 	return out;
56 }
57 
58 /* Write out the function for a transition. */
TRANS_ACTION(RedTransAp * trans)59 std::ostream &GoFFlatCodeGen::TRANS_ACTION( RedTransAp *trans )
60 {
61 	int action = 0;
62 	if ( trans->action != 0 )
63 		action = trans->action->actListId+1;
64 	out << action;
65 	return out;
66 }
67 
68 /* Write out the function switch. This switch is keyed on the values
69  * of the func index. */
TO_STATE_ACTION_SWITCH(int level)70 std::ostream &GoFFlatCodeGen::TO_STATE_ACTION_SWITCH( int level )
71 {
72 	/* Loop the actions. */
73 	for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
74 		if ( redAct->numToStateRefs > 0 ) {
75 			/* Write the entry label. */
76 			out << TABS(level) << "case " << redAct->actListId+1 << ":" << endl;
77 
78 			/* Write each action in the list of action items. */
79 			for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
80 				ACTION( out, item->value, 0, false, false );
81 		}
82 	}
83 
84 	genLineDirective( out );
85 	return out;
86 }
87 
88 /* Write out the function switch. This switch is keyed on the values
89  * of the func index. */
FROM_STATE_ACTION_SWITCH(int level)90 std::ostream &GoFFlatCodeGen::FROM_STATE_ACTION_SWITCH( int level )
91 {
92 	/* Loop the actions. */
93 	for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
94 		if ( redAct->numFromStateRefs > 0 ) {
95 			/* Write the entry label. */
96 			out << TABS(level) << "case " << redAct->actListId+1 << ":" << endl;
97 
98 			/* Write each action in the list of action items. */
99 			for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
100 				ACTION( out, item->value, 0, false, false );
101 		}
102 	}
103 
104 	genLineDirective( out );
105 	return out;
106 }
107 
EOF_ACTION_SWITCH(int level)108 std::ostream &GoFFlatCodeGen::EOF_ACTION_SWITCH( int level )
109 {
110 	/* Loop the actions. */
111 	for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
112 		if ( redAct->numEofRefs > 0 ) {
113 			/* Write the entry label. */
114 			out << TABS(level) << "case " << redAct->actListId+1 << ":" << endl;
115 
116 			/* Write each action in the list of action items. */
117 			for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
118 				ACTION( out, item->value, 0, true, false );
119 		}
120 	}
121 
122 	genLineDirective( out );
123 	return out;
124 }
125 
126 /* Write out the function switch. This switch is keyed on the values
127  * of the func index. */
ACTION_SWITCH(int level)128 std::ostream &GoFFlatCodeGen::ACTION_SWITCH( int level )
129 {
130 	/* Loop the actions. */
131 	for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
132 		if ( redAct->numTransRefs > 0 ) {
133 			/* Write the entry label. */
134 			out << TABS(level) << "case " << redAct->actListId+1 << ":" << endl;
135 
136 			/* Write each action in the list of action items. */
137 			for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
138 				ACTION( out, item->value, 0, false, false );
139 		}
140 	}
141 
142 	genLineDirective( out );
143 	return out;
144 }
145 
writeData()146 void GoFFlatCodeGen::writeData()
147 {
148 	if ( redFsm->anyConditions() ) {
149 		OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
150 		COND_KEYS();
151 		CLOSE_ARRAY() <<
152 		endl;
153 
154 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondSpan), CSP() );
155 		COND_KEY_SPANS();
156 		CLOSE_ARRAY() <<
157 		endl;
158 
159 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCond), C() );
160 		CONDS();
161 		CLOSE_ARRAY() <<
162 		endl;
163 
164 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxCondIndexOffset), CO() );
165 		COND_INDEX_OFFSET();
166 		CLOSE_ARRAY() <<
167 		endl;
168 	}
169 
170 	OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
171 	KEYS();
172 	CLOSE_ARRAY() <<
173 	endl;
174 
175 	OPEN_ARRAY( ARRAY_TYPE(redFsm->maxSpan), SP() );
176 	KEY_SPANS();
177 	CLOSE_ARRAY() <<
178 	endl;
179 
180 	OPEN_ARRAY( ARRAY_TYPE(redFsm->maxFlatIndexOffset), IO() );
181 	FLAT_INDEX_OFFSET();
182 	CLOSE_ARRAY() <<
183 	endl;
184 
185 	OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndex), I() );
186 	INDICIES();
187 	CLOSE_ARRAY() <<
188 	endl;
189 
190 	OPEN_ARRAY( ARRAY_TYPE(redFsm->maxState), TT() );
191 	TRANS_TARGS();
192 	CLOSE_ARRAY() <<
193 	endl;
194 
195 	if ( redFsm->anyActions() ) {
196 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), TA() );
197 		TRANS_ACTIONS();
198 		CLOSE_ARRAY() <<
199 		endl;
200 	}
201 
202 	if ( redFsm->anyToStateActions() ) {
203 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc),  TSA() );
204 		TO_STATE_ACTIONS();
205 		CLOSE_ARRAY() <<
206 		endl;
207 	}
208 
209 	if ( redFsm->anyFromStateActions() ) {
210 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
211 		FROM_STATE_ACTIONS();
212 		CLOSE_ARRAY() <<
213 		endl;
214 	}
215 
216 	if ( redFsm->anyEofActions() ) {
217 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActListId), EA() );
218 		EOF_ACTIONS();
219 		CLOSE_ARRAY() <<
220 		endl;
221 	}
222 
223 	if ( redFsm->anyEofTrans() ) {
224 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxIndexOffset+1), ET() );
225 		EOF_TRANS();
226 		CLOSE_ARRAY() <<
227 		endl;
228 	}
229 
230 	STATE_IDS();
231 }
232 
writeExec()233 void GoFFlatCodeGen::writeExec()
234 {
235 	testEofUsed = false;
236 	outLabelUsed = false;
237 
238 	out <<
239 		"	{" << endl <<
240 		"	var _slen " << INT() << endl;
241 
242 	if ( redFsm->anyRegCurStateRef() )
243 		out << "	var _ps " << INT() << endl;
244 
245 	out << "	var _trans " << INT() << endl;
246 
247 	if ( redFsm->anyConditions() )
248 		out << "	var _cond " << INT() << endl;
249 
250 	out <<
251 		"	var _keys " << INT() << endl <<
252 		"	var _inds " << INT() << endl;
253 
254 	if ( redFsm->anyConditions() ) {
255 		out <<
256 			"	var _conds " << INT() << endl <<
257 			"	var _widec " << WIDE_ALPH_TYPE() << endl;
258 	}
259 
260 	if ( !noEnd ) {
261 		testEofUsed = true;
262 		out <<
263 			"	if " << P() << " == " << PE() << " {" << endl <<
264 			"		goto _test_eof" << endl <<
265 			"	}" << endl;
266 	}
267 
268 	if ( redFsm->errState != 0 ) {
269 		outLabelUsed = true;
270 		out <<
271 			"	if " << vCS() << " == " << redFsm->errState->id << " {" << endl <<
272 			"		goto _out" << endl <<
273 			"	}" << endl;
274 	}
275 
276 	out << "_resume:" << endl;
277 
278 	if ( redFsm->anyFromStateActions() ) {
279 		out <<
280 			"	switch " << FSA() << "[" << vCS() << "] {" << endl;
281 			FROM_STATE_ACTION_SWITCH(1);
282 			out <<
283 			"	}" << endl <<
284 			endl;
285 	}
286 
287 	if ( redFsm->anyConditions() )
288 		COND_TRANSLATE();
289 
290 	LOCATE_TRANS();
291 
292 	if ( redFsm->anyEofTrans() )
293 		out << "_eof_trans:" << endl;
294 
295 	if ( redFsm->anyRegCurStateRef() )
296 		out << "	_ps = " << vCS() << endl;
297 
298 	out <<
299 		"	" << vCS() << " = " << CAST(INT(), TT() + "[_trans]") << endl <<
300 		endl;
301 
302 	if ( redFsm->anyRegActions() ) {
303 		out <<
304 			"	if " << TA() << "[_trans] == 0 {" << endl <<
305 			"		goto _again" << endl <<
306 			"	}" << endl <<
307 			endl <<
308 			"	switch " << TA() << "[_trans] {" << endl;
309 			ACTION_SWITCH(1);
310 			out <<
311 			"	}" << endl <<
312 			endl;
313 	}
314 
315 	if ( redFsm->anyRegActions() || redFsm->anyActionGotos() ||
316 			redFsm->anyActionCalls() || redFsm->anyActionRets() )
317 		out << "_again:" << endl;
318 
319 	if ( redFsm->anyToStateActions() ) {
320 		out <<
321 			"	switch " << TSA() << "[" << vCS() << "] {" << endl;
322 			TO_STATE_ACTION_SWITCH(1);
323 			out <<
324 			"	}" << endl <<
325 			endl;
326 	}
327 
328 	if ( redFsm->errState != 0 ) {
329 		outLabelUsed = true;
330 		out <<
331 			"	if " << vCS() << " == " << redFsm->errState->id << " {" << endl <<
332 			"		goto _out" << endl <<
333 			"	}" << endl;
334 	}
335 
336 	if ( !noEnd ) {
337 		out <<
338 			"	if " << P() << "++; " << P() << " != " << PE() << " {"
339 			"		goto _resume" << endl <<
340 			"	}" << endl;
341 	}
342 	else {
343 		out <<
344 			"	" << P() << "++" << endl <<
345 			"	goto _resume" << endl;
346 	}
347 
348 	if ( testEofUsed )
349 		out << "	_test_eof: {}" << endl;
350 
351 	if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
352 		out <<
353 			"	if " << P() << " == " << vEOF() << " {" << endl;
354 
355 		if ( redFsm->anyEofTrans() ) {
356 			out <<
357 				"		if " << ET() << "[" << vCS() << "] > 0 {" << endl <<
358 				"			_trans = " << CAST(INT(), ET() + "[" + vCS() + "] - 1") << endl <<
359 				"			goto _eof_trans" << endl <<
360 				"		}" << endl;
361 		}
362 
363 		if ( redFsm->anyEofActions() ) {
364 			out <<
365 				"		switch " << EA() << "[" << vCS() << "] {" << endl;
366 				EOF_ACTION_SWITCH(2);
367 				out <<
368 				"		}" << endl;
369 		}
370 
371 		out <<
372 			"	}" << endl <<
373 			endl;
374 	}
375 
376 	if ( outLabelUsed )
377 		out << "	_out: {}" << endl;
378 
379 	out << "	}" << endl;
380 }
381