2 * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
3 * 2004 Erich Ocean <eric.ocean@ampede.com>
4 * 2005 Alan West <alan@alanz.com>
7 /* This file is part of Ragel.
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.
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.
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
32 bool GoIpGotoCodeGen::useAgainLabel()
34 return redFsm
->anyRegActionRets() ||
35 redFsm
->anyRegActionByValControl() ||
36 redFsm
->anyRegNextStmt();
39 void GoIpGotoCodeGen::GOTO( ostream
&ret
, int gotoDest
, bool inFinish
)
41 ret
<< "{" << "goto st" << gotoDest
<< " }";
44 void GoIpGotoCodeGen::CALL( ostream
&ret
, int callDest
, int targState
, bool inFinish
)
46 if ( prePushExpr
!= 0 ) {
48 INLINE_LIST( ret
, prePushExpr
, 0, false, false );
51 ret
<< "{" << STACK() << "[" << TOP() << "] = " << targState
<<
52 "; " << TOP() << "++; " << "goto st" << callDest
<< " }";
54 if ( prePushExpr
!= 0 )
58 void GoIpGotoCodeGen::CALL_EXPR( ostream
&ret
, GenInlineItem
*ilItem
, int targState
, bool inFinish
)
60 if ( prePushExpr
!= 0 ) {
62 INLINE_LIST( ret
, prePushExpr
, 0, false, false );
65 ret
<< "{" << STACK() << "[" << TOP() << "] = " << targState
<< "; " << TOP() << "++; " << vCS() << " = (";
66 INLINE_LIST( ret
, ilItem
->children
, 0, inFinish
, false );
67 ret
<< "); " << "goto _again }";
69 if ( prePushExpr
!= 0 )
73 void GoIpGotoCodeGen::RET( ostream
&ret
, bool inFinish
)
75 ret
<< "{" << TOP() << "--; " << vCS() << " = " << STACK() << "[" << TOP() << "];";
77 if ( postPopExpr
!= 0 ) {
79 INLINE_LIST( ret
, postPopExpr
, 0, false, false );
83 ret
<< "goto _again }";
86 void GoIpGotoCodeGen::GOTO_EXPR( ostream
&ret
, GenInlineItem
*ilItem
, bool inFinish
)
88 ret
<< "{" << vCS() << " = (";
89 INLINE_LIST( ret
, ilItem
->children
, 0, inFinish
, false );
90 ret
<< "); " << "goto _again }";
93 void GoIpGotoCodeGen::NEXT( ostream
&ret
, int nextDest
, bool inFinish
)
95 ret
<< vCS() << " = " << nextDest
<< ";";
98 void GoIpGotoCodeGen::NEXT_EXPR( ostream
&ret
, GenInlineItem
*ilItem
, bool inFinish
)
100 ret
<< vCS() << " = (";
101 INLINE_LIST( ret
, ilItem
->children
, 0, inFinish
, false );
105 void GoIpGotoCodeGen::CURS( ostream
&ret
, bool inFinish
)
110 void GoIpGotoCodeGen::TARGS( ostream
&ret
, bool inFinish
, int targState
)
115 void GoIpGotoCodeGen::BREAK( ostream
&ret
, int targState
, bool csForced
)
118 ret
<< "{" << P() << "++; ";
120 ret
<< vCS() << " = " << targState
<< "; ";
121 ret
<< "goto _out }";
124 bool GoIpGotoCodeGen::IN_TRANS_ACTIONS( RedStateAp
*state
)
126 bool anyWritten
= false;
128 /* Emit any transitions that have actions and that go to this state. */
129 for ( int it
= 0; it
< state
->numInTrans
; it
++ ) {
130 RedTransAp
*trans
= state
->inTrans
[it
];
131 if ( trans
->action
!= 0 && trans
->labelNeeded
) {
132 /* Remember that we wrote an action so we know to write the
133 * line directive for going back to the output. */
136 /* Write the label for the transition so it can be jumped to. */
137 out
<< "tr" << trans
->id
<< ":" << endl
;
139 /* If the action contains a next, then we must preload the current
140 * state since the action may or may not set it. */
141 if ( trans
->action
->anyNextStmt() )
142 out
<< " " << vCS() << " = " << trans
->targ
->id
<< endl
;
144 /* Write each action in the list. */
145 for ( GenActionTable::Iter item
= trans
->action
->key
; item
.lte(); item
++ ) {
146 ACTION( out
, item
->value
, trans
->targ
->id
, false,
147 trans
->action
->anyNextStmt() );
150 /* If the action contains a next then we need to reload, otherwise
151 * jump directly to the target state. */
152 if ( trans
->action
->anyNextStmt() )
153 out
<< " goto _again" << endl
;
155 out
<< " goto st" << trans
->targ
->id
<< endl
;
162 std::ostream
&GoIpGotoCodeGen::STATE_GOTOS_SWITCH( int level
)
164 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ ) {
165 out
<< TABS(level
) << "case " << st
->id
<< ":" << endl
;
166 out
<< TABS(level
+ 1) << "goto st_case_" << st
->id
<< endl
;
171 /* Called from GotoCodeGen::STATE_GOTOS just before writing the gotos for each
173 void GoIpGotoCodeGen::GOTO_HEADER( RedStateAp
*state
, int level
)
175 bool anyWritten
= IN_TRANS_ACTIONS( state
);
177 if ( state
->labelNeeded
)
178 out
<< TABS(level
) << "st" << state
->id
<< ":" << endl
;
180 if ( state
->toStateAction
!= 0 ) {
181 /* Remember that we wrote an action. Write every action in the list. */
183 for ( GenActionTable::Iter item
= state
->toStateAction
->key
; item
.lte(); item
++ ) {
184 ACTION( out
, item
->value
, state
->id
, false,
185 state
->toStateAction
->anyNextStmt() );
189 /* Advance and test buffer pos. */
190 if ( state
->labelNeeded
) {
193 TABS(level
+ 1) << "if " << P() << "++; " << P() << " == " << PE() << " {" << endl
<<
194 TABS(level
+ 2) << "goto _test_eof" << state
->id
<< endl
<<
195 TABS(level
+ 1) << "}" << endl
;
199 TABS(level
+ 1) << P() << "++" << endl
;
203 /* Give the state a label. */
204 out
<< TABS(level
) << "st_case_" << state
->id
<< ":" << endl
;
206 if ( state
->fromStateAction
!= 0 ) {
207 /* Remember that we wrote an action. Write every action in the list. */
209 for ( GenActionTable::Iter item
= state
->fromStateAction
->key
; item
.lte(); item
++ ) {
210 ACTION( out
, item
->value
, state
->id
, false,
211 state
->fromStateAction
->anyNextStmt() );
216 genLineDirective( out
);
218 /* Record the prev state if necessary. */
219 if ( state
->anyRegCurStateRef() )
220 out
<< TABS(level
+ 1) << "_ps = " << state
->id
<< endl
;
223 void GoIpGotoCodeGen::STATE_GOTO_ERROR( int level
)
225 /* In the error state we need to emit some stuff that usually goes into
227 RedStateAp
*state
= redFsm
->errState
;
228 bool anyWritten
= IN_TRANS_ACTIONS( state
);
230 /* No case label needed since we don't switch on the error state. */
232 genLineDirective( out
);
234 out
<< "st_case_" << state
->id
<< ":" << endl
;
235 if ( state
->labelNeeded
)
236 out
<< TABS(level
) << "st" << state
->id
<< ":" << endl
;
238 /* Break out here. */
240 out
<< TABS(level
+ 1) << vCS() << " = " << state
->id
<< endl
;
241 out
<< TABS(level
+ 1) << "goto _out" << endl
;
245 /* Emit the goto to take for a given transition. */
246 std::ostream
&GoIpGotoCodeGen::TRANS_GOTO( RedTransAp
*trans
, int level
)
248 if ( trans
->action
!= 0 ) {
249 /* Go to the transition which will go to the state. */
250 out
<< TABS(level
) << "goto tr" << trans
->id
;
253 /* Go directly to the target state. */
254 out
<< TABS(level
) << "goto st" << trans
->targ
->id
;
259 int GoIpGotoCodeGen::TRANS_NR( RedTransAp
*trans
)
261 if ( trans
->action
!= 0 ) {
262 /* Go to the transition which will go to the state. */
263 return trans
->id
+ redFsm
->stateList
.length();
266 /* Go directly to the target state. */
267 return trans
->targ
->id
;
271 std::ostream
&GoIpGotoCodeGen::EXIT_STATES()
273 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ ) {
274 if ( st
->outNeeded
) {
276 out
<< " _test_eof" << st
->id
<< ": " << vCS() << " = " <<
277 st
->id
<< "; goto _test_eof" << endl
;
283 std::ostream
&GoIpGotoCodeGen::AGAIN_CASES( int level
)
285 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ ) {
287 TABS(level
) << "case " << st
->id
<< ":" << endl
<<
288 TABS(level
+ 1) << "goto st" << st
->id
<< endl
;
293 std::ostream
&GoIpGotoCodeGen::FINISH_CASES( int level
)
295 bool anyWritten
= false;
297 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ ) {
298 if ( st
->eofAction
!= 0 ) {
299 if ( st
->eofAction
->eofRefs
== 0 )
300 st
->eofAction
->eofRefs
= new IntSet
;
301 st
->eofAction
->eofRefs
->insert( st
->id
);
305 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ ) {
306 if ( st
->eofTrans
!= 0 )
307 out
<< TABS(level
) << "case " << st
->id
<< ":" << endl
<<
308 TABS(level
+ 1) << "goto tr" << st
->eofTrans
->id
<< endl
;
311 for ( GenActionTableMap::Iter act
= redFsm
->actionMap
; act
.lte(); act
++ ) {
312 if ( act
->eofRefs
!= 0 ) {
313 out
<< TABS(level
) << "case ";
314 for ( IntSet::Iter pst
= *act
->eofRefs
; pst
.lte(); pst
++ ) {
321 /* Remember that we wrote a trans so we know to write the
322 * line directive for going back to the output. */
325 /* Write each action in the eof action list. */
326 for ( GenActionTable::Iter item
= act
->key
; item
.lte(); item
++ )
327 ACTION( out
, item
->value
, STATE_ERR_STATE
, true, false );
332 genLineDirective( out
);
336 void GoIpGotoCodeGen::setLabelsNeeded( GenInlineList
*inlineList
)
338 for ( GenInlineList::Iter item
= *inlineList
; item
.lte(); item
++ ) {
339 switch ( item
->type
) {
340 case GenInlineItem::Goto
: case GenInlineItem::Call
: {
341 /* Mark the target as needing a label. */
342 item
->targState
->labelNeeded
= true;
348 if ( item
->children
!= 0 )
349 setLabelsNeeded( item
->children
);
353 /* Set up labelNeeded flag for each state. */
354 void GoIpGotoCodeGen::setLabelsNeeded()
356 /* If we use the _again label, then we the _again switch, which uses all
358 if ( useAgainLabel() ) {
359 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ )
360 st
->labelNeeded
= true;
363 /* Do not use all labels by default, init all labelNeeded vars to false. */
364 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ )
365 st
->labelNeeded
= false;
367 /* Walk all transitions and set only those that have targs. */
368 for ( TransApSet::Iter trans
= redFsm
->transSet
; trans
.lte(); trans
++ ) {
369 /* If there is no action with a next statement, then the label will be
371 if ( trans
->action
== 0 || !trans
->action
->anyNextStmt() )
372 trans
->targ
->labelNeeded
= true;
374 /* Need labels for states that have goto or calls in action code
375 * invoked on characters (ie, not from out action code). */
376 if ( trans
->action
!= 0 ) {
377 /* Loop the actions. */
378 for ( GenActionTable::Iter act
= trans
->action
->key
; act
.lte(); act
++ ) {
379 /* Get the action and walk it's tree. */
380 setLabelsNeeded( act
->value
->inlineList
);
387 for ( RedStateList::Iter st
= redFsm
->stateList
; st
.lte(); st
++ ) {
388 if ( st
!= redFsm
->errState
)
389 st
->outNeeded
= st
->labelNeeded
;
394 void GoIpGotoCodeGen::writeData()
399 void GoIpGotoCodeGen::writeExec()
401 /* Must set labels immediately before writing because we may depend on the
402 * noend write option. */
405 outLabelUsed
= false;
409 if ( redFsm
->anyRegCurStateRef() )
410 out
<< " var _ps " << INT() << " = 0" << endl
;
412 if ( redFsm
->anyConditions() )
413 out
<< " var _widec " << WIDE_ALPH_TYPE() << endl
;
418 " if " << P() << " == " << PE() << " {" << endl
<<
419 " goto _test_eof" << endl
<<
423 if ( useAgainLabel() ) {
425 " goto _resume" << endl
<<
428 " switch " << vCS() << " {" << endl
;
436 " if " << P() << "++; " << P() << " == " << PE() << " {" << endl
<<
437 " goto _test_eof" << endl
<<
442 " " << P() << "++" << endl
;
444 out
<< "_resume:" << endl
;
448 " switch " << vCS() << " {" << endl
;
449 STATE_GOTOS_SWITCH(1);
452 out
<< " goto st_out" << endl
;
454 out
<< " st_out:" << endl
;
459 out
<< " _test_eof: {}" << endl
;
461 if ( redFsm
->anyEofTrans() || redFsm
->anyEofActions() ) {
463 " if " << P() << " == " << vEOF() << " {" << endl
<<
464 " switch " << vCS() << " {" << endl
;
473 out
<< " _out: {}" << endl
;