34ef47c0de4031b2e9392903ca1b23b53604ea80
[external/ragel.git] / rlcodegen / fgotocodegen.cpp
1 /*
2  *  Copyright 2001-2006 Adrian Thurston <thurston@cs.queensu.ca>
3  *            2004 Eric 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 "rlcodegen.h"
25 #include "fgotocodegen.h"
26 #include "redfsm.h"
27 #include "gendata.h"
28 #include "bstmap.h"
29
30 std::ostream &FGotoCodeGen::EXEC_ACTIONS()
31 {
32         /* Loop the actions. */
33         for ( ActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
34                 if ( redAct->numTransRefs > 0 ) {
35                         /*      We are at the start of a glob, write the case. */
36                         out << "f" << redAct->actListId << ":\n";
37
38                         /* Write each action in the list of action items. */
39                         for ( ActionTable::Iter item = redAct->key; item.lte(); item++ )
40                                 ACTION( out, item->value, 0, false );
41
42                         out << "\tgoto _again;\n";
43                 }
44         }
45         return out;
46 }
47
48 /* Write out the function switch. This switch is keyed on the values
49  * of the func index. */
50 std::ostream &FGotoCodeGen::TO_STATE_ACTION_SWITCH()
51 {
52         /* Loop the actions. */
53         for ( ActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
54                 if ( redAct->numToStateRefs > 0 ) {
55                         /* Write the entry label. */
56                         out << "\tcase " << redAct->actListId+1 << ":\n";
57
58                         /* Write each action in the list of action items. */
59                         for ( ActionTable::Iter item = redAct->key; item.lte(); item++ )
60                                 ACTION( out, item->value, 0, false );
61
62                         out << "\tbreak;\n";
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. */
72 std::ostream &FGotoCodeGen::FROM_STATE_ACTION_SWITCH()
73 {
74         /* Loop the actions. */
75         for ( ActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
76                 if ( redAct->numFromStateRefs > 0 ) {
77                         /* Write the entry label. */
78                         out << "\tcase " << redAct->actListId+1 << ":\n";
79
80                         /* Write each action in the list of action items. */
81                         for ( ActionTable::Iter item = redAct->key; item.lte(); item++ )
82                                 ACTION( out, item->value, 0, false );
83
84                         out << "\tbreak;\n";
85                 }
86         }
87
88         genLineDirective( out );
89         return out;
90 }
91
92 std::ostream &FGotoCodeGen::EOF_ACTION_SWITCH()
93 {
94         /* Loop the actions. */
95         for ( ActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
96                 if ( redAct->numEofRefs > 0 ) {
97                         /* Write the entry label. */
98                         out << "\tcase " << redAct->actListId+1 << ":\n";
99
100                         /* Write each action in the list of action items. */
101                         for ( ActionTable::Iter item = redAct->key; item.lte(); item++ )
102                                 ACTION( out, item->value, 0, true );
103
104                         out << "\tbreak;\n";
105                 }
106         }
107
108         genLineDirective( out );
109         return out;
110 }
111
112
113 std::ostream &FGotoCodeGen::FINISH_CASES()
114 {
115         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
116                 /* States that are final and have an out action need a case. */
117                 if ( st->eofAction != 0 ) {
118                         /* Write the case label. */
119                         out << "\t\tcase " << st->id << ": ";
120
121                         /* Jump to the func. */
122                         out << "goto f" << st->eofAction->actListId << ";\n";
123                 }
124         }
125
126         return out;
127 }
128
129 unsigned int FGotoCodeGen::TO_STATE_ACTION( RedStateAp *state )
130 {
131         int act = 0;
132         if ( state->toStateAction != 0 )
133                 act = state->toStateAction->actListId+1;
134         return act;
135 }
136
137 unsigned int FGotoCodeGen::FROM_STATE_ACTION( RedStateAp *state )
138 {
139         int act = 0;
140         if ( state->fromStateAction != 0 )
141                 act = state->fromStateAction->actListId+1;
142         return act;
143 }
144
145 unsigned int FGotoCodeGen::EOF_ACTION( RedStateAp *state )
146 {
147         int act = 0;
148         if ( state->eofAction != 0 )
149                 act = state->eofAction->actListId+1;
150         return act;
151 }
152
153 void FGotoCodeGen::writeOutData()
154 {
155         out <<
156                 "static const int " << START() << " = " << START_STATE_ID() << ";\n"
157                 "\n";
158
159         if ( cgd->writeFirstFinal ) {
160                 out <<
161                         "static const int " << FIRST_FINAL() << " = " << FIRST_FINAL_STATE() << ";\n"
162                         "\n";
163         }
164
165         if ( cgd->writeErr ) {
166                 out <<
167                         "static const int " << ERROR() << " = " << ERROR_STATE() << ";\n"
168                         "\n";
169         }
170
171         if ( anyToStateActions() ) {
172                 OPEN_ARRAY( ARRAY_TYPE(maxActionLoc), TSA() );
173                 TO_STATE_ACTIONS();
174                 CLOSE_ARRAY() <<
175                 "\n";
176         }
177
178         if ( anyFromStateActions() ) {
179                 OPEN_ARRAY( ARRAY_TYPE(maxActionLoc), FSA() );
180                 FROM_STATE_ACTIONS();
181                 CLOSE_ARRAY() <<
182                 "\n";
183         }
184
185         if ( anyEofActions() ) {
186                 OPEN_ARRAY( ARRAY_TYPE(maxActionLoc), EA() );
187                 EOF_ACTIONS();
188                 CLOSE_ARRAY() <<
189                 "\n";
190         }
191 }
192
193 void FGotoCodeGen::writeOutExec()
194 {
195         outLabelUsed = false;
196
197         out << "        {\n";
198
199         if ( anyRegCurStateRef() )
200                 out << "        int _ps = 0;\n";
201
202         if ( anyConditions() )
203                 out << "        " << WIDE_ALPH_TYPE() << " _widec;\n";
204
205         if ( cgd->hasEnd ) {
206                 outLabelUsed = true;
207                 out << 
208                         "       if ( " << P() << " == " << PE() << " )\n"
209                         "               goto _out;\n";
210         }
211
212         out << "_resume:\n";
213
214         if ( anyFromStateActions() ) {
215                 out <<
216                         "       switch ( " << FSA() << "[" << CS() << "] ) {\n";
217                         FROM_STATE_ACTION_SWITCH();
218                         SWITCH_DEFAULT() <<
219                         "       }\n"
220                         "\n";
221         }
222
223         out << 
224                 "       switch ( " << CS() << " ) {\n";
225                 STATE_GOTOS();
226                 SWITCH_DEFAULT() <<
227                 "       }\n"
228                 "\n";
229                 TRANSITIONS() << 
230                 "\n";
231
232         if ( anyRegActions() )
233                 EXEC_ACTIONS() << "\n";
234
235         out << "_again:\n";
236
237         if ( anyToStateActions() ) {
238                 out <<
239                         "       switch ( " << TSA() << "[" << CS() << "] ) {\n";
240                         TO_STATE_ACTION_SWITCH();
241                         SWITCH_DEFAULT() <<
242                         "       }\n"
243                         "\n";
244         }
245
246         if ( cgd->hasEnd ) {
247                 out << 
248                         "       if ( ++" << P() << " != " << PE() << " )\n"
249                         "               goto _resume;\n";
250         }
251         else {
252                 out << 
253                         "       " << P() << " += 1;\n"
254                         "       goto _resume;\n";
255         }
256
257
258         if ( outLabelUsed )
259                 out << "        _out: {}\n";
260
261         out << "        }\n";
262 }
263
264 void FGotoCodeGen::writeOutEOF()
265 {
266         if ( anyEofActions() ) {
267                 out <<
268                         "       {\n"
269                         "       switch ( " << EA() << "[" << CS() << "] ) {\n";
270                         EOF_ACTION_SWITCH();
271                         SWITCH_DEFAULT() <<
272                         "       }\n"
273                         "       }\n"
274                         "\n";
275         }
276 }