2aba78bf94ccc4dc902d3aeaa763ad4b34d55759
[external/ragel.git] / rlcodegen / ftabcodegen.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 "ftabcodegen.h"
26 #include "redfsm.h"
27 #include "gendata.h"
28
29 /* Determine if we should use indicies or not. */
30 void FTabCodeGen::calcIndexSize()
31 {
32         int sizeWithInds = 0, sizeWithoutInds = 0;
33
34         /* Calculate cost of using with indicies. */
35         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
36                 int totalIndex = st->outSingle.length() + st->outRange.length() + 
37                                 (st->defTrans == 0 ? 0 : 1);
38                 sizeWithInds += arrayTypeSize(maxIndex) * totalIndex;
39         }
40         sizeWithInds += arrayTypeSize(maxState) * redFsm->transSet.length();
41         if ( anyActions() )
42                 sizeWithInds += arrayTypeSize(maxActListId) * redFsm->transSet.length();
43
44         /* Calculate the cost of not using indicies. */
45         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
46                 int totalIndex = st->outSingle.length() + st->outRange.length() + 
47                                 (st->defTrans == 0 ? 0 : 1);
48                 sizeWithoutInds += arrayTypeSize(maxState) * totalIndex;
49                 if ( anyActions() )
50                         sizeWithoutInds += arrayTypeSize(maxActListId) * totalIndex;
51         }
52
53         /* If using indicies reduces the size, use them. */
54         useIndicies = sizeWithInds < sizeWithoutInds;
55 }
56
57 std::ostream &FTabCodeGen::TO_STATE_ACTION( RedStateAp *state )
58 {
59         int act = 0;
60         if ( state->toStateAction != 0 )
61                 act = state->toStateAction->actListId+1;
62         out << act;
63         return out;
64 }
65
66 std::ostream &FTabCodeGen::FROM_STATE_ACTION( RedStateAp *state )
67 {
68         int act = 0;
69         if ( state->fromStateAction != 0 )
70                 act = state->fromStateAction->actListId+1;
71         out << act;
72         return out;
73 }
74
75 std::ostream &FTabCodeGen::EOF_ACTION( RedStateAp *state )
76 {
77         int act = 0;
78         if ( state->eofAction != 0 )
79                 act = state->eofAction->actListId+1;
80         out << act;
81         return out;
82 }
83
84
85 /* Write out the function for a transition. */
86 std::ostream &FTabCodeGen::TRANS_ACTION( RedTransAp *trans )
87 {
88         int action = 0;
89         if ( trans->action != 0 )
90                 action = trans->action->actListId+1;
91         out << action;
92         return out;
93 }
94
95 /* Write out the function switch. This switch is keyed on the values
96  * of the func index. */
97 std::ostream &FTabCodeGen::TO_STATE_ACTION_SWITCH()
98 {
99         /* Loop the actions. */
100         for ( ActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
101                 if ( redAct->numToStateRefs > 0 ) {
102                         /* Write the entry label. */
103                         out << "\tcase " << redAct->actListId+1 << ":\n";
104
105                         /* Write each action in the list of action items. */
106                         for ( ActionTable::Iter item = redAct->key; item.lte(); item++ )
107                                 ACTION( out, item->value, 0, false );
108
109                         out << "\tbreak;\n";
110                 }
111         }
112
113         genLineDirective( out );
114         return out;
115 }
116
117 /* Write out the function switch. This switch is keyed on the values
118  * of the func index. */
119 std::ostream &FTabCodeGen::FROM_STATE_ACTION_SWITCH()
120 {
121         /* Loop the actions. */
122         for ( ActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
123                 if ( redAct->numFromStateRefs > 0 ) {
124                         /* Write the entry label. */
125                         out << "\tcase " << redAct->actListId+1 << ":\n";
126
127                         /* Write each action in the list of action items. */
128                         for ( ActionTable::Iter item = redAct->key; item.lte(); item++ )
129                                 ACTION( out, item->value, 0, false );
130
131                         out << "\tbreak;\n";
132                 }
133         }
134
135         genLineDirective( out );
136         return out;
137 }
138
139 std::ostream &FTabCodeGen::EOF_ACTION_SWITCH()
140 {
141         /* Loop the actions. */
142         for ( ActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
143                 if ( redAct->numEofRefs > 0 ) {
144                         /* Write the entry label. */
145                         out << "\tcase " << redAct->actListId+1 << ":\n";
146
147                         /* Write each action in the list of action items. */
148                         for ( ActionTable::Iter item = redAct->key; item.lte(); item++ )
149                                 ACTION( out, item->value, 0, true );
150
151                         out << "\tbreak;\n";
152                 }
153         }
154
155         genLineDirective( out );
156         return out;
157 }
158
159 /* Write out the function switch. This switch is keyed on the values
160  * of the func index. */
161 std::ostream &FTabCodeGen::ACTION_SWITCH()
162 {
163         /* Loop the actions. */
164         for ( ActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
165                 if ( redAct->numTransRefs > 0 ) {
166                         /* Write the entry label. */
167                         out << "\tcase " << redAct->actListId+1 << ":\n";
168
169                         /* Write each action in the list of action items. */
170                         for ( ActionTable::Iter item = redAct->key; item.lte(); item++ )
171                                 ACTION( out, item->value, 0, false );
172
173                         out << "\tbreak;\n";
174                 }
175         }
176
177         genLineDirective( out );
178         return out;
179 }
180
181 void FTabCodeGen::writeOutData()
182 {
183         if ( anyConditions() ) {
184                 OPEN_ARRAY( ARRAY_TYPE(maxCondOffset), CO() );
185                 COND_OFFSETS();
186                 CLOSE_ARRAY() <<
187                 "\n";
188
189                 OPEN_ARRAY( ARRAY_TYPE(maxCondLen), CL() );
190                 COND_LENS();
191                 CLOSE_ARRAY() <<
192                 "\n";
193
194                 OPEN_ARRAY( WIDE_ALPH_TYPE(), CK() );
195                 COND_KEYS();
196                 CLOSE_ARRAY() <<
197                 "\n";
198
199                 OPEN_ARRAY( ARRAY_TYPE(maxCondSpaceId), C() );
200                 COND_SPACES();
201                 CLOSE_ARRAY() <<
202                 "\n";
203         }
204
205         OPEN_ARRAY( ARRAY_TYPE(maxKeyOffset), KO() );
206         KEY_OFFSETS();
207         CLOSE_ARRAY() <<
208         "\n";
209
210         OPEN_ARRAY( WIDE_ALPH_TYPE(), K() );
211         KEYS();
212         CLOSE_ARRAY() <<
213         "\n";
214
215         OPEN_ARRAY( ARRAY_TYPE(maxSingleLen), SL() );
216         SINGLE_LENS();
217         CLOSE_ARRAY() <<
218         "\n";
219
220         OPEN_ARRAY( ARRAY_TYPE(maxRangeLen), RL() );
221         RANGE_LENS();
222         CLOSE_ARRAY() <<
223         "\n";
224
225         OPEN_ARRAY( ARRAY_TYPE(maxIndexOffset), IO() );
226         INDEX_OFFSETS();
227         CLOSE_ARRAY() <<
228         "\n";
229
230         if ( useIndicies ) {
231                 OPEN_ARRAY( ARRAY_TYPE(maxIndex), I() );
232                 INDICIES();
233                 CLOSE_ARRAY() <<
234                 "\n";
235
236                 OPEN_ARRAY( ARRAY_TYPE(maxState), TT() );
237                 TRANS_TARGS_WI();
238                 CLOSE_ARRAY() <<
239                 "\n";
240
241                 if ( anyActions() ) {
242                         OPEN_ARRAY( ARRAY_TYPE(maxActListId), TA() );
243                         TRANS_ACTIONS_WI();
244                         CLOSE_ARRAY() <<
245                         "\n";
246                 }
247         }
248         else {
249                 OPEN_ARRAY( ARRAY_TYPE(maxState), TT() );
250                 TRANS_TARGS();
251                 CLOSE_ARRAY() <<
252                 "\n";
253
254                 if ( anyActions() ) {
255                         OPEN_ARRAY( ARRAY_TYPE(maxActListId), TA() );
256                         TRANS_ACTIONS();
257                         CLOSE_ARRAY() <<
258                         "\n";
259                 }
260         }
261
262         if ( anyToStateActions() ) {
263                 OPEN_ARRAY( ARRAY_TYPE(maxActionLoc), TSA() );
264                 TO_STATE_ACTIONS();
265                 CLOSE_ARRAY() <<
266                 "\n";
267         }
268
269         if ( anyFromStateActions() ) {
270                 OPEN_ARRAY( ARRAY_TYPE(maxActionLoc), FSA() );
271                 FROM_STATE_ACTIONS();
272                 CLOSE_ARRAY() <<
273                 "\n";
274         }
275
276         if ( anyEofActions() ) {
277                 OPEN_ARRAY( ARRAY_TYPE(maxActListId), EA() );
278                 EOF_ACTIONS();
279                 CLOSE_ARRAY() <<
280                 "\n";
281         }
282
283         out <<
284                 "static const int " << START() << " = " << START_STATE_ID() << ";\n"
285                 "\n";
286
287         if ( cgd->writeFirstFinal ) {
288                 out <<
289                         "static const int " << FIRST_FINAL() << " = " << FIRST_FINAL_STATE() << ";\n"
290                         "\n";
291         }
292
293         if ( cgd->writeErr ) {
294                 out <<
295                         "static const int " << ERROR() << " = " << ERROR_STATE() << ";\n"
296                         "\n";
297         }
298 }
299
300 void FTabCodeGen::writeOutExec()
301 {
302         outLabelUsed = false;
303
304         out << 
305                 "       {\n"
306                 "       int _klen";
307
308         if ( anyRegCurStateRef() )
309                 out << ", _ps";
310
311         out <<
312                 ";\n"
313                 "       " << PTR_CONST() << WIDE_ALPH_TYPE() << POINTER() << "_keys;\n"
314                 "       int _trans;\n";
315
316         if ( anyConditions() )
317                 out << "        " << WIDE_ALPH_TYPE() << " _widec;\n";
318
319         out << "\n";
320
321         if ( cgd->hasEnd ) {
322                 outLabelUsed = true;
323                 out <<
324                         "       if ( " << P() << " == " << PE() << " )\n"
325                         "               goto _out;\n";
326         }
327
328         out << "_resume:\n";
329
330         if ( redFsm->errState != 0 ) {
331                 outLabelUsed = true;
332                 out << 
333                         "       if ( " << CS() << " == " << redFsm->errState->id << " )\n"
334                         "               goto _out;\n";
335         }
336
337         if ( anyFromStateActions() ) {
338                 out <<
339                         "       switch ( " << FSA() << "[" << CS() << "] ) {\n";
340                         FROM_STATE_ACTION_SWITCH();
341                         SWITCH_DEFAULT() <<
342                         "       }\n"
343                         "\n";
344         }
345
346         if ( anyConditions() )
347                 COND_TRANSLATE();
348
349         LOCATE_TRANS();
350
351         out << "_match:\n";
352
353         if ( anyRegCurStateRef() )
354                 out << "        _ps = " << CS() << ";\n";
355
356         if ( useIndicies )
357                 out << "        _trans = " << I() << "[_trans];\n";
358
359         out <<
360                 "       " << CS() << " = " << TT() << "[_trans];\n"
361                 "\n";
362
363         if ( anyRegActions() ) {
364                 out << 
365                         "       if ( " << TA() << "[_trans] == 0 )\n"
366                         "               goto _again;\n"
367                         "\n"
368                         "       switch ( " << TA() << "[_trans] ) {\n";
369                         ACTION_SWITCH();
370                         SWITCH_DEFAULT() <<
371                         "       }\n"
372                         "\n";
373         }
374
375         if ( anyRegActions() || anyActionGotos() || anyActionCalls() || anyActionRets() )
376                 out << "_again:\n";
377
378         if ( anyToStateActions() ) {
379                 out <<
380                         "       switch ( " << TSA() << "[" << CS() << "] ) {\n";
381                         TO_STATE_ACTION_SWITCH();
382                         SWITCH_DEFAULT() <<
383                         "       }\n"
384                         "\n";
385         }
386
387         if ( cgd->hasEnd ) {
388                 out << 
389                         "       if ( ++" << P() << " != " << PE() << " )\n"
390                         "               goto _resume;\n";
391         }
392         else {
393                 out << 
394                         "       " << P() << " += 1;\n"
395                         "       goto _resume;\n";
396         }
397
398
399         if ( outLabelUsed )
400                 out << "        _out: {}\n";
401
402         out << "        }\n";
403 }
404
405
406 void FTabCodeGen::writeOutEOF()
407 {
408         if ( anyEofActions() ) {
409                 out <<
410                         "       {\n"
411                         "       switch ( " << EA() << "[" << CS() << "] ) {\n";
412                         EOF_ACTION_SWITCH();
413                         SWITCH_DEFAULT() <<
414                         "       }\n"
415                         "       }\n"
416                         "\n";
417         }
418 }