Implemented makeLmSwitch and started making calls to makeGenInlineList.
[external/ragel.git] / redfsm / gendata.cpp
1 /*
2  *  Copyright 2005-2007 Adrian Thurston <thurston@complang.org>
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 "gendata.h"
23 #include <iostream>
24
25 using std::cerr;
26 using std::endl;
27
28 /* Total error count. */
29 /* int gblErrorCount = 0; */
30
31 CodeGenData::CodeGenData( ostream &out )
32 :
33         sourceFileName(0),
34         fsmName(0), 
35         out(out),
36         redFsm(0), 
37         allActions(0),
38         allActionTables(0),
39         allConditions(0),
40         allCondSpaces(0),
41         allStates(0),
42         nameIndex(0),
43         startState(-1),
44         errState(-1),
45         getKeyExpr(0),
46         accessExpr(0),
47         prePushExpr(0),
48         postPopExpr(0),
49         pExpr(0),
50         peExpr(0),
51         eofExpr(0),
52         csExpr(0),
53         topExpr(0),
54         stackExpr(0),
55         actExpr(0),
56         tokstartExpr(0),
57         tokendExpr(0),
58         dataExpr(0),
59         wantComplete(0),
60         hasLongestMatch(false),
61         hasEnd(true),
62         dataPrefix(true),
63         writeFirstFinal(true),
64         writeErr(true),
65         writeCS(true)
66 {}
67
68
69 void CodeGenData::createMachine()
70 {
71         redFsm = new RedFsmAp();
72 }
73
74 void CodeGenData::initActionList( unsigned long length )
75
76         allActions = new GenAction[length];
77         for ( unsigned long a = 0; a < length; a++ )
78                 actionList.append( allActions+a );
79 }
80
81 void CodeGenData::newAction( int anum, char *name, int line, 
82                 int col, GenInlineList *inlineList )
83 {
84         allActions[anum].actionId = anum;
85         allActions[anum].name = name;
86         allActions[anum].loc.line = line;
87         allActions[anum].loc.col = col;
88         allActions[anum].inlineList = inlineList;
89 }
90
91 void CodeGenData::initActionTableList( unsigned long length )
92
93         allActionTables = new RedAction[length];
94 }
95
96 void CodeGenData::initStateList( unsigned long length )
97 {
98         allStates = new RedStateAp[length];
99         for ( unsigned long s = 0; s < length; s++ )
100                 redFsm->stateList.append( allStates+s );
101
102         /* We get the start state as an offset, set the pointer now. */
103         if ( startState >= 0 )
104                 redFsm->startState = allStates + startState;
105         if ( errState >= 0 )
106                 redFsm->errState = allStates + errState;
107         for ( EntryIdVect::Iter en = entryPointIds; en.lte(); en++ )
108                 redFsm->entryPoints.insert( allStates + *en );
109
110         /* The nextStateId is no longer used to assign state ids (they come in set
111          * from the frontend now), however generation code still depends on it.
112          * Should eventually remove this variable. */
113         redFsm->nextStateId = redFsm->stateList.length();
114 }
115
116 void CodeGenData::setStartState( unsigned long startState )
117 {
118         this->startState = startState;
119 }
120
121 void CodeGenData::setErrorState( unsigned long errState )
122 {
123         this->errState = errState;
124 }
125
126 void CodeGenData::addEntryPoint( char *name, unsigned long entryState )
127 {
128         entryPointIds.append( entryState );
129         entryPointNames.append( name );
130 }
131
132 void CodeGenData::initTransList( int snum, unsigned long length )
133 {
134         /* Could preallocate the out range to save time growing it. For now do
135          * nothing. */
136 }
137
138 void CodeGenData::newTrans( int snum, int tnum, Key lowKey, 
139                 Key highKey, long targ, long action )
140 {
141         /* Get the current state and range. */
142         RedStateAp *curState = allStates + snum;
143         RedTransList &destRange = curState->outRange;
144
145         if ( curState == redFsm->errState )
146                 return;
147
148         /* Make the new transitions. */
149         RedStateAp *targState = targ >= 0 ? (allStates + targ) : 
150                         wantComplete ? redFsm->getErrorState() : 0;
151         RedAction *actionTable = action >= 0 ? (allActionTables + action) : 0;
152         RedTransAp *trans = redFsm->allocateTrans( targState, actionTable );
153         RedTransEl transEl( lowKey, highKey, trans );
154
155         if ( wantComplete ) {
156                 /* If the machine is to be complete then we need to fill any gaps with
157                  * the error transitions. */
158                 if ( destRange.length() == 0 ) {
159                         /* Range is currently empty. */
160                         if ( keyOps->minKey < lowKey ) {
161                                 /* The first range doesn't start at the low end. */
162                                 Key fillHighKey = lowKey;
163                                 fillHighKey.decrement();
164
165                                 /* Create the filler with the state's error transition. */
166                                 RedTransEl newTel( keyOps->minKey, fillHighKey, redFsm->getErrorTrans() );
167                                 destRange.append( newTel );
168                         }
169                 }
170                 else {
171                         /* The range list is not empty, get the the last range. */
172                         RedTransEl *last = &destRange[destRange.length()-1];
173                         Key nextKey = last->highKey;
174                         nextKey.increment();
175                         if ( nextKey < lowKey ) {
176                                 /* There is a gap to fill. Make the high key. */
177                                 Key fillHighKey = lowKey;
178                                 fillHighKey.decrement();
179
180                                 /* Create the filler with the state's error transtion. */
181                                 RedTransEl newTel( nextKey, fillHighKey, redFsm->getErrorTrans() );
182                                 destRange.append( newTel );
183                         }
184                 }
185         }
186
187         /* Filler taken care of. Append the range. */
188         destRange.append( RedTransEl( lowKey, highKey, trans ) );
189 }
190
191 void CodeGenData::finishTransList( int snum )
192 {
193         /* Get the current state and range. */
194         RedStateAp *curState = allStates + snum;
195         RedTransList &destRange = curState->outRange;
196
197         if ( curState == redFsm->errState )
198                 return;
199
200         /* If building a complete machine we may need filler on the end. */
201         if ( wantComplete ) {
202                 /* Check if there are any ranges already. */
203                 if ( destRange.length() == 0 ) {
204                         /* Fill with the whole alphabet. */
205                         /* Add the range on the lower and upper bound. */
206                         RedTransEl newTel( keyOps->minKey, keyOps->maxKey, redFsm->getErrorTrans() );
207                         destRange.append( newTel );
208                 }
209                 else {
210                         /* Get the last and check for a gap on the end. */
211                         RedTransEl *last = &destRange[destRange.length()-1];
212                         if ( last->highKey < keyOps->maxKey ) {
213                                 /* Make the high key. */
214                                 Key fillLowKey = last->highKey;
215                                 fillLowKey.increment();
216
217                                 /* Create the new range with the error trans and append it. */
218                                 RedTransEl newTel( fillLowKey, keyOps->maxKey, redFsm->getErrorTrans() );
219                                 destRange.append( newTel );
220                         }
221                 }
222         }
223 }
224
225 void CodeGenData::setId( int snum, int id )
226 {
227         RedStateAp *curState = allStates + snum;
228         curState->id = id;
229 }
230
231 void CodeGenData::setFinal( int snum )
232 {
233         RedStateAp *curState = allStates + snum;
234         curState->isFinal = true;
235 }
236
237
238 void CodeGenData::setStateActions( int snum, long toStateAction, 
239                 long fromStateAction, long eofAction )
240 {
241         RedStateAp *curState = allStates + snum;
242         if ( toStateAction >= 0 )
243                 curState->toStateAction = allActionTables + toStateAction;
244         if ( fromStateAction >= 0 )
245                 curState->fromStateAction = allActionTables + fromStateAction;
246         if ( eofAction >= 0 )
247                 curState->eofAction = allActionTables + eofAction;
248 }
249
250 void CodeGenData::setEofTrans( int snum, long eofTarget, long actId )
251 {
252         RedStateAp *curState = allStates + snum;
253         RedStateAp *targState = allStates + eofTarget;
254         RedAction *eofAct = allActionTables + actId;
255         curState->eofTrans = redFsm->allocateTrans( targState, eofAct );
256 }
257
258 void CodeGenData::resolveTargetStates( GenInlineList *inlineList )
259 {
260         for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) {
261                 switch ( item->type ) {
262                 case GenInlineItem::Goto: case GenInlineItem::Call:
263                 case GenInlineItem::Next: case GenInlineItem::Entry:
264                         item->targState = allStates + item->targId;
265                         break;
266                 default:
267                         break;
268                 }
269
270                 if ( item->children != 0 )
271                         resolveTargetStates( item->children );
272         }
273 }
274
275 void CodeGenData::closeMachine()
276 {
277         for ( GenActionList::Iter a = actionList; a.lte(); a++ )
278                 resolveTargetStates( a->inlineList );
279
280         /* Note that even if we want a complete graph we do not give the error
281          * state a default transition. All machines break out of the processing
282          * loop when in the error state. */
283
284         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
285                 for ( GenStateCondList::Iter sci = st->stateCondList; sci.lte(); sci++ )
286                         st->stateCondVect.append( sci );
287         }
288 }
289
290
291 bool CodeGenData::setAlphType( const char *data )
292 {
293         HostType *alphType = findAlphTypeInternal( data );
294         if ( alphType == 0 )
295                 return false;
296
297         thisKeyOps.setAlphType( alphType );
298         return true;
299 }
300
301 void CodeGenData::initCondSpaceList( ulong length )
302 {
303         allCondSpaces = new GenCondSpace[length];
304         for ( ulong c = 0; c < length; c++ )
305                 condSpaceList.append( allCondSpaces + c );
306 }
307
308 void CodeGenData::newCondSpace( int cnum, int condSpaceId, Key baseKey )
309 {
310         GenCondSpace *cond = allCondSpaces + cnum;
311         cond->condSpaceId = condSpaceId;
312         cond->baseKey = baseKey;
313 }
314
315 void CodeGenData::condSpaceItem( int cnum, long condActionId )
316 {
317         GenCondSpace *cond = allCondSpaces + cnum;
318         cond->condSet.append( allActions + condActionId );
319 }
320
321 void CodeGenData::initStateCondList( int snum, ulong length )
322 {
323         /* Could preallocate these, as we could with transitions. */
324 }
325
326 void CodeGenData::addStateCond( int snum, Key lowKey, Key highKey, long condNum )
327 {
328         RedStateAp *curState = allStates + snum;
329
330         /* Create the new state condition. */
331         GenStateCond *stateCond = new GenStateCond;
332         stateCond->lowKey = lowKey;
333         stateCond->highKey = highKey;
334
335         /* Assign it a cond space. */
336         GenCondSpace *condSpace = allCondSpaces + condNum;
337         stateCond->condSpace = condSpace;
338
339         curState->stateCondList.append( stateCond );
340 }
341
342
343 GenCondSpace *CodeGenData::findCondSpace( Key lowKey, Key highKey )
344 {
345         for ( CondSpaceList::Iter cs = condSpaceList; cs.lte(); cs++ ) {
346                 Key csHighKey = cs->baseKey;
347                 csHighKey += keyOps->alphSize() * (1 << cs->condSet.length());
348
349                 if ( lowKey >= cs->baseKey && highKey <= csHighKey )
350                         return cs;
351         }
352         return 0;
353 }
354
355 Condition *CodeGenData::findCondition( Key key )
356 {
357         for ( ConditionList::Iter cond = conditionList; cond.lte(); cond++ ) {
358                 Key upperKey = cond->baseKey + (1 << cond->condSet.length());
359                 if ( cond->baseKey <= key && key <= upperKey )
360                         return cond;
361         }
362         return 0;
363 }
364
365 Key CodeGenData::findMaxKey()
366 {
367         Key maxKey = keyOps->maxKey;
368         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
369                 assert( st->outSingle.length() == 0 );
370                 assert( st->defTrans == 0 );
371
372                 long rangeLen = st->outRange.length();
373                 if ( rangeLen > 0 ) {
374                         Key highKey = st->outRange[rangeLen-1].highKey;
375                         if ( highKey > maxKey )
376                                 maxKey = highKey;
377                 }
378         }
379         return maxKey;
380 }
381
382 void CodeGenData::findFinalActionRefs()
383 {
384         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
385                 /* Rerence count out of single transitions. */
386                 for ( RedTransList::Iter rtel = st->outSingle; rtel.lte(); rtel++ ) {
387                         if ( rtel->value->action != 0 ) {
388                                 rtel->value->action->numTransRefs += 1;
389                                 for ( GenActionTable::Iter item = rtel->value->action->key; item.lte(); item++ )
390                                         item->value->numTransRefs += 1;
391                         }
392                 }
393
394                 /* Reference count out of range transitions. */
395                 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
396                         if ( rtel->value->action != 0 ) {
397                                 rtel->value->action->numTransRefs += 1;
398                                 for ( GenActionTable::Iter item = rtel->value->action->key; item.lte(); item++ )
399                                         item->value->numTransRefs += 1;
400                         }
401                 }
402
403                 /* Reference count default transition. */
404                 if ( st->defTrans != 0 && st->defTrans->action != 0 ) {
405                         st->defTrans->action->numTransRefs += 1;
406                         for ( GenActionTable::Iter item = st->defTrans->action->key; item.lte(); item++ )
407                                 item->value->numTransRefs += 1;
408                 }
409
410                 /* Reference count eof transitions. */
411                 if ( st->eofTrans != 0 && st->eofTrans->action != 0 ) {
412                         st->eofTrans->action->numTransRefs += 1;
413                         for ( GenActionTable::Iter item = st->eofTrans->action->key; item.lte(); item++ )
414                                 item->value->numTransRefs += 1;
415                 }
416
417                 /* Reference count to state actions. */
418                 if ( st->toStateAction != 0 ) {
419                         st->toStateAction->numToStateRefs += 1;
420                         for ( GenActionTable::Iter item = st->toStateAction->key; item.lte(); item++ )
421                                 item->value->numToStateRefs += 1;
422                 }
423
424                 /* Reference count from state actions. */
425                 if ( st->fromStateAction != 0 ) {
426                         st->fromStateAction->numFromStateRefs += 1;
427                         for ( GenActionTable::Iter item = st->fromStateAction->key; item.lte(); item++ )
428                                 item->value->numFromStateRefs += 1;
429                 }
430
431                 /* Reference count EOF actions. */
432                 if ( st->eofAction != 0 ) {
433                         st->eofAction->numEofRefs += 1;
434                         for ( GenActionTable::Iter item = st->eofAction->key; item.lte(); item++ )
435                                 item->value->numEofRefs += 1;
436                 }
437         }
438 }
439
440 void CodeGenData::analyzeAction( GenAction *act, GenInlineList *inlineList )
441 {
442         for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) {
443                 /* Only consider actions that are referenced. */
444                 if ( act->numRefs() > 0 ) {
445                         if ( item->type == GenInlineItem::Goto || item->type == GenInlineItem::GotoExpr )
446                                 redFsm->bAnyActionGotos = true;
447                         else if ( item->type == GenInlineItem::Call || item->type == GenInlineItem::CallExpr )
448                                 redFsm->bAnyActionCalls = true;
449                         else if ( item->type == GenInlineItem::Ret )
450                                 redFsm->bAnyActionRets = true;
451                 }
452
453                 /* Check for various things in regular actions. */
454                 if ( act->numTransRefs > 0 || act->numToStateRefs > 0 || act->numFromStateRefs > 0 ) {
455                         /* Any returns in regular actions? */
456                         if ( item->type == GenInlineItem::Ret )
457                                 redFsm->bAnyRegActionRets = true;
458
459                         /* Any next statements in the regular actions? */
460                         if ( item->type == GenInlineItem::Next || item->type == GenInlineItem::NextExpr )
461                                 redFsm->bAnyRegNextStmt = true;
462
463                         /* Any by value control in regular actions? */
464                         if ( item->type == GenInlineItem::CallExpr || item->type == GenInlineItem::GotoExpr )
465                                 redFsm->bAnyRegActionByValControl = true;
466
467                         /* Any references to the current state in regular actions? */
468                         if ( item->type == GenInlineItem::Curs )
469                                 redFsm->bAnyRegCurStateRef = true;
470
471                         if ( item->type == GenInlineItem::Break )
472                                 redFsm->bAnyRegBreak = true;
473                 }
474
475                 if ( item->children != 0 )
476                         analyzeAction( act, item->children );
477         }
478 }
479
480 void CodeGenData::analyzeActionList( RedAction *redAct, GenInlineList *inlineList )
481 {
482         for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) {
483                 /* Any next statements in the action table? */
484                 if ( item->type == GenInlineItem::Next || item->type == GenInlineItem::NextExpr )
485                         redAct->bAnyNextStmt = true;
486
487                 /* Any references to the current state. */
488                 if ( item->type == GenInlineItem::Curs )
489                         redAct->bAnyCurStateRef = true;
490
491                 if ( item->type == GenInlineItem::Break )
492                         redAct->bAnyBreakStmt = true;
493
494                 if ( item->children != 0 )
495                         analyzeActionList( redAct, item->children );
496         }
497 }
498
499 /* Assign ids to referenced actions. */
500 void CodeGenData::assignActionIds()
501 {
502         int nextActionId = 0;
503         for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
504                 /* Only ever interested in referenced actions. */
505                 if ( act->numRefs() > 0 )
506                         act->actionId = nextActionId++;
507         }
508 }
509
510 void CodeGenData::setValueLimits()
511 {
512         redFsm->maxSingleLen = 0;
513         redFsm->maxRangeLen = 0;
514         redFsm->maxKeyOffset = 0;
515         redFsm->maxIndexOffset = 0;
516         redFsm->maxActListId = 0;
517         redFsm->maxActionLoc = 0;
518         redFsm->maxActArrItem = 0;
519         redFsm->maxSpan = 0;
520         redFsm->maxCondSpan = 0;
521         redFsm->maxFlatIndexOffset = 0;
522         redFsm->maxCondOffset = 0;
523         redFsm->maxCondLen = 0;
524         redFsm->maxCondSpaceId = 0;
525         redFsm->maxCondIndexOffset = 0;
526
527         /* In both of these cases the 0 index is reserved for no value, so the max
528          * is one more than it would be if they started at 0. */
529         redFsm->maxIndex = redFsm->transSet.length();
530         redFsm->maxCond = condSpaceList.length(); 
531
532         /* The nextStateId - 1 is the last state id assigned. */
533         redFsm->maxState = redFsm->nextStateId - 1;
534
535         for ( CondSpaceList::Iter csi = condSpaceList; csi.lte(); csi++ ) {
536                 if ( csi->condSpaceId > redFsm->maxCondSpaceId )
537                         redFsm->maxCondSpaceId = csi->condSpaceId;
538         }
539
540         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
541                 /* Maximum cond length. */
542                 if ( st->stateCondList.length() > redFsm->maxCondLen )
543                         redFsm->maxCondLen = st->stateCondList.length();
544
545                 /* Maximum single length. */
546                 if ( st->outSingle.length() > redFsm->maxSingleLen )
547                         redFsm->maxSingleLen = st->outSingle.length();
548
549                 /* Maximum range length. */
550                 if ( st->outRange.length() > redFsm->maxRangeLen )
551                         redFsm->maxRangeLen = st->outRange.length();
552
553                 /* The key offset index offset for the state after last is not used, skip it.. */
554                 if ( ! st.last() ) {
555                         redFsm->maxCondOffset += st->stateCondList.length();
556                         redFsm->maxKeyOffset += st->outSingle.length() + st->outRange.length()*2;
557                         redFsm->maxIndexOffset += st->outSingle.length() + st->outRange.length() + 2;
558                 }
559
560                 /* Max cond span. */
561                 if ( st->condList != 0 ) {
562                         unsigned long long span = keyOps->span( st->condLowKey, st->condHighKey );
563                         if ( span > redFsm->maxCondSpan )
564                                 redFsm->maxCondSpan = span;
565                 }
566
567                 /* Max key span. */
568                 if ( st->transList != 0 ) {
569                         unsigned long long span = keyOps->span( st->lowKey, st->highKey );
570                         if ( span > redFsm->maxSpan )
571                                 redFsm->maxSpan = span;
572                 }
573
574                 /* Max cond index offset. */
575                 if ( ! st.last() ) {
576                         if ( st->condList != 0 )
577                                 redFsm->maxCondIndexOffset += keyOps->span( st->condLowKey, st->condHighKey );
578                 }
579
580                 /* Max flat index offset. */
581                 if ( ! st.last() ) {
582                         if ( st->transList != 0 )
583                                 redFsm->maxFlatIndexOffset += keyOps->span( st->lowKey, st->highKey );
584                         redFsm->maxFlatIndexOffset += 1;
585                 }
586         }
587
588         for ( GenActionTableMap::Iter at = redFsm->actionMap; at.lte(); at++ ) {
589                 /* Maximum id of action lists. */
590                 if ( at->actListId+1 > redFsm->maxActListId )
591                         redFsm->maxActListId = at->actListId+1;
592
593                 /* Maximum location of items in action array. */
594                 if ( at->location+1 > redFsm->maxActionLoc )
595                         redFsm->maxActionLoc = at->location+1;
596
597                 /* Maximum values going into the action array. */
598                 if ( at->key.length() > redFsm->maxActArrItem )
599                         redFsm->maxActArrItem = at->key.length();
600                 for ( GenActionTable::Iter item = at->key; item.lte(); item++ ) {
601                         if ( item->value->actionId > redFsm->maxActArrItem )
602                                 redFsm->maxActArrItem = item->value->actionId;
603                 }
604         }
605 }
606
607
608
609 /* Gather various info on the machine. */
610 void CodeGenData::analyzeMachine()
611 {
612         /* Find the true count of action references.  */
613         findFinalActionRefs();
614
615         /* Check if there are any calls in action code. */
616         for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
617                 /* Record the occurrence of various kinds of actions. */
618                 if ( act->numToStateRefs > 0 )
619                         redFsm->bAnyToStateActions = true;
620                 if ( act->numFromStateRefs > 0 )
621                         redFsm->bAnyFromStateActions = true;
622                 if ( act->numEofRefs > 0 )
623                         redFsm->bAnyEofActions = true;
624                 if ( act->numTransRefs > 0 )
625                         redFsm->bAnyRegActions = true;
626
627                 /* Recurse through the action's parse tree looking for various things. */
628                 analyzeAction( act, act->inlineList );
629         }
630
631         /* Analyze reduced action lists. */
632         for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
633                 for ( GenActionTable::Iter act = redAct->key; act.lte(); act++ )
634                         analyzeActionList( redAct, act->value->inlineList );
635         }
636
637         /* Find states that have transitions with actions that have next
638          * statements. */
639         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
640                 /* Check any actions out of outSinge. */
641                 for ( RedTransList::Iter rtel = st->outSingle; rtel.lte(); rtel++ ) {
642                         if ( rtel->value->action != 0 && rtel->value->action->anyCurStateRef() )
643                                 st->bAnyRegCurStateRef = true;
644                 }
645
646                 /* Check any actions out of outRange. */
647                 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
648                         if ( rtel->value->action != 0 && rtel->value->action->anyCurStateRef() )
649                                 st->bAnyRegCurStateRef = true;
650                 }
651
652                 /* Check any action out of default. */
653                 if ( st->defTrans != 0 && st->defTrans->action != 0 && 
654                                 st->defTrans->action->anyCurStateRef() )
655                         st->bAnyRegCurStateRef = true;
656                 
657                 if ( st->stateCondList.length() > 0 )
658                         redFsm->bAnyConditions = true;
659
660                 if ( st->eofTrans != 0 )
661                         redFsm->bAnyEofTrans = true;
662         }
663
664         /* Assign ids to actions that are referenced. */
665         assignActionIds();
666
667         /* Set the maximums of various values used for deciding types. */
668         setValueLimits();
669 }
670
671 void CodeGenData::writeStatement( GenInputLoc &loc, int nargs, char **args )
672 {
673         /* FIXME: This should be moved to the virtual functions in the code
674          * generators.
675          *
676          * Force a newline. */
677         out << "\n";
678         genLineDirective( out );
679
680         if ( strcmp( args[0], "data" ) == 0 ) {
681                 for ( int i = 1; i < nargs; i++ ) {
682                         if ( strcmp( args[i], "noerror" ) == 0 )
683                                 writeErr = false;
684                         else if ( strcmp( args[i], "noprefix" ) == 0 )
685                                 dataPrefix = false;
686                         else if ( strcmp( args[i], "nofinal" ) == 0 )
687                                 writeFirstFinal = false;
688                         else {
689                                 source_warning(loc) << "unrecognized write option \"" << 
690                                                 args[i] << "\"" << endl;
691                         }
692                 }
693                 writeData();
694         }
695         else if ( strcmp( args[0], "init" ) == 0 ) {
696                 for ( int i = 1; i < nargs; i++ ) {
697                         if ( strcmp( args[i], "nocs" ) == 0 )
698                                 writeCS = false;
699                         else {
700                                 source_warning(loc) << "unrecognized write option \"" << 
701                                                 args[i] << "\"" << endl;
702                         }
703                 }
704                 writeInit();
705         }
706         else if ( strcmp( args[0], "exec" ) == 0 ) {
707                 for ( int i = 1; i < nargs; i++ ) {
708                         if ( strcmp( args[i], "noend" ) == 0 )
709                                 hasEnd = false;
710                         else {
711                                 source_warning(loc) << "unrecognized write option \"" << 
712                                                 args[i] << "\"" << endl;
713                         }
714                 }
715                 writeExec();
716         }
717         else if ( strcmp( args[0], "exports" ) == 0 ) {
718                 for ( int i = 1; i < nargs; i++ ) {
719                         source_warning(loc) << "unrecognized write option \"" << 
720                                         args[i] << "\"" << endl;
721                 }
722                 writeExports();
723         }
724         else {
725                 /* EMIT An error here. */
726                 source_error(loc) << "unrecognized write command \"" << 
727                                 args[0] << "\"" << endl;
728         }
729 }
730
731 ostream &CodeGenData::source_warning( const GenInputLoc &loc )
732 {
733         cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": warning: ";
734         return cerr;
735 }
736
737 ostream &CodeGenData::source_error( const GenInputLoc &loc )
738 {
739         gblErrorCount += 1;
740         assert( sourceFileName != 0 );
741         cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": ";
742         return cerr;
743 }
744
745