2 * Copyright 2001-2006 Adrian Thurston <thurston@cs.queensu.ca>
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
25 #include "ipgotocodegen.h"
30 bool IpGotoCodeGen::useAgainLabel()
32 return redFsm->anyRegActionRets() ||
33 redFsm->anyRegActionByValControl() ||
34 redFsm->anyRegNextStmt();
37 void IpGotoCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
39 ret << "{" << CTRL_FLOW() << "goto st" << gotoDest << ";}";
42 void IpGotoCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
44 if ( prePushExpr != 0 ) {
46 INLINE_LIST( ret, prePushExpr, 0, false );
49 ret << "{" << STACK() << "[" << TOP() << "++] = " << targState <<
50 "; " << CTRL_FLOW() << "goto st" << callDest << ";}";
52 if ( prePushExpr != 0 )
56 void IpGotoCodeGen::CALL_EXPR( ostream &ret, InlineItem *ilItem, int targState, bool inFinish )
58 if ( prePushExpr != 0 ) {
60 INLINE_LIST( ret, prePushExpr, 0, false );
63 ret << "{" << STACK() << "[" << TOP() << "++] = " << targState << "; " << CS() << " = (";
64 INLINE_LIST( ret, ilItem->children, 0, inFinish );
65 ret << "); " << CTRL_FLOW() << "goto _again;}";
67 if ( prePushExpr != 0 )
71 void IpGotoCodeGen::RET( ostream &ret, bool inFinish )
73 ret << "{" << CS() << " = " << STACK() << "[--" << TOP() << "];";
75 if ( postPopExpr != 0 ) {
77 INLINE_LIST( ret, postPopExpr, 0, false );
81 ret << CTRL_FLOW() << "goto _again;}";
84 void IpGotoCodeGen::GOTO_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish )
86 ret << "{" << CS() << " = (";
87 INLINE_LIST( ret, ilItem->children, 0, inFinish );
88 ret << "); " << CTRL_FLOW() << "goto _again;}";
91 void IpGotoCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
93 ret << CS() << " = " << nextDest << ";";
96 void IpGotoCodeGen::NEXT_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish )
98 ret << CS() << " = (";
99 INLINE_LIST( ret, ilItem->children, 0, inFinish );
103 void IpGotoCodeGen::CURS( ostream &ret, bool inFinish )
108 void IpGotoCodeGen::TARGS( ostream &ret, bool inFinish, int targState )
113 void IpGotoCodeGen::BREAK( ostream &ret, int targState )
115 ret << CTRL_FLOW() << "goto _out" << targState << ";";
118 bool IpGotoCodeGen::IN_TRANS_ACTIONS( RedStateAp *state )
120 bool anyWritten = false;
122 /* Emit any transitions that have actions and that go to this state. */
123 for ( int it = 0; it < state->numInTrans; it++ ) {
124 RedTransAp *trans = state->inTrans[it];
125 if ( trans->action != 0 && trans->labelNeeded ) {
126 /* Remember that we wrote an action so we know to write the
127 * line directive for going back to the output. */
130 /* Write the label for the transition so it can be jumped to. */
131 out << "tr" << trans->id << ":\n";
133 /* If the action contains a next, then we must preload the current
134 * state since the action may or may not set it. */
135 if ( trans->action->anyNextStmt() )
136 out << " " << CS() << " = " << trans->targ->id << ";\n";
138 /* Write each action in the list. */
139 for ( ActionTable::Iter item = trans->action->key; item.lte(); item++ )
140 ACTION( out, item->value, trans->targ->id, false );
142 /* If the action contains a next then we need to reload, otherwise
143 * jump directly to the target state. */
144 if ( trans->action->anyNextStmt() )
145 out << "\tgoto _again;\n";
147 out << "\tgoto st" << trans->targ->id << ";\n";
154 /* Called from GotoCodeGen::STATE_GOTOS just before writing the gotos for each
156 void IpGotoCodeGen::GOTO_HEADER( RedStateAp *state )
158 bool anyWritten = IN_TRANS_ACTIONS( state );
160 if ( state->labelNeeded )
161 out << "st" << state->id << ":\n";
163 if ( state->toStateAction != 0 ) {
164 /* Remember that we wrote an action. Write every action in the list. */
166 for ( ActionTable::Iter item = state->toStateAction->key; item.lte(); item++ )
167 ACTION( out, item->value, state->id, false );
170 /* Advance and test buffer pos. */
171 if ( state->labelNeeded ) {
174 " if ( ++" << P() << " == " << PE() << " )\n"
175 " goto _out" << state->id << ";\n";
179 " " << P() << " += 1;\n";
183 /* Give the state a switch case. */
184 out << "case " << state->id << ":\n";
186 if ( state->fromStateAction != 0 ) {
187 /* Remember that we wrote an action. Write every action in the list. */
189 for ( ActionTable::Iter item = state->fromStateAction->key; item.lte(); item++ )
190 ACTION( out, item->value, state->id, false );
194 genLineDirective( out );
196 /* Record the prev state if necessary. */
197 if ( state->anyRegCurStateRef() )
198 out << " _ps = " << state->id << ";\n";
201 void IpGotoCodeGen::STATE_GOTO_ERROR()
203 /* In the error state we need to emit some stuff that usually goes into
205 RedStateAp *state = redFsm->errState;
206 bool anyWritten = IN_TRANS_ACTIONS( state );
208 /* No case label needed since we don't switch on the error state. */
210 genLineDirective( out );
212 if ( state->labelNeeded )
213 out << "st" << state->id << ":\n";
215 /* Break out here. */
216 out << " goto _out" << state->id << ";\n";
220 /* Emit the goto to take for a given transition. */
221 std::ostream &IpGotoCodeGen::TRANS_GOTO( RedTransAp *trans, int level )
223 if ( trans->action != 0 ) {
224 /* Go to the transition which will go to the state. */
225 out << TABS(level) << "goto tr" << trans->id << ";";
228 /* Go directly to the target state. */
229 out << TABS(level) << "goto st" << trans->targ->id << ";";
234 std::ostream &IpGotoCodeGen::EXIT_STATES()
236 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
237 if ( st->outNeeded ) {
239 out << " _out" << st->id << ": " << CS() << " = " <<
240 st->id << "; goto _out; \n";
246 std::ostream &IpGotoCodeGen::AGAIN_CASES()
248 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
250 " case " << st->id << ": goto st" << st->id << ";\n";
255 std::ostream &IpGotoCodeGen::FINISH_CASES()
257 bool anyWritten = false;
259 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
260 if ( st->eofAction != 0 ) {
261 if ( st->eofAction->eofRefs == 0 )
262 st->eofAction->eofRefs = new IntSet;
263 st->eofAction->eofRefs->insert( st->id );
267 for ( ActionTableMap::Iter act = redFsm->actionMap; act.lte(); act++ ) {
268 if ( act->eofRefs != 0 ) {
269 for ( IntSet::Iter pst = *act->eofRefs; pst.lte(); pst++ )
270 out << " case " << *pst << ": \n";
272 /* Remember that we wrote a trans so we know to write the
273 * line directive for going back to the output. */
276 /* Write each action in the eof action list. */
277 for ( ActionTable::Iter item = act->key; item.lte(); item++ )
278 ACTION( out, item->value, STATE_ERR_STATE, true );
284 genLineDirective( out );
288 void IpGotoCodeGen::setLabelsNeeded( InlineList *inlineList )
290 for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
291 switch ( item->type ) {
292 case InlineItem::Goto: case InlineItem::Call: {
293 /* Mark the target as needing a label. */
294 item->targState->labelNeeded = true;
300 if ( item->children != 0 )
301 setLabelsNeeded( item->children );
305 /* Set up labelNeeded flag for each state. */
306 void IpGotoCodeGen::setLabelsNeeded()
308 /* If we use the _again label, then we the _again switch, which uses all
310 if ( useAgainLabel() ) {
311 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
312 st->labelNeeded = true;
315 /* Do not use all labels by default, init all labelNeeded vars to false. */
316 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
317 st->labelNeeded = false;
319 /* Walk all transitions and set only those that have targs. */
320 for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) {
321 /* If there is no action with a next statement, then the label will be
323 if ( trans->action == 0 || !trans->action->anyNextStmt() )
324 trans->targ->labelNeeded = true;
326 /* Need labels for states that have goto or calls in action code
327 * invoked on characters (ie, not from out action code). */
328 if ( trans->action != 0 ) {
329 /* Loop the actions. */
330 for ( ActionTable::Iter act = trans->action->key; act.lte(); act++ ) {
331 /* Get the action and walk it's tree. */
332 setLabelsNeeded( act->value->inlineList );
339 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
340 st->outNeeded = st->labelNeeded;
343 if ( redFsm->errState != 0 )
344 redFsm->errState->outNeeded = true;
346 for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) {
347 /* Any state with a transition in that has a break will need an
349 if ( trans->action != 0 && trans->action->anyBreakStmt() )
350 trans->targ->outNeeded = true;
355 void IpGotoCodeGen::writeData()
360 void IpGotoCodeGen::writeExec()
362 /* Must set labels immediately before writing because we may depend on the
363 * noend write option. */
365 outLabelUsed = false;
369 if ( redFsm->anyRegCurStateRef() )
370 out << " int _ps = 0;\n";
372 if ( redFsm->anyConditions() )
373 out << " " << WIDE_ALPH_TYPE() << " _widec;\n";
378 " if ( " << P() << " == " << PE() << " )\n"
382 if ( useAgainLabel() ) {
387 " switch ( " << CS() << " ) {\n";
396 " if ( ++" << P() << " == " << PE() << " )\n"
401 " " << P() << " += 1;\n";
408 " switch ( " << CS() << " )\n {\n";
416 out << " _out: {}\n";
422 void IpGotoCodeGen::writeEOF()
424 if ( redFsm->anyEofActions() ) {
427 " switch ( " << CS() << " ) {\n";