"Fossies" - the Fresh Open Source Software Archive 
Member "ragel-6.10/ragel/cdipgoto.cpp" (24 Mar 2017, 12537 Bytes) of package /linux/misc/ragel-6.10.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "cdipgoto.cpp" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
6.9_vs_6.10.
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 "cdipgoto.h"
26 #include "redfsm.h"
27 #include "gendata.h"
28 #include "bstmap.h"
29
30 bool IpGotoCodeGen::useAgainLabel()
31 {
32 return redFsm->anyActionRets() ||
33 redFsm->anyActionByValControl() ||
34 redFsm->anyRegNextStmt();
35 }
36
37 void IpGotoCodeGen::EOF_CHECK( ostream &ret, int gotoDest )
38 {
39 ret <<
40 " if ( " << P() << " == " << PE() << " )\n"
41 " goto _test_eof" << gotoDest << ";\n";
42
43 testEofUsed = true;
44 }
45
46 void IpGotoCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
47 {
48 ret << "{";
49
50 if ( inFinish && !noEnd )
51 EOF_CHECK( ret, gotoDest );
52
53 ret << CTRL_FLOW() << "goto st" << gotoDest << ";";
54
55 ret << "}";
56 }
57
58 void IpGotoCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
59 {
60 if ( prePushExpr != 0 ) {
61 ret << "{";
62 INLINE_LIST( ret, prePushExpr, 0, false, false );
63 }
64
65 ret << "{" << STACK() << "[" << TOP() << "++] = " << targState << ";";
66
67 if ( inFinish && !noEnd )
68 EOF_CHECK( ret, callDest );
69
70 ret << CTRL_FLOW() << "goto st" << callDest << ";";
71
72 ret << "}";
73
74 if ( prePushExpr != 0 )
75 ret << "}";
76 }
77
78 void IpGotoCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish )
79 {
80 if ( prePushExpr != 0 ) {
81 ret << "{";
82 INLINE_LIST( ret, prePushExpr, 0, false, false );
83 }
84
85 ret << "{";
86
87 ret << STACK() << "[" << TOP() << "++] = " << targState << "; " << vCS() << " = (";
88 INLINE_LIST( ret, ilItem->children, 0, inFinish, false );
89 ret << ");";
90
91 if ( inFinish && !noEnd )
92 FsmCodeGen::EOF_CHECK( ret );
93
94 ret << CTRL_FLOW() << "goto _again;";
95
96 ret << "}";
97
98 if ( prePushExpr != 0 )
99 ret << "}";
100 }
101
102 void IpGotoCodeGen::RET( ostream &ret, bool inFinish )
103 {
104 ret << "{" << vCS() << " = " << STACK() << "[--" << TOP() << "];";
105
106 if ( postPopExpr != 0 ) {
107 ret << "{";
108 INLINE_LIST( ret, postPopExpr, 0, false, false );
109 ret << "}";
110 }
111
112 if ( inFinish && !noEnd )
113 FsmCodeGen::EOF_CHECK( ret );
114
115 ret << CTRL_FLOW() << "goto _again;";
116
117 ret << "}";
118 }
119
120 void IpGotoCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
121 {
122 ret << "{";
123
124 ret << vCS() << " = (";
125 INLINE_LIST( ret, ilItem->children, 0, inFinish, false );
126 ret << ");";
127
128 if ( inFinish && !noEnd )
129 FsmCodeGen::EOF_CHECK( ret );
130
131 ret << CTRL_FLOW() << "goto _again;";
132 ret << "}";
133 }
134
135 void IpGotoCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
136 {
137 ret << vCS() << " = " << nextDest << ";";
138 }
139
140 void IpGotoCodeGen::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
141 {
142 ret << vCS() << " = (";
143 INLINE_LIST( ret, ilItem->children, 0, inFinish, false );
144 ret << ");";
145 }
146
147 void IpGotoCodeGen::CURS( ostream &ret, bool inFinish )
148 {
149 ret << "(_ps)";
150 }
151
152 void IpGotoCodeGen::TARGS( ostream &ret, bool inFinish, int targState )
153 {
154 ret << targState;
155 }
156
157 void IpGotoCodeGen::BREAK( ostream &ret, int targState, bool csForced )
158 {
159 outLabelUsed = true;
160 ret << "{" << P() << "++; ";
161 if ( !csForced )
162 ret << vCS() << " = " << targState << "; ";
163 ret << CTRL_FLOW() << "goto _out;}";
164 }
165
166 bool IpGotoCodeGen::IN_TRANS_ACTIONS( RedStateAp *state )
167 {
168 bool anyWritten = false;
169
170 /* Emit any transitions that have actions and that go to this state. */
171 for ( int it = 0; it < state->numInTrans; it++ ) {
172 RedTransAp *trans = state->inTrans[it];
173 if ( trans->action != 0 && trans->labelNeeded ) {
174 /* Remember that we wrote an action so we know to write the
175 * line directive for going back to the output. */
176 anyWritten = true;
177
178 /* Write the label for the transition so it can be jumped to. */
179 out << "tr" << trans->id << ":\n";
180
181 /* If the action contains a next, then we must preload the current
182 * state since the action may or may not set it. */
183 if ( trans->action->anyNextStmt() )
184 out << " " << vCS() << " = " << trans->targ->id << ";\n";
185
186 /* Write each action in the list. */
187 for ( GenActionTable::Iter item = trans->action->key; item.lte(); item++ ) {
188 ACTION( out, item->value, trans->targ->id, false,
189 trans->action->anyNextStmt() );
190 }
191
192 /* If the action contains a next then we need to reload, otherwise
193 * jump directly to the target state. */
194 if ( trans->action->anyNextStmt() )
195 out << "\tgoto _again;\n";
196 else
197 out << "\tgoto st" << trans->targ->id << ";\n";
198 }
199 }
200
201 return anyWritten;
202 }
203
204 /* Called from GotoCodeGen::STATE_GOTOS just before writing the gotos for each
205 * state. */
206 void IpGotoCodeGen::GOTO_HEADER( RedStateAp *state )
207 {
208 bool anyWritten = IN_TRANS_ACTIONS( state );
209
210 if ( state->labelNeeded )
211 out << "st" << state->id << ":\n";
212
213 if ( state->toStateAction != 0 ) {
214 /* Remember that we wrote an action. Write every action in the list. */
215 anyWritten = true;
216 for ( GenActionTable::Iter item = state->toStateAction->key; item.lte(); item++ ) {
217 ACTION( out, item->value, state->id, false,
218 state->toStateAction->anyNextStmt() );
219 }
220 }
221
222 /* Advance and test buffer pos. */
223 if ( state->labelNeeded ) {
224 if ( !noEnd ) {
225 out <<
226 " if ( ++" << P() << " == " << PE() << " )\n"
227 " goto _test_eof" << state->id << ";\n";
228 }
229 else {
230 out <<
231 " " << P() << " += 1;\n";
232 }
233 }
234
235 /* Give the state a switch case. */
236 out << "case " << state->id << ":\n";
237
238 if ( state->fromStateAction != 0 ) {
239 /* Remember that we wrote an action. Write every action in the list. */
240 anyWritten = true;
241 for ( GenActionTable::Iter item = state->fromStateAction->key; item.lte(); item++ ) {
242 ACTION( out, item->value, state->id, false,
243 state->fromStateAction->anyNextStmt() );
244 }
245 }
246
247 if ( anyWritten )
248 genLineDirective( out );
249
250 /* Record the prev state if necessary. */
251 if ( state->anyRegCurStateRef() )
252 out << " _ps = " << state->id << ";\n";
253 }
254
255 void IpGotoCodeGen::STATE_GOTO_ERROR()
256 {
257 /* In the error state we need to emit some stuff that usually goes into
258 * the header. */
259 RedStateAp *state = redFsm->errState;
260 bool anyWritten = IN_TRANS_ACTIONS( state );
261
262 /* No case label needed since we don't switch on the error state. */
263 if ( anyWritten )
264 genLineDirective( out );
265
266 if ( state->labelNeeded )
267 out << "st" << state->id << ":\n";
268
269 /* Break out here. */
270 outLabelUsed = true;
271 out << vCS() << " = " << state->id << ";\n";
272 out << " goto _out;\n";
273 }
274
275
276 /* Emit the goto to take for a given transition. */
277 std::ostream &IpGotoCodeGen::TRANS_GOTO( RedTransAp *trans, int level )
278 {
279 if ( trans->action != 0 ) {
280 /* Go to the transition which will go to the state. */
281 out << TABS(level) << "goto tr" << trans->id << ";";
282 }
283 else {
284 /* Go directly to the target state. */
285 out << TABS(level) << "goto st" << trans->targ->id << ";";
286 }
287 return out;
288 }
289
290 std::ostream &IpGotoCodeGen::EXIT_STATES()
291 {
292 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
293 if ( st->outNeeded ) {
294 testEofUsed = true;
295 out << " _test_eof" << st->id << ": " << vCS() << " = " <<
296 st->id << "; goto _test_eof; \n";
297 }
298 }
299 return out;
300 }
301
302 std::ostream &IpGotoCodeGen::AGAIN_CASES()
303 {
304 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
305 out <<
306 " case " << st->id << ": goto st" << st->id << ";\n";
307 }
308 return out;
309 }
310
311 std::ostream &IpGotoCodeGen::FINISH_CASES()
312 {
313 bool anyWritten = false;
314
315 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
316 if ( st->eofAction != 0 ) {
317 if ( st->eofAction->eofRefs == 0 )
318 st->eofAction->eofRefs = new IntSet;
319 st->eofAction->eofRefs->insert( st->id );
320 }
321 }
322
323 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
324 if ( st->eofTrans != 0 )
325 out << " case " << st->id << ": goto tr" << st->eofTrans->id << ";\n";
326 }
327
328 for ( GenActionTableMap::Iter act = redFsm->actionMap; act.lte(); act++ ) {
329 if ( act->eofRefs != 0 ) {
330 for ( IntSet::Iter pst = *act->eofRefs; pst.lte(); pst++ )
331 out << " case " << *pst << ": \n";
332
333 /* Remember that we wrote a trans so we know to write the
334 * line directive for going back to the output. */
335 anyWritten = true;
336
337 /* Write each action in the eof action list. */
338 for ( GenActionTable::Iter item = act->key; item.lte(); item++ )
339 ACTION( out, item->value, STATE_ERR_STATE, true, false );
340 out << "\tbreak;\n";
341 }
342 }
343
344 if ( anyWritten )
345 genLineDirective( out );
346 return out;
347 }
348
349 void IpGotoCodeGen::setLabelsNeeded( GenInlineList *inlineList )
350 {
351 for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) {
352 switch ( item->type ) {
353 case GenInlineItem::Goto: case GenInlineItem::Call: {
354 /* Mark the target as needing a label. */
355 item->targState->labelNeeded = true;
356 break;
357 }
358 default: break;
359 }
360
361 if ( item->children != 0 )
362 setLabelsNeeded( item->children );
363 }
364 }
365
366 /* Set up labelNeeded flag for each state. */
367 void IpGotoCodeGen::setLabelsNeeded()
368 {
369 /* If we use the _again label, then we the _again switch, which uses all
370 * labels. */
371 if ( useAgainLabel() ) {
372 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
373 st->labelNeeded = true;
374 }
375 else {
376 /* Do not use all labels by default, init all labelNeeded vars to false. */
377 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
378 st->labelNeeded = false;
379
380 /* Walk all transitions and set only those that have targs. */
381 for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) {
382 /* If there is no action with a next statement, then the label will be
383 * needed. */
384 if ( trans->action == 0 || !trans->action->anyNextStmt() )
385 trans->targ->labelNeeded = true;
386
387 /* Need labels for states that have goto or calls in action code
388 * invoked on characters (ie, not from out action code). */
389 if ( trans->action != 0 ) {
390 /* Loop the actions. */
391 for ( GenActionTable::Iter act = trans->action->key; act.lte(); act++ ) {
392 /* Get the action and walk it's tree. */
393 setLabelsNeeded( act->value->inlineList );
394 }
395 }
396 }
397
398 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
399 if ( st->eofAction != 0 ) {
400 for ( GenActionTable::Iter item = st->eofAction->key; item.lte(); item++ )
401 setLabelsNeeded( item->value->inlineList );
402 }
403 }
404 }
405
406 if ( !noEnd ) {
407 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
408 if ( st != redFsm->errState )
409 st->outNeeded = st->labelNeeded;
410 }
411 }
412 }
413
414 void IpGotoCodeGen::writeData()
415 {
416 STATE_IDS();
417 }
418
419 void IpGotoCodeGen::writeExec()
420 {
421 /* Must set labels immediately before writing because we may depend on the
422 * noend write option. */
423 setLabelsNeeded();
424 testEofUsed = false;
425 outLabelUsed = false;
426
427 out << " {\n";
428
429 if ( redFsm->anyRegCurStateRef() )
430 out << " int _ps = 0;\n";
431
432 if ( redFsm->anyConditions() )
433 out << " " << WIDE_ALPH_TYPE() << " _widec;\n";
434
435 if ( !noEnd ) {
436 testEofUsed = true;
437 out <<
438 " if ( " << P() << " == " << PE() << " )\n"
439 " goto _test_eof;\n";
440 }
441
442 if ( useAgainLabel() ) {
443 out <<
444 " goto _resume;\n"
445 "\n"
446 "_again:\n"
447 " switch ( " << vCS() << " ) {\n";
448 AGAIN_CASES() <<
449 " default: break;\n"
450 " }\n"
451 "\n";
452
453 if ( !noEnd ) {
454 testEofUsed = true;
455 out <<
456 " if ( ++" << P() << " == " << PE() << " )\n"
457 " goto _test_eof;\n";
458 }
459 else {
460 out <<
461 " " << P() << " += 1;\n";
462 }
463
464 out << "_resume:\n";
465 }
466
467 out <<
468 " switch ( " << vCS() << " )\n {\n";
469 STATE_GOTOS();
470 SWITCH_DEFAULT() <<
471 " }\n";
472 EXIT_STATES() <<
473 "\n";
474
475 if ( testEofUsed )
476 out << " _test_eof: {}\n";
477
478 if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
479 out <<
480 " if ( " << P() << " == " << vEOF() << " )\n"
481 " {\n"
482 " switch ( " << vCS() << " ) {\n";
483 FINISH_CASES();
484 SWITCH_DEFAULT() <<
485 " }\n"
486 " }\n"
487 "\n";
488 }
489
490 if ( outLabelUsed )
491 out << " _out: {}\n";
492
493 out <<
494 " }\n";
495 }