1 /*
2  *  Copyright 2001-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 "gofgoto.h"
26 #include "redfsm.h"
27 #include "gendata.h"
28 #include "bstmap.h"
29 
30 using std::endl;
31 
EXEC_ACTIONS()32 std::ostream &GoFGotoCodeGen::EXEC_ACTIONS()
33 {
34 	/* Loop the actions. */
35 	for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
36 		if ( redAct->numTransRefs > 0 ) {
37 			/* 	We are at the start of a glob, write the case. */
38 			out << "f" << redAct->actListId << ":" << endl;
39 
40 			/* Write each action in the list of action items. */
41 			for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
42 				ACTION( out, item->value, 0, false, false );
43 
44 			out << TABS(1) << "goto _again" << endl;
45 		}
46 	}
47 	return out;
48 }
49 
50 /* Write out the function switch. This switch is keyed on the values
51  * of the func index. */
TO_STATE_ACTION_SWITCH(int level)52 std::ostream &GoFGotoCodeGen::TO_STATE_ACTION_SWITCH( int level )
53 {
54 	/* Loop the actions. */
55 	for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
56 		if ( redAct->numToStateRefs > 0 ) {
57 			/* Write the entry label. */
58 			out << TABS(level) << "case " << redAct->actListId+1 << ":" << endl;
59 
60 			/* Write each action in the list of action items. */
61 			for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
62 				ACTION( out, item->value, 0, false, false );
63 		}
64 	}
65 
66 	genLineDirective( out );
67 	return out;
68 }
69 
70 /* Write out the function switch. This switch is keyed on the values
71  * of the func index. */
FROM_STATE_ACTION_SWITCH(int level)72 std::ostream &GoFGotoCodeGen::FROM_STATE_ACTION_SWITCH( int level )
73 {
74 	/* Loop the actions. */
75 	for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
76 		if ( redAct->numFromStateRefs > 0 ) {
77 			/* Write the entry label. */
78 			out << TABS(level) << "case " << redAct->actListId+1 << ":" << endl;
79 
80 			/* Write each action in the list of action items. */
81 			for ( GenActionTable::Iter item = redAct->key; item.lte(); item++ )
82 				ACTION( out, item->value, 0, false, false );
83 		}
84 	}
85 
86 	genLineDirective( out );
87 	return out;
88 }
89 
EOF_ACTION_SWITCH(int level)90 std::ostream &GoFGotoCodeGen::EOF_ACTION_SWITCH( int level )
91 {
92 	/* Loop the actions. */
93 	for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
94 		if ( redAct->numEofRefs > 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, true, false );
101 		}
102 	}
103 
104 	genLineDirective( out );
105 	return out;
106 }
107 
108 
FINISH_CASES()109 std::ostream &GoFGotoCodeGen::FINISH_CASES()
110 {
111 	for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
112 		/* States that are final and have an out action need a case. */
113 		if ( st->eofAction != 0 ) {
114 			/* Write the case label. */
115 			out << TABS(2) << "case " << st->id << ":" << endl;
116 
117 			/* Jump to the func. */
118 			out << TABS(3) << "goto f" << st->eofAction->actListId << endl;
119 		}
120 	}
121 
122 	return out;
123 }
124 
TO_STATE_ACTION(RedStateAp * state)125 unsigned int GoFGotoCodeGen::TO_STATE_ACTION( RedStateAp *state )
126 {
127 	int act = 0;
128 	if ( state->toStateAction != 0 )
129 		act = state->toStateAction->actListId+1;
130 	return act;
131 }
132 
FROM_STATE_ACTION(RedStateAp * state)133 unsigned int GoFGotoCodeGen::FROM_STATE_ACTION( RedStateAp *state )
134 {
135 	int act = 0;
136 	if ( state->fromStateAction != 0 )
137 		act = state->fromStateAction->actListId+1;
138 	return act;
139 }
140 
EOF_ACTION(RedStateAp * state)141 unsigned int GoFGotoCodeGen::EOF_ACTION( RedStateAp *state )
142 {
143 	int act = 0;
144 	if ( state->eofAction != 0 )
145 		act = state->eofAction->actListId+1;
146 	return act;
147 }
148 
writeData()149 void GoFGotoCodeGen::writeData()
150 {
151 	if ( redFsm->anyToStateActions() ) {
152 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
153 		TO_STATE_ACTIONS();
154 		CLOSE_ARRAY() <<
155 		endl;
156 	}
157 
158 	if ( redFsm->anyFromStateActions() ) {
159 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
160 		FROM_STATE_ACTIONS();
161 		CLOSE_ARRAY() <<
162 		endl;
163 	}
164 
165 	if ( redFsm->anyEofActions() ) {
166 		OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
167 		EOF_ACTIONS();
168 		CLOSE_ARRAY() <<
169 		endl;
170 	}
171 
172 	STATE_IDS();
173 }
174 
writeExec()175 void GoFGotoCodeGen::writeExec()
176 {
177 	testEofUsed = false;
178 	outLabelUsed = false;
179 
180 	out << "	{" << endl;
181 
182 	if ( redFsm->anyRegCurStateRef() )
183 		out << "	var _ps " << INT() << " = 0" << endl;
184 
185 	if ( redFsm->anyConditions() )
186 		out << "	var _widec " << WIDE_ALPH_TYPE() << endl;
187 
188 	if ( !noEnd ) {
189 		testEofUsed = true;
190 		out <<
191 			"	if " << P() << " == " << PE() << " {" << endl <<
192 			"		goto _test_eof" << endl <<
193 			"	}" << endl;
194 	}
195 
196 	if ( redFsm->errState != 0 ) {
197 		outLabelUsed = true;
198 		out <<
199 			"	if " << vCS() << " == " << redFsm->errState->id << " {" << endl <<
200 			"		goto _out" << endl <<
201 			"	}" << endl;
202 	}
203 
204 	out << "_resume:" << endl;
205 
206 	if ( redFsm->anyFromStateActions() ) {
207 		out <<
208 			"	switch " << FSA() << "[" << vCS() << "] {" << endl;
209 			FROM_STATE_ACTION_SWITCH(1);
210 			out <<
211 			"	}" << endl <<
212 			endl;
213 	}
214 
215 	out <<
216 		"	switch " << vCS() << " {" << endl;
217 		STATE_GOTOS(1);
218 		out <<
219 		"	}" << endl <<
220 		endl;
221 		TRANSITIONS() <<
222 		endl;
223 
224 	if ( redFsm->anyRegActions() )
225 		EXEC_ACTIONS() << endl;
226 
227 	out << "_again:" << endl;
228 
229 	if ( redFsm->anyToStateActions() ) {
230 		out <<
231 			"	switch " << TSA() << "[" << vCS() << "] {" << endl;
232 			TO_STATE_ACTION_SWITCH(1);
233 			out <<
234 			"	}" << endl <<
235 			endl;
236 	}
237 
238 	if ( redFsm->errState != 0 ) {
239 		outLabelUsed = true;
240 		out <<
241 			"	if " << vCS() << " == " << redFsm->errState->id << " {" << endl <<
242 			"		goto _out" << endl <<
243 			"	}" << endl;
244 	}
245 
246 	if ( !noEnd ) {
247 		out <<
248 			"	if " << P() << "++; " << P() << " != " << PE() << " {" << endl <<
249 			"		goto _resume" << endl <<
250 			"	}" << endl;
251 	}
252 	else {
253 		out <<
254 			"	" << P() << "++" << endl <<
255 			"	goto _resume" << endl;
256 	}
257 
258 	if ( testEofUsed )
259 		out << "	_test_eof: {}" << endl;
260 
261 	if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
262 		out <<
263 			"	if " << P() << " == " << vEOF() << " {" << endl;
264 
265 		if ( redFsm->anyEofTrans() ) {
266 			out <<
267 				"		switch " << vCS() << " {" << endl;
268 
269 			for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
270 				if ( st->eofTrans != 0 )
271 					out <<
272 						"		case " << st->id << ":" << endl <<
273 						"			goto tr" << st->eofTrans->id << endl;
274 			}
275 
276 			out <<
277 				"		}" << endl;
278 		}
279 
280 		if ( redFsm->anyEofActions() ) {
281 			out <<
282 				"		switch " << EA() << "[" << vCS() << "] {" << endl;
283 				EOF_ACTION_SWITCH(2);
284 				out <<
285 				"		}" << endl;
286 		}
287 
288 		out <<
289 			"	}" << endl <<
290 			endl;
291 	}
292 
293 	if ( outLabelUsed )
294 		out << "	_out: {}" << endl;
295 
296 	out << "	}" << endl;
297 }
298