Updated to the latest aapl. This completely eliminates the shallowCopy
[external/ragel.git] / redfsm / redfsm.cpp
1 /*
2  *  Copyright 2001-2006 Adrian Thurston <thurston@cs.queensu.ca>
3  */
4
5 /*  This file is part of Ragel.
6  *
7  *  Ragel is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  * 
12  *  Ragel is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  * 
17  *  You should have received a copy of the GNU General Public License
18  *  along with Ragel; if not, write to the Free Software
19  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
20  */
21
22 #include "redfsm.h"
23 #include "avlmap.h"
24 #include <iostream>
25 #include <sstream>
26
27 using std::ostringstream;
28
29 KeyOps *keyOps = 0;
30
31 string Action::nameOrLoc()
32 {
33         if ( name != 0 )
34                 return string(name);
35         else {
36                 ostringstream ret;
37                 ret << loc.line << ":" << loc.col;
38                 return ret.str();
39         }
40 }
41
42 RedFsmAp::RedFsmAp()
43 :
44         wantComplete(false),
45         forcedErrorState(false),
46         nextActionId(0),
47         nextTransId(0),
48         errState(0),
49         errTrans(0),
50         firstFinState(0),
51         numFinStates(0),
52         bAnyToStateActions(false),
53         bAnyFromStateActions(false),
54         bAnyRegActions(false),
55         bAnyEofActions(false),
56         bAnyActionGotos(false),
57         bAnyActionCalls(false),
58         bAnyActionRets(false),
59         bAnyRegActionRets(false),
60         bAnyRegActionByValControl(false),
61         bAnyRegNextStmt(false),
62         bAnyRegCurStateRef(false),
63         bAnyRegBreak(false),
64         bAnyLmSwitchError(false),
65         bAnyConditions(false)
66 {
67 }
68
69 /* Does the machine have any actions. */
70 bool RedFsmAp::anyActions()
71 {
72         return actionMap.length() > 0;
73 }
74
75 void RedFsmAp::depthFirstOrdering( RedStateAp *state )
76 {
77         /* Nothing to do if the state is already on the list. */
78         if ( state->onStateList )
79                 return;
80
81         /* Doing depth first, put state on the list. */
82         state->onStateList = true;
83         stateList.append( state );
84         
85         /* At this point transitions should only be in ranges. */
86         assert( state->outSingle.length() == 0 );
87         assert( state->defTrans == 0 );
88
89         /* Recurse on everything ranges. */
90         for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) {
91                 if ( rtel->value->targ != 0 )
92                         depthFirstOrdering( rtel->value->targ );
93         }
94 }
95
96 /* Ordering states by transition connections. */
97 void RedFsmAp::depthFirstOrdering()
98 {
99         /* Init on state list flags. */
100         for ( RedStateList::Iter st = stateList; st.lte(); st++ )
101                 st->onStateList = false;
102         
103         /* Clear out the state list, we will rebuild it. */
104         int stateListLen = stateList.length();
105         stateList.abandon();
106
107         /* Add back to the state list from the start state and all other entry
108          * points. */
109         depthFirstOrdering( startState );
110         for ( RedStateSet::Iter en = entryPoints; en.lte(); en++ )
111                 depthFirstOrdering( *en );
112         if ( forcedErrorState )
113                 depthFirstOrdering( errState );
114         
115         /* Make sure we put everything back on. */
116         assert( stateListLen == stateList.length() );
117 }
118
119 /* Assign state ids by appearance in the state list. */
120 void RedFsmAp::sequentialStateIds()
121 {
122         /* Table based machines depend on the state numbers starting at zero. */
123         nextStateId = 0;
124         for ( RedStateList::Iter st = stateList; st.lte(); st++ )
125                 st->id = nextStateId++;
126 }
127
128 /* Stable sort the states by final state status. */
129 void RedFsmAp::sortStatesByFinal()
130 {
131         /* Move forward through the list and throw final states onto the end. */
132         RedStateAp *state = 0;
133         RedStateAp *next = stateList.head;
134         RedStateAp *last = stateList.tail;
135         while ( state != last ) {
136                 /* Move forward and load up the next. */
137                 state = next;
138                 next = state->next;
139
140                 /* Throw to the end? */
141                 if ( state->isFinal ) {
142                         stateList.detach( state );
143                         stateList.append( state );
144                 }
145         }
146 }
147
148 /* Assign state ids by final state state status. */
149 void RedFsmAp::sortStateIdsByFinal()
150 {
151         /* Table based machines depend on this starting at zero. */
152         nextStateId = 0;
153
154         /* First pass to assign non final ids. */
155         for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
156                 if ( ! st->isFinal ) 
157                         st->id = nextStateId++;
158         }
159
160         /* Second pass to assign final ids. */
161         for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
162                 if ( st->isFinal ) 
163                         st->id = nextStateId++;
164         }
165 }
166
167 void RedFsmAp::sortByStateId()
168 {
169         /* FIXME: Implement. */
170 }
171
172 /* Find the final state with the lowest id. */
173 void RedFsmAp::findFirstFinState()
174 {
175         for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
176                 if ( st->isFinal && (firstFinState == 0 || st->id < firstFinState->id) )
177                         firstFinState = st;
178         }
179 }
180
181 void RedFsmAp::assignActionLocs()
182 {
183         int nextLocation = 0;
184         for ( ActionTableMap::Iter act = actionMap; act.lte(); act++ ) {
185                 /* Store the loc, skip over the array and a null terminator. */
186                 act->location = nextLocation;
187                 nextLocation += act->key.length() + 1;          
188         }
189 }
190
191 /* Check if we can extend the current range by displacing any ranges
192  * ahead to the singles. */
193 bool RedFsmAp::canExtend( const RedTransList &list, int pos )
194 {
195         /* Get the transition that we want to extend. */
196         RedTransAp *extendTrans = list[pos].value;
197
198         /* Look ahead in the transition list. */
199         for ( int next = pos + 1; next < list.length(); pos++, next++ ) {
200                 /* If they are not continuous then cannot extend. */
201                 Key nextKey = list[next].lowKey;
202                 nextKey.decrement();
203                 if ( list[pos].highKey != nextKey )
204                         break;
205
206                 /* Check for the extenstion property. */
207                 if ( extendTrans == list[next].value )
208                         return true;
209
210                 /* If the span of the next element is more than one, then don't keep
211                  * checking, it won't be moved to single. */
212                 unsigned long long nextSpan = keyOps->span( list[next].lowKey, list[next].highKey );
213                 if ( nextSpan > 1 )
214                         break;
215         }
216         return false;
217 }
218
219 /* Move ranges to the singles list. */
220 void RedFsmAp::moveTransToSingle( RedStateAp *state )
221 {
222         RedTransList &range = state->outRange;
223         RedTransList &single = state->outSingle;
224         for ( int rpos = 0; rpos < range.length(); ) {
225                 /* Check if this is a range we can extend. */
226                 if ( canExtend( range, rpos ) ) {
227                         /* Transfer singles over. */
228                         while ( range[rpos].value != range[rpos+1].value ) {
229                                 /* Transfer the range to single. */
230                                 single.append( range[rpos+1] );
231                                 range.remove( rpos+1 );
232                         }
233                         
234                         /* Extend. */
235                         range[rpos].highKey = range[rpos+1].highKey;
236                         range.remove( rpos+1 );
237                 }
238                 /* Maybe move it to the singles. */
239                 else if ( keyOps->span( range[rpos].lowKey, range[rpos].highKey ) == 1 ) {
240                         single.append( range[rpos] );
241                         range.remove( rpos );
242                 }
243                 else {
244                         /* Keeping it in the ranges. */
245                         rpos += 1;
246                 }
247         }
248 }
249
250 /* Look through ranges and choose suitable single character transitions. */
251 void RedFsmAp::chooseSingle()
252 {
253         /* Loop the states. */
254         for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
255                 /* Rewrite the transition list taking out the suitable single
256                  * transtions. */
257                 moveTransToSingle( st );
258         }
259 }
260
261 void RedFsmAp::makeFlat()
262 {
263         for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
264                 if ( st->stateCondList.length() == 0 ) {
265                         st->condLowKey = 0;
266                         st->condHighKey = 0;
267                 }
268                 else {
269                         st->condLowKey = st->stateCondList.head->lowKey;
270                         st->condHighKey = st->stateCondList.tail->highKey;
271
272                         unsigned long long span = keyOps->span( st->condLowKey, st->condHighKey );
273                         st->condList = new CondSpace*[ span ];
274                         memset( st->condList, 0, sizeof(CondSpace*)*span );
275
276                         for ( StateCondList::Iter sci = st->stateCondList; sci.lte(); sci++ ) {
277                                 unsigned long long base, trSpan;
278                                 base = keyOps->span( st->condLowKey, sci->lowKey )-1;
279                                 trSpan = keyOps->span( sci->lowKey, sci->highKey );
280                                 for ( unsigned long long pos = 0; pos < trSpan; pos++ )
281                                         st->condList[base+pos] = sci->condSpace;
282                         }
283                 }
284
285                 if ( st->outRange.length() == 0 ) {
286                         st->lowKey = st->highKey = 0;
287                         st->transList = 0;
288                 }
289                 else {
290                         st->lowKey = st->outRange[0].lowKey;
291                         st->highKey = st->outRange[st->outRange.length()-1].highKey;
292                         unsigned long long span = keyOps->span( st->lowKey, st->highKey );
293                         st->transList = new RedTransAp*[ span ];
294                         memset( st->transList, 0, sizeof(RedTransAp*)*span );
295                         
296                         for ( RedTransList::Iter trans = st->outRange; trans.lte(); trans++ ) {
297                                 unsigned long long base, trSpan;
298                                 base = keyOps->span( st->lowKey, trans->lowKey )-1;
299                                 trSpan = keyOps->span( trans->lowKey, trans->highKey );
300                                 for ( unsigned long long pos = 0; pos < trSpan; pos++ )
301                                         st->transList[base+pos] = trans->value;
302                         }
303
304                         /* Fill in the gaps with the default transition. */
305                         for ( unsigned long long pos = 0; pos < span; pos++ ) {
306                                 if ( st->transList[pos] == 0 )
307                                         st->transList[pos] = st->defTrans;
308                         }
309                 }
310         }
311 }
312
313
314 /* A default transition has been picked, move it from the outRange to the
315  * default pointer. */
316 void RedFsmAp::moveToDefault( RedTransAp *defTrans, RedStateAp *state )
317 {
318         /* Rewrite the outRange, omitting any ranges that use 
319          * the picked default. */
320         RedTransList outRange;
321         for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) {
322                 /* If it does not take the default, copy it over. */
323                 if ( rtel->value != defTrans )
324                         outRange.append( *rtel );
325         }
326
327         /* Save off the range we just created into the state's range. */
328         state->outRange.transfer( outRange );
329
330         /* Store the default. */
331         state->defTrans = defTrans;
332 }
333
334 bool RedFsmAp::alphabetCovered( RedTransList &outRange )
335 {
336         /* Cannot cover without any out ranges. */
337         if ( outRange.length() == 0 )
338                 return false;
339
340         /* If the first range doesn't start at the the lower bound then the
341          * alphabet is not covered. */
342         RedTransList::Iter rtel = outRange;
343         if ( keyOps->minKey < rtel->lowKey )
344                 return false;
345
346         /* Check that every range is next to the previous one. */
347         rtel.increment();
348         for ( ; rtel.lte(); rtel++ ) {
349                 Key highKey = rtel[-1].highKey;
350                 highKey.increment();
351                 if ( highKey != rtel->lowKey )
352                         return false;
353         }
354
355         /* The last must extend to the upper bound. */
356         RedTransEl *last = &outRange[outRange.length()-1];
357         if ( last->highKey < keyOps->maxKey )
358                 return false;
359
360         return true;
361 }
362
363 RedTransAp *RedFsmAp::chooseDefaultSpan( RedStateAp *state )
364 {
365         /* Make a set of transitions from the outRange. */
366         RedTransSet stateTransSet;
367         for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ )
368                 stateTransSet.insert( rtel->value );
369         
370         /* For each transition in the find how many alphabet characters the
371          * transition spans. */
372         unsigned long long *span = new unsigned long long[stateTransSet.length()];
373         memset( span, 0, sizeof(unsigned long long) * stateTransSet.length() );
374         for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) {
375                 /* Lookup the transition in the set. */
376                 RedTransAp **inSet = stateTransSet.find( rtel->value );
377                 int pos = inSet - stateTransSet.data;
378                 span[pos] += keyOps->span( rtel->lowKey, rtel->highKey );
379         }
380
381         /* Find the max span, choose it for making the default. */
382         RedTransAp *maxTrans = 0;
383         unsigned long long maxSpan = 0;
384         for ( RedTransSet::Iter rtel = stateTransSet; rtel.lte(); rtel++ ) {
385                 if ( span[rtel.pos()] > maxSpan ) {
386                         maxSpan = span[rtel.pos()];
387                         maxTrans = *rtel;
388                 }
389         }
390
391         delete[] span;
392         return maxTrans;
393 }
394
395 /* Pick default transitions from ranges for the states. */
396 void RedFsmAp::chooseDefaultSpan()
397 {
398         /* Loop the states. */
399         for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
400                 /* Only pick a default transition if the alphabet is covered. This
401                  * avoids any transitions in the out range that go to error and avoids
402                  * the need for an ERR state. */
403                 if ( alphabetCovered( st->outRange ) ) {
404                         /* Pick a default transition by largest span. */
405                         RedTransAp *defTrans = chooseDefaultSpan( st );
406
407                         /* Rewrite the transition list taking out the transition we picked
408                          * as the default and store the default. */
409                         moveToDefault( defTrans, st );
410                 }
411         }
412 }
413
414 RedTransAp *RedFsmAp::chooseDefaultGoto( RedStateAp *state )
415 {
416         /* Make a set of transitions from the outRange. */
417         RedTransSet stateTransSet;
418         for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) {
419                 if ( rtel->value->targ == state->next )
420                         return rtel->value;
421         }
422         return 0;
423 }
424
425 void RedFsmAp::chooseDefaultGoto()
426 {
427         /* Loop the states. */
428         for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
429                 /* Pick a default transition. */
430                 RedTransAp *defTrans = chooseDefaultGoto( st );
431                 if ( defTrans == 0 )
432                         defTrans = chooseDefaultSpan( st );
433
434                 /* Rewrite the transition list taking out the transition we picked
435                  * as the default and store the default. */
436                 moveToDefault( defTrans, st );
437         }
438 }
439
440 RedTransAp *RedFsmAp::chooseDefaultNumRanges( RedStateAp *state )
441 {
442         /* Make a set of transitions from the outRange. */
443         RedTransSet stateTransSet;
444         for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ )
445                 stateTransSet.insert( rtel->value );
446         
447         /* For each transition in the find how many ranges use the transition. */
448         int *numRanges = new int[stateTransSet.length()];
449         memset( numRanges, 0, sizeof(int) * stateTransSet.length() );
450         for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) {
451                 /* Lookup the transition in the set. */
452                 RedTransAp **inSet = stateTransSet.find( rtel->value );
453                 numRanges[inSet - stateTransSet.data] += 1;
454         }
455
456         /* Find the max number of ranges. */
457         RedTransAp *maxTrans = 0;
458         int maxNumRanges = 0;
459         for ( RedTransSet::Iter rtel = stateTransSet; rtel.lte(); rtel++ ) {
460                 if ( numRanges[rtel.pos()] > maxNumRanges ) {
461                         maxNumRanges = numRanges[rtel.pos()];
462                         maxTrans = *rtel;
463                 }
464         }
465
466         delete[] numRanges;
467         return maxTrans;
468 }
469
470 void RedFsmAp::chooseDefaultNumRanges()
471 {
472         /* Loop the states. */
473         for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
474                 /* Pick a default transition. */
475                 RedTransAp *defTrans = chooseDefaultNumRanges( st );
476
477                 /* Rewrite the transition list taking out the transition we picked
478                  * as the default and store the default. */
479                 moveToDefault( defTrans, st );
480         }
481 }
482
483 RedTransAp *RedFsmAp::getErrorTrans( )
484 {
485         /* If the error trans has not been made aready, make it. */
486         if ( errTrans == 0 ) {
487                 /* This insert should always succeed since no transition created by
488                  * the user can point to the error state. */
489                 errTrans = new RedTransAp( getErrorState(), 0, nextTransId++ );
490                 RedTransAp *inRes = transSet.insert( errTrans );
491                 assert( inRes != 0 );
492         }
493         return errTrans;
494 }
495
496 RedStateAp *RedFsmAp::getErrorState()
497 {
498         /* Something went wrong. An error state is needed but one was not supplied
499          * by the frontend. */
500         assert( errState != 0 );
501         return errState;
502 }
503
504
505 RedTransAp *RedFsmAp::allocateTrans( RedStateAp *targ, RedAction *action )
506 {
507         /* Create a reduced trans and look for it in the transiton set. */
508         RedTransAp redTrans( targ, action, 0 );
509         RedTransAp *inDict = transSet.find( &redTrans );
510         if ( inDict == 0 ) {
511                 inDict = new RedTransAp( targ, action, nextTransId++ );
512                 transSet.insert( inDict );
513         }
514         return inDict;
515 }
516
517 void RedFsmAp::partitionFsm( int nparts )
518 {
519         /* At this point the states are ordered by a depth-first traversal. We
520          * will allocate to partitions based on this ordering. */
521         this->nParts = nparts;
522         int partSize = stateList.length() / nparts;
523         int remainder = stateList.length() % nparts;
524         int numInPart = partSize;
525         int partition = 0;
526         if ( remainder-- > 0 )
527                 numInPart += 1;
528         for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
529                 st->partition = partition;
530
531                 numInPart -= 1;
532                 if ( numInPart == 0 ) {
533                         partition += 1;
534                         numInPart = partSize;
535                         if ( remainder-- > 0 )
536                                 numInPart += 1;
537                 }
538         }
539 }
540
541 void RedFsmAp::setInTrans()
542 {
543         /* First pass counts the number of transitions. */
544         for ( TransApSet::Iter trans = transSet; trans.lte(); trans++ )
545                 trans->targ->numInTrans += 1;
546
547         /* Pass over states to allocate the needed memory. Reset the counts so we
548          * can use them as the current size. */
549         for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
550                 st->inTrans = new RedTransAp*[st->numInTrans];
551                 st->numInTrans = 0;
552         }
553
554         /* Second pass over transitions copies pointers into the in trans list. */
555         for ( TransApSet::Iter trans = transSet; trans.lte(); trans++ )
556                 trans->targ->inTrans[trans->targ->numInTrans++] = trans;
557 }