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