update(add) packaging directory and spec file from OBSTF:Private, OBS
[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 "ragel.h"
24 #include <iostream>
25
26 /*
27  * Code generators.
28  */
29
30 #include "cstable.h"
31 #include "csftable.h"
32 #include "csflat.h"
33 #include "csfflat.h"
34 #include "csgoto.h"
35 #include "csfgoto.h"
36 #include "csipgoto.h"
37 #include "cssplit.h"
38
39 #include "cdtable.h"
40 #include "cdftable.h"
41 #include "cdflat.h"
42 #include "cdfflat.h"
43 #include "cdgoto.h"
44 #include "cdfgoto.h"
45 #include "cdipgoto.h"
46 #include "cdsplit.h"
47
48 #include "dotcodegen.h"
49
50 #include "javacodegen.h"
51
52 #include "rubytable.h"
53 #include "rubyftable.h"
54 #include "rubyflat.h"
55 #include "rubyfflat.h"
56 #include "rbxgoto.h"
57
58 string itoa( int i )
59 {
60         char buf[16];
61         sprintf( buf, "%i", i );
62         return buf;
63 }
64
65 using std::cout;
66 using std::cerr;
67 using std::endl;
68
69 /* Invoked by the parser when a ragel definition is opened. */
70 CodeGenData *dotMakeCodeGen( const char *sourceFileName, const char *fsmName, ostream &out )
71 {
72         CodeGenData *codeGen = new GraphvizDotGen(out);
73
74         codeGen->sourceFileName = sourceFileName;
75         codeGen->fsmName = fsmName;
76
77         /* For normal code generation we want a transition on every character so we never
78          * end up in an undefined state. For graphviz this just clutters the
79          * drawing so we turn it off. */
80         codeGen->wantComplete = false;
81
82         return codeGen;
83 }
84
85 /* Invoked by the parser when a ragel definition is opened. */
86 CodeGenData *cdMakeCodeGen( const char *sourceFileName, const char *fsmName, ostream &out )
87 {
88         CodeGenData *codeGen = 0;
89         switch ( hostLang->lang ) {
90         case HostLang::C:
91                 switch ( codeStyle ) {
92                 case GenTables:
93                         codeGen = new CTabCodeGen(out);
94                         break;
95                 case GenFTables:
96                         codeGen = new CFTabCodeGen(out);
97                         break;
98                 case GenFlat:
99                         codeGen = new CFlatCodeGen(out);
100                         break;
101                 case GenFFlat:
102                         codeGen = new CFFlatCodeGen(out);
103                         break;
104                 case GenGoto:
105                         codeGen = new CGotoCodeGen(out);
106                         break;
107                 case GenFGoto:
108                         codeGen = new CFGotoCodeGen(out);
109                         break;
110                 case GenIpGoto:
111                         codeGen = new CIpGotoCodeGen(out);
112                         break;
113                 case GenSplit:
114                         codeGen = new CSplitCodeGen(out);
115                         break;
116                 }
117                 break;
118
119         case HostLang::D:
120                 switch ( codeStyle ) {
121                 case GenTables:
122                         codeGen = new DTabCodeGen(out);
123                         break;
124                 case GenFTables:
125                         codeGen = new DFTabCodeGen(out);
126                         break;
127                 case GenFlat:
128                         codeGen = new DFlatCodeGen(out);
129                         break;
130                 case GenFFlat:
131                         codeGen = new DFFlatCodeGen(out);
132                         break;
133                 case GenGoto:
134                         codeGen = new DGotoCodeGen(out);
135                         break;
136                 case GenFGoto:
137                         codeGen = new DFGotoCodeGen(out);
138                         break;
139                 case GenIpGoto:
140                         codeGen = new DIpGotoCodeGen(out);
141                         break;
142                 case GenSplit:
143                         codeGen = new DSplitCodeGen(out);
144                         break;
145                 }
146                 break;
147
148         default: break;
149         }
150
151         codeGen->sourceFileName = sourceFileName;
152         codeGen->fsmName = fsmName;
153
154         return codeGen;
155 }
156
157 /* Invoked by the parser when a ragel definition is opened. */
158 CodeGenData *javaMakeCodeGen( const char *sourceFileName, const char *fsmName, ostream &out )
159 {
160         CodeGenData *codeGen = new JavaTabCodeGen(out);
161
162         codeGen->sourceFileName = sourceFileName;
163         codeGen->fsmName = fsmName;
164
165         return codeGen;
166 }
167
168 /* Invoked by the parser when a ragel definition is opened. */
169 CodeGenData *rubyMakeCodeGen( const char *sourceFileName, const char *fsmName, ostream &out )
170 {
171         CodeGenData *codeGen = 0;
172         switch ( codeStyle ) {
173                 case GenTables: 
174                         codeGen = new RubyTabCodeGen(out);
175                         break;
176                 case GenFTables:
177                         codeGen = new RubyFTabCodeGen(out);
178                         break;
179                 case GenFlat:
180                         codeGen = new RubyFlatCodeGen(out);
181                         break;
182                 case GenFFlat:
183                         codeGen = new RubyFFlatCodeGen(out);
184                         break;
185                 case GenGoto:
186                         if ( rubyImpl == Rubinius ) {
187                                 codeGen = new RbxGotoCodeGen(out);
188                         } else {
189                                 cerr << "Goto style is still _very_ experimental " 
190                                         "and only supported using Rubinius.\n"
191                                         "You may want to enable the --rbx flag "
192                                         " to give it a try.\n";
193                                 exit(1);
194                         }
195                         break;
196                 default:
197                         cout << "Invalid code style\n";
198                         exit(1);
199                         break;
200         }
201         codeGen->sourceFileName = sourceFileName;
202         codeGen->fsmName = fsmName;
203
204         return codeGen;
205 }
206
207 /* Invoked by the parser when a ragel definition is opened. */
208 CodeGenData *csharpMakeCodeGen( const char *sourceFileName, const char *fsmName, ostream &out )
209 {
210         CodeGenData *codeGen = 0;
211
212         switch ( codeStyle ) {
213         case GenTables:
214                 codeGen = new CSharpTabCodeGen(out);
215                 break;
216         case GenFTables:
217                 codeGen = new CSharpFTabCodeGen(out);
218                 break;
219         case GenFlat:
220                 codeGen = new CSharpFlatCodeGen(out);
221                 break;
222         case GenFFlat:
223                 codeGen = new CSharpFFlatCodeGen(out);
224                 break;
225         case GenGoto:
226                 codeGen = new CSharpGotoCodeGen(out);
227                 break;
228         case GenFGoto:
229                 codeGen = new CSharpFGotoCodeGen(out);
230                 break;
231         case GenIpGoto:
232                 codeGen = new CSharpIpGotoCodeGen(out);
233                 break;
234         case GenSplit:
235                 codeGen = new CSharpSplitCodeGen(out);
236                 break;
237         }
238
239         codeGen->sourceFileName = sourceFileName;
240         codeGen->fsmName = fsmName;
241
242         return codeGen;
243 }
244
245
246 CodeGenData *makeCodeGen( const char *sourceFileName, const char *fsmName, ostream &out )
247 {
248         CodeGenData *cgd = 0;
249         if ( generateDot )
250                 cgd = dotMakeCodeGen( sourceFileName, fsmName, out );
251         else if ( hostLang == &hostLangC )
252                 cgd = cdMakeCodeGen( sourceFileName, fsmName, out );
253         else if ( hostLang == &hostLangD )
254                 cgd = cdMakeCodeGen( sourceFileName, fsmName, out );
255         else if ( hostLang == &hostLangJava )
256                 cgd = javaMakeCodeGen( sourceFileName, fsmName, out );
257         else if ( hostLang == &hostLangRuby )
258                 cgd = rubyMakeCodeGen( sourceFileName, fsmName, out );
259         else if ( hostLang == &hostLangCSharp )
260                 cgd = csharpMakeCodeGen( sourceFileName, fsmName, out );
261         return cgd;
262 }
263
264 void lineDirective( ostream &out, const char *fileName, int line )
265 {
266         if ( !generateDot ) {
267                 if ( hostLang == &hostLangC )
268                         cdLineDirective( out, fileName, line );
269                 else if ( hostLang == &hostLangD )
270                         cdLineDirective( out, fileName, line );
271                 else if ( hostLang == &hostLangJava )
272                         javaLineDirective( out, fileName, line );
273                 else if ( hostLang == &hostLangRuby )
274                         rubyLineDirective( out, fileName, line );
275                 else if ( hostLang == &hostLangCSharp )
276                         csharpLineDirective( out, fileName, line );
277         }
278 }
279
280 void genLineDirective( ostream &out )
281 {
282         std::streambuf *sbuf = out.rdbuf();
283         output_filter *filter = static_cast<output_filter*>(sbuf);
284         lineDirective( out, filter->fileName, filter->line + 1 );
285 }
286
287
288 /* Total error count. */
289 /* int gblErrorCount = 0; */
290
291 CodeGenData::CodeGenData( ostream &out )
292 :
293         sourceFileName(0),
294         fsmName(0), 
295         out(out),
296         redFsm(0), 
297         allActions(0),
298         allActionTables(0),
299         allConditions(0),
300         allCondSpaces(0),
301         allStates(0),
302         nameIndex(0),
303         startState(-1),
304         errState(-1),
305         getKeyExpr(0),
306         accessExpr(0),
307         prePushExpr(0),
308         postPopExpr(0),
309         pExpr(0),
310         peExpr(0),
311         eofExpr(0),
312         csExpr(0),
313         topExpr(0),
314         stackExpr(0),
315         actExpr(0),
316         tokstartExpr(0),
317         tokendExpr(0),
318         dataExpr(0),
319         wantComplete(true),
320         hasLongestMatch(false),
321         noEnd(false),
322         noPrefix(false),
323         noFinal(false),
324         noError(false),
325         noCS(false)
326 {}
327
328
329 void CodeGenData::createMachine()
330 {
331         redFsm = new RedFsmAp();
332 }
333
334 void CodeGenData::initActionList( unsigned long length )
335
336         allActions = new GenAction[length];
337         for ( unsigned long a = 0; a < length; a++ )
338                 actionList.append( allActions+a );
339 }
340
341 void CodeGenData::newAction( int anum, const char *name,
342                 const InputLoc &loc, GenInlineList *inlineList )
343 {
344         allActions[anum].actionId = anum;
345         allActions[anum].name = name;
346         allActions[anum].loc = loc;
347         allActions[anum].inlineList = inlineList;
348 }
349
350 void CodeGenData::initActionTableList( unsigned long length )
351
352         allActionTables = new RedAction[length];
353 }
354
355 void CodeGenData::initStateList( unsigned long length )
356 {
357         allStates = new RedStateAp[length];
358         for ( unsigned long s = 0; s < length; s++ )
359                 redFsm->stateList.append( allStates+s );
360
361         /* We get the start state as an offset, set the pointer now. */
362         if ( startState >= 0 )
363                 redFsm->startState = allStates + startState;
364         if ( errState >= 0 )
365                 redFsm->errState = allStates + errState;
366         for ( EntryIdVect::Iter en = entryPointIds; en.lte(); en++ )
367                 redFsm->entryPoints.insert( allStates + *en );
368
369         /* The nextStateId is no longer used to assign state ids (they come in set
370          * from the frontend now), however generation code still depends on it.
371          * Should eventually remove this variable. */
372         redFsm->nextStateId = redFsm->stateList.length();
373 }
374
375 void CodeGenData::setStartState( unsigned long startState )
376 {
377         this->startState = startState;
378 }
379
380 void CodeGenData::setErrorState( unsigned long errState )
381 {
382         this->errState = errState;
383 }
384
385 void CodeGenData::addEntryPoint( char *name, unsigned long entryState )
386 {
387         entryPointIds.append( entryState );
388         entryPointNames.append( name );
389 }
390
391 void CodeGenData::initTransList( int snum, unsigned long length )
392 {
393         /* Could preallocate the out range to save time growing it. For now do
394          * nothing. */
395 }
396
397 void CodeGenData::newTrans( int snum, int tnum, Key lowKey, 
398                 Key highKey, long targ, long action )
399 {
400         /* Get the current state and range. */
401         RedStateAp *curState = allStates + snum;
402         RedTransList &destRange = curState->outRange;
403
404         if ( curState == redFsm->errState )
405                 return;
406
407         /* Make the new transitions. */
408         RedStateAp *targState = targ >= 0 ? (allStates + targ) : 
409                         wantComplete ? redFsm->getErrorState() : 0;
410         RedAction *actionTable = action >= 0 ? (allActionTables + action) : 0;
411         RedTransAp *trans = redFsm->allocateTrans( targState, actionTable );
412         RedTransEl transEl( lowKey, highKey, trans );
413
414         if ( wantComplete ) {
415                 /* If the machine is to be complete then we need to fill any gaps with
416                  * the error transitions. */
417                 if ( destRange.length() == 0 ) {
418                         /* Range is currently empty. */
419                         if ( keyOps->minKey < lowKey ) {
420                                 /* The first range doesn't start at the low end. */
421                                 Key fillHighKey = lowKey;
422                                 fillHighKey.decrement();
423
424                                 /* Create the filler with the state's error transition. */
425                                 RedTransEl newTel( keyOps->minKey, fillHighKey, redFsm->getErrorTrans() );
426                                 destRange.append( newTel );
427                         }
428                 }
429                 else {
430                         /* The range list is not empty, get the the last range. */
431                         RedTransEl *last = &destRange[destRange.length()-1];
432                         Key nextKey = last->highKey;
433                         nextKey.increment();
434                         if ( nextKey < lowKey ) {
435                                 /* There is a gap to fill. Make the high key. */
436                                 Key fillHighKey = lowKey;
437                                 fillHighKey.decrement();
438
439                                 /* Create the filler with the state's error transtion. */
440                                 RedTransEl newTel( nextKey, fillHighKey, redFsm->getErrorTrans() );
441                                 destRange.append( newTel );
442                         }
443                 }
444         }
445
446         /* Filler taken care of. Append the range. */
447         destRange.append( RedTransEl( lowKey, highKey, trans ) );
448 }
449
450 void CodeGenData::finishTransList( int snum )
451 {
452         /* Get the current state and range. */
453         RedStateAp *curState = allStates + snum;
454         RedTransList &destRange = curState->outRange;
455
456         if ( curState == redFsm->errState )
457                 return;
458
459         /* If building a complete machine we may need filler on the end. */
460         if ( wantComplete ) {
461                 /* Check if there are any ranges already. */
462                 if ( destRange.length() == 0 ) {
463                         /* Fill with the whole alphabet. */
464                         /* Add the range on the lower and upper bound. */
465                         RedTransEl newTel( keyOps->minKey, keyOps->maxKey, redFsm->getErrorTrans() );
466                         destRange.append( newTel );
467                 }
468                 else {
469                         /* Get the last and check for a gap on the end. */
470                         RedTransEl *last = &destRange[destRange.length()-1];
471                         if ( last->highKey < keyOps->maxKey ) {
472                                 /* Make the high key. */
473                                 Key fillLowKey = last->highKey;
474                                 fillLowKey.increment();
475
476                                 /* Create the new range with the error trans and append it. */
477                                 RedTransEl newTel( fillLowKey, keyOps->maxKey, redFsm->getErrorTrans() );
478                                 destRange.append( newTel );
479                         }
480                 }
481         }
482 }
483
484 void CodeGenData::setId( int snum, int id )
485 {
486         RedStateAp *curState = allStates + snum;
487         curState->id = id;
488 }
489
490 void CodeGenData::setFinal( int snum )
491 {
492         RedStateAp *curState = allStates + snum;
493         curState->isFinal = true;
494 }
495
496
497 void CodeGenData::setStateActions( int snum, long toStateAction, 
498                 long fromStateAction, long eofAction )
499 {
500         RedStateAp *curState = allStates + snum;
501         if ( toStateAction >= 0 )
502                 curState->toStateAction = allActionTables + toStateAction;
503         if ( fromStateAction >= 0 )
504                 curState->fromStateAction = allActionTables + fromStateAction;
505         if ( eofAction >= 0 )
506                 curState->eofAction = allActionTables + eofAction;
507 }
508
509 void CodeGenData::setEofTrans( int snum, long eofTarget, long actId )
510 {
511         RedStateAp *curState = allStates + snum;
512         RedStateAp *targState = allStates + eofTarget;
513         RedAction *eofAct = allActionTables + actId;
514         curState->eofTrans = redFsm->allocateTrans( targState, eofAct );
515 }
516
517 void CodeGenData::resolveTargetStates( GenInlineList *inlineList )
518 {
519         for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) {
520                 switch ( item->type ) {
521                 case GenInlineItem::Goto: case GenInlineItem::Call:
522                 case GenInlineItem::Next: case GenInlineItem::Entry:
523                         item->targState = allStates + item->targId;
524                         break;
525                 default:
526                         break;
527                 }
528
529                 if ( item->children != 0 )
530                         resolveTargetStates( item->children );
531         }
532 }
533
534 void CodeGenData::closeMachine()
535 {
536         for ( GenActionList::Iter a = actionList; a.lte(); a++ )
537                 resolveTargetStates( a->inlineList );
538
539         /* Note that even if we want a complete graph we do not give the error
540          * state a default transition. All machines break out of the processing
541          * loop when in the error state. */
542
543         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
544                 for ( GenStateCondList::Iter sci = st->stateCondList; sci.lte(); sci++ )
545                         st->stateCondVect.append( sci );
546         }
547 }
548
549
550 bool CodeGenData::setAlphType( const char *data )
551 {
552         HostType *alphType = findAlphTypeInternal( data );
553         if ( alphType == 0 )
554                 return false;
555
556         thisKeyOps.setAlphType( alphType );
557         return true;
558 }
559
560 void CodeGenData::initCondSpaceList( ulong length )
561 {
562         allCondSpaces = new GenCondSpace[length];
563         for ( ulong c = 0; c < length; c++ )
564                 condSpaceList.append( allCondSpaces + c );
565 }
566
567 void CodeGenData::newCondSpace( int cnum, int condSpaceId, Key baseKey )
568 {
569         GenCondSpace *cond = allCondSpaces + cnum;
570         cond->condSpaceId = condSpaceId;
571         cond->baseKey = baseKey;
572 }
573
574 void CodeGenData::condSpaceItem( int cnum, long condActionId )
575 {
576         GenCondSpace *cond = allCondSpaces + cnum;
577         cond->condSet.append( allActions + condActionId );
578 }
579
580 void CodeGenData::initStateCondList( int snum, ulong length )
581 {
582         /* Could preallocate these, as we could with transitions. */
583 }
584
585 void CodeGenData::addStateCond( int snum, Key lowKey, Key highKey, long condNum )
586 {
587         RedStateAp *curState = allStates + snum;
588
589         /* Create the new state condition. */
590         GenStateCond *stateCond = new GenStateCond;
591         stateCond->lowKey = lowKey;
592         stateCond->highKey = highKey;
593
594         /* Assign it a cond space. */
595         GenCondSpace *condSpace = allCondSpaces + condNum;
596         stateCond->condSpace = condSpace;
597
598         curState->stateCondList.append( stateCond );
599 }
600
601
602 GenCondSpace *CodeGenData::findCondSpace( Key lowKey, Key highKey )
603 {
604         for ( CondSpaceList::Iter cs = condSpaceList; cs.lte(); cs++ ) {
605                 Key csHighKey = cs->baseKey;
606                 csHighKey += keyOps->alphSize() * (1 << cs->condSet.length());
607
608                 if ( lowKey >= cs->baseKey && highKey <= csHighKey )
609                         return cs;
610         }
611         return 0;
612 }
613
614 Condition *CodeGenData::findCondition( Key key )
615 {
616         for ( ConditionList::Iter cond = conditionList; cond.lte(); cond++ ) {
617                 Key upperKey = cond->baseKey + (1 << cond->condSet.length());
618                 if ( cond->baseKey <= key && key <= upperKey )
619                         return cond;
620         }
621         return 0;
622 }
623
624 Key CodeGenData::findMaxKey()
625 {
626         Key maxKey = keyOps->maxKey;
627         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
628                 assert( st->outSingle.length() == 0 );
629                 assert( st->defTrans == 0 );
630
631                 long rangeLen = st->outRange.length();
632                 if ( rangeLen > 0 ) {
633                         Key highKey = st->outRange[rangeLen-1].highKey;
634                         if ( highKey > maxKey )
635                                 maxKey = highKey;
636                 }
637         }
638         return maxKey;
639 }
640
641 void CodeGenData::findFinalActionRefs()
642 {
643         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
644                 /* Rerence count out of single transitions. */
645                 for ( RedTransList::Iter rtel = st->outSingle; rtel.lte(); rtel++ ) {
646                         if ( rtel->value->action != 0 ) {
647                                 rtel->value->action->numTransRefs += 1;
648                                 for ( GenActionTable::Iter item = rtel->value->action->key; item.lte(); item++ )
649                                         item->value->numTransRefs += 1;
650                         }
651                 }
652
653                 /* Reference count out of range transitions. */
654                 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
655                         if ( rtel->value->action != 0 ) {
656                                 rtel->value->action->numTransRefs += 1;
657                                 for ( GenActionTable::Iter item = rtel->value->action->key; item.lte(); item++ )
658                                         item->value->numTransRefs += 1;
659                         }
660                 }
661
662                 /* Reference count default transition. */
663                 if ( st->defTrans != 0 && st->defTrans->action != 0 ) {
664                         st->defTrans->action->numTransRefs += 1;
665                         for ( GenActionTable::Iter item = st->defTrans->action->key; item.lte(); item++ )
666                                 item->value->numTransRefs += 1;
667                 }
668
669                 /* Reference count eof transitions. */
670                 if ( st->eofTrans != 0 && st->eofTrans->action != 0 ) {
671                         st->eofTrans->action->numTransRefs += 1;
672                         for ( GenActionTable::Iter item = st->eofTrans->action->key; item.lte(); item++ )
673                                 item->value->numTransRefs += 1;
674                 }
675
676                 /* Reference count to state actions. */
677                 if ( st->toStateAction != 0 ) {
678                         st->toStateAction->numToStateRefs += 1;
679                         for ( GenActionTable::Iter item = st->toStateAction->key; item.lte(); item++ )
680                                 item->value->numToStateRefs += 1;
681                 }
682
683                 /* Reference count from state actions. */
684                 if ( st->fromStateAction != 0 ) {
685                         st->fromStateAction->numFromStateRefs += 1;
686                         for ( GenActionTable::Iter item = st->fromStateAction->key; item.lte(); item++ )
687                                 item->value->numFromStateRefs += 1;
688                 }
689
690                 /* Reference count EOF actions. */
691                 if ( st->eofAction != 0 ) {
692                         st->eofAction->numEofRefs += 1;
693                         for ( GenActionTable::Iter item = st->eofAction->key; item.lte(); item++ )
694                                 item->value->numEofRefs += 1;
695                 }
696         }
697 }
698
699 void CodeGenData::analyzeAction( GenAction *act, GenInlineList *inlineList )
700 {
701         for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) {
702                 /* Only consider actions that are referenced. */
703                 if ( act->numRefs() > 0 ) {
704                         if ( item->type == GenInlineItem::Goto || item->type == GenInlineItem::GotoExpr )
705                                 redFsm->bAnyActionGotos = true;
706                         else if ( item->type == GenInlineItem::Call || item->type == GenInlineItem::CallExpr )
707                                 redFsm->bAnyActionCalls = true;
708                         else if ( item->type == GenInlineItem::Ret )
709                                 redFsm->bAnyActionRets = true;
710                 }
711
712                 /* Check for various things in regular actions. */
713                 if ( act->numTransRefs > 0 || act->numToStateRefs > 0 || act->numFromStateRefs > 0 ) {
714                         /* Any returns in regular actions? */
715                         if ( item->type == GenInlineItem::Ret )
716                                 redFsm->bAnyRegActionRets = true;
717
718                         /* Any next statements in the regular actions? */
719                         if ( item->type == GenInlineItem::Next || item->type == GenInlineItem::NextExpr )
720                                 redFsm->bAnyRegNextStmt = true;
721
722                         /* Any by value control in regular actions? */
723                         if ( item->type == GenInlineItem::CallExpr || item->type == GenInlineItem::GotoExpr )
724                                 redFsm->bAnyRegActionByValControl = true;
725
726                         /* Any references to the current state in regular actions? */
727                         if ( item->type == GenInlineItem::Curs )
728                                 redFsm->bAnyRegCurStateRef = true;
729
730                         if ( item->type == GenInlineItem::Break )
731                                 redFsm->bAnyRegBreak = true;
732                 }
733
734                 if ( item->children != 0 )
735                         analyzeAction( act, item->children );
736         }
737 }
738
739 void CodeGenData::analyzeActionList( RedAction *redAct, GenInlineList *inlineList )
740 {
741         for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) {
742                 /* Any next statements in the action table? */
743                 if ( item->type == GenInlineItem::Next || item->type == GenInlineItem::NextExpr )
744                         redAct->bAnyNextStmt = true;
745
746                 /* Any references to the current state. */
747                 if ( item->type == GenInlineItem::Curs )
748                         redAct->bAnyCurStateRef = true;
749
750                 if ( item->type == GenInlineItem::Break )
751                         redAct->bAnyBreakStmt = true;
752
753                 if ( item->children != 0 )
754                         analyzeActionList( redAct, item->children );
755         }
756 }
757
758 /* Assign ids to referenced actions. */
759 void CodeGenData::assignActionIds()
760 {
761         int nextActionId = 0;
762         for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
763                 /* Only ever interested in referenced actions. */
764                 if ( act->numRefs() > 0 )
765                         act->actionId = nextActionId++;
766         }
767 }
768
769 void CodeGenData::setValueLimits()
770 {
771         redFsm->maxSingleLen = 0;
772         redFsm->maxRangeLen = 0;
773         redFsm->maxKeyOffset = 0;
774         redFsm->maxIndexOffset = 0;
775         redFsm->maxActListId = 0;
776         redFsm->maxActionLoc = 0;
777         redFsm->maxActArrItem = 0;
778         redFsm->maxSpan = 0;
779         redFsm->maxCondSpan = 0;
780         redFsm->maxFlatIndexOffset = 0;
781         redFsm->maxCondOffset = 0;
782         redFsm->maxCondLen = 0;
783         redFsm->maxCondSpaceId = 0;
784         redFsm->maxCondIndexOffset = 0;
785
786         /* In both of these cases the 0 index is reserved for no value, so the max
787          * is one more than it would be if they started at 0. */
788         redFsm->maxIndex = redFsm->transSet.length();
789         redFsm->maxCond = condSpaceList.length(); 
790
791         /* The nextStateId - 1 is the last state id assigned. */
792         redFsm->maxState = redFsm->nextStateId - 1;
793
794         for ( CondSpaceList::Iter csi = condSpaceList; csi.lte(); csi++ ) {
795                 if ( csi->condSpaceId > redFsm->maxCondSpaceId )
796                         redFsm->maxCondSpaceId = csi->condSpaceId;
797         }
798
799         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
800                 /* Maximum cond length. */
801                 if ( st->stateCondList.length() > redFsm->maxCondLen )
802                         redFsm->maxCondLen = st->stateCondList.length();
803
804                 /* Maximum single length. */
805                 if ( st->outSingle.length() > redFsm->maxSingleLen )
806                         redFsm->maxSingleLen = st->outSingle.length();
807
808                 /* Maximum range length. */
809                 if ( st->outRange.length() > redFsm->maxRangeLen )
810                         redFsm->maxRangeLen = st->outRange.length();
811
812                 /* The key offset index offset for the state after last is not used, skip it.. */
813                 if ( ! st.last() ) {
814                         redFsm->maxCondOffset += st->stateCondList.length();
815                         redFsm->maxKeyOffset += st->outSingle.length() + st->outRange.length()*2;
816                         redFsm->maxIndexOffset += st->outSingle.length() + st->outRange.length() + 2;
817                 }
818
819                 /* Max cond span. */
820                 if ( st->condList != 0 ) {
821                         unsigned long long span = keyOps->span( st->condLowKey, st->condHighKey );
822                         if ( span > redFsm->maxCondSpan )
823                                 redFsm->maxCondSpan = span;
824                 }
825
826                 /* Max key span. */
827                 if ( st->transList != 0 ) {
828                         unsigned long long span = keyOps->span( st->lowKey, st->highKey );
829                         if ( span > redFsm->maxSpan )
830                                 redFsm->maxSpan = span;
831                 }
832
833                 /* Max cond index offset. */
834                 if ( ! st.last() ) {
835                         if ( st->condList != 0 )
836                                 redFsm->maxCondIndexOffset += keyOps->span( st->condLowKey, st->condHighKey );
837                 }
838
839                 /* Max flat index offset. */
840                 if ( ! st.last() ) {
841                         if ( st->transList != 0 )
842                                 redFsm->maxFlatIndexOffset += keyOps->span( st->lowKey, st->highKey );
843                         redFsm->maxFlatIndexOffset += 1;
844                 }
845         }
846
847         for ( GenActionTableMap::Iter at = redFsm->actionMap; at.lte(); at++ ) {
848                 /* Maximum id of action lists. */
849                 if ( at->actListId+1 > redFsm->maxActListId )
850                         redFsm->maxActListId = at->actListId+1;
851
852                 /* Maximum location of items in action array. */
853                 if ( at->location+1 > redFsm->maxActionLoc )
854                         redFsm->maxActionLoc = at->location+1;
855
856                 /* Maximum values going into the action array. */
857                 if ( at->key.length() > redFsm->maxActArrItem )
858                         redFsm->maxActArrItem = at->key.length();
859                 for ( GenActionTable::Iter item = at->key; item.lte(); item++ ) {
860                         if ( item->value->actionId > redFsm->maxActArrItem )
861                                 redFsm->maxActArrItem = item->value->actionId;
862                 }
863         }
864 }
865
866
867
868 /* Gather various info on the machine. */
869 void CodeGenData::analyzeMachine()
870 {
871         /* Find the true count of action references.  */
872         findFinalActionRefs();
873
874         /* Check if there are any calls in action code. */
875         for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
876                 /* Record the occurrence of various kinds of actions. */
877                 if ( act->numToStateRefs > 0 )
878                         redFsm->bAnyToStateActions = true;
879                 if ( act->numFromStateRefs > 0 )
880                         redFsm->bAnyFromStateActions = true;
881                 if ( act->numEofRefs > 0 )
882                         redFsm->bAnyEofActions = true;
883                 if ( act->numTransRefs > 0 )
884                         redFsm->bAnyRegActions = true;
885
886                 /* Recurse through the action's parse tree looking for various things. */
887                 analyzeAction( act, act->inlineList );
888         }
889
890         /* Analyze reduced action lists. */
891         for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
892                 for ( GenActionTable::Iter act = redAct->key; act.lte(); act++ )
893                         analyzeActionList( redAct, act->value->inlineList );
894         }
895
896         /* Find states that have transitions with actions that have next
897          * statements. */
898         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
899                 /* Check any actions out of outSinge. */
900                 for ( RedTransList::Iter rtel = st->outSingle; rtel.lte(); rtel++ ) {
901                         if ( rtel->value->action != 0 && rtel->value->action->anyCurStateRef() )
902                                 st->bAnyRegCurStateRef = true;
903                 }
904
905                 /* Check any actions out of outRange. */
906                 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
907                         if ( rtel->value->action != 0 && rtel->value->action->anyCurStateRef() )
908                                 st->bAnyRegCurStateRef = true;
909                 }
910
911                 /* Check any action out of default. */
912                 if ( st->defTrans != 0 && st->defTrans->action != 0 && 
913                                 st->defTrans->action->anyCurStateRef() )
914                         st->bAnyRegCurStateRef = true;
915                 
916                 if ( st->stateCondList.length() > 0 )
917                         redFsm->bAnyConditions = true;
918
919                 if ( st->eofTrans != 0 )
920                         redFsm->bAnyEofTrans = true;
921         }
922
923         /* Assign ids to actions that are referenced. */
924         assignActionIds();
925
926         /* Set the maximums of various values used for deciding types. */
927         setValueLimits();
928 }
929
930 void CodeGenData::write_option_error( InputLoc &loc, char *arg )
931 {
932         source_warning(loc) << "unrecognized write option \"" << arg << "\"" << endl;
933 }
934
935 void CodeGenData::writeStatement( InputLoc &loc, int nargs, char **args )
936 {
937         /* FIXME: This should be moved to the virtual functions in the code
938          * generators.
939          *
940          * Force a newline. */
941         out << '\n';
942         genLineDirective( out );
943
944         if ( strcmp( args[0], "data" ) == 0 ) {
945                 for ( int i = 1; i < nargs; i++ ) {
946                         if ( strcmp( args[i], "noerror" ) == 0 )
947                                 noError = true;
948                         else if ( strcmp( args[i], "noprefix" ) == 0 )
949                                 noPrefix = true;
950                         else if ( strcmp( args[i], "nofinal" ) == 0 )
951                                 noFinal = true;
952                         else
953                                 write_option_error( loc, args[i] );
954                 }
955                 writeData();
956         }
957         else if ( strcmp( args[0], "init" ) == 0 ) {
958                 for ( int i = 1; i < nargs; i++ ) {
959                         if ( strcmp( args[i], "nocs" ) == 0 )
960                                 noCS = true;
961                         else
962                                 write_option_error( loc, args[i] );
963                 }
964                 writeInit();
965         }
966         else if ( strcmp( args[0], "exec" ) == 0 ) {
967                 for ( int i = 1; i < nargs; i++ ) {
968                         if ( strcmp( args[i], "noend" ) == 0 )
969                                 noEnd = true;
970                         else
971                                 write_option_error( loc, args[i] );
972                 }
973                 writeExec();
974         }
975         else if ( strcmp( args[0], "exports" ) == 0 ) {
976                 for ( int i = 1; i < nargs; i++ )
977                         write_option_error( loc, args[i] );
978                 writeExports();
979         }
980         else if ( strcmp( args[0], "start" ) == 0 ) {
981                 for ( int i = 1; i < nargs; i++ )
982                         write_option_error( loc, args[i] );
983                 writeStart();
984         }
985         else if ( strcmp( args[0], "first_final" ) == 0 ) {
986                 for ( int i = 1; i < nargs; i++ )
987                         write_option_error( loc, args[i] );
988                 writeFirstFinal();
989         }
990         else if ( strcmp( args[0], "error" ) == 0 ) {
991                 for ( int i = 1; i < nargs; i++ )
992                         write_option_error( loc, args[i] );
993                 writeError();
994         }
995         else {
996                 /* EMIT An error here. */
997                 source_error(loc) << "unrecognized write command \"" << 
998                                 args[0] << "\"" << endl;
999         }
1000 }
1001
1002 ostream &CodeGenData::source_warning( const InputLoc &loc )
1003 {
1004         cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": warning: ";
1005         return cerr;
1006 }
1007
1008 ostream &CodeGenData::source_error( const InputLoc &loc )
1009 {
1010         gblErrorCount += 1;
1011         assert( sourceFileName != 0 );
1012         cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": ";
1013         return cerr;
1014 }
1015
1016