Bug fix: when -S or -M was given the ragel version number was not emitted,
[external/ragel.git] / ragel / parsedata.cpp
1 /*
2  *  Copyright 2001-2006 Adrian Thurston <thurston@cs.queensu.ca>
3  */
4
5 /*  This file is part of Ragel.
6  *
7  *  Ragel is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  * 
12  *  Ragel is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  * 
17  *  You should have received a copy of the GNU General Public License
18  *  along with Ragel; if not, write to the Free Software
19  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
20  */
21
22 #include <iostream>
23 #include <iomanip>
24 #include <errno.h>
25 #include <stdlib.h>
26 #include <limits.h>
27
28 #include "ragel.h"
29 #include "rlparse.h"
30 #include "parsedata.h"
31 #include "parsetree.h"
32 #include "mergesort.h"
33 #include "xmlcodegen.h"
34 #include "version.h"
35
36 using namespace std;
37
38 char mainMachine[] = "main";
39
40 void Token::set( char *str, int len )
41 {
42         length = len;
43         data = new char[len+1];
44         memcpy( data, str, len );
45         data[len] = 0;
46 }
47
48 void Token::append( const Token &other )
49 {
50         int newLength = length + other.length;
51         char *newString = new char[newLength+1];
52         memcpy( newString, data, length );
53         memcpy( newString + length, other.data, other.length );
54         newString[newLength] = 0;
55         data = newString;
56         length = newLength;
57 }
58
59 /* Perform minimization after an operation according 
60  * to the command line args. */
61 void afterOpMinimize( FsmAp *fsm, bool lastInSeq )
62 {
63         /* Switch on the prefered minimization algorithm. */
64         if ( minimizeOpt == MinimizeEveryOp || minimizeOpt == MinimizeMostOps && lastInSeq ) {
65                 /* First clean up the graph. FsmAp operations may leave these
66                  * lying around. There should be no dead end states. The subtract
67                  * intersection operators are the only places where they may be
68                  * created and those operators clean them up. */
69                 fsm->removeUnreachableStates();
70
71                 switch ( minimizeLevel ) {
72                         case MinimizeApprox:
73                                 fsm->minimizeApproximate();
74                                 break;
75                         case MinimizePartition1:
76                                 fsm->minimizePartition1();
77                                 break;
78                         case MinimizePartition2:
79                                 fsm->minimizePartition2();
80                                 break;
81                         case MinimizeStable:
82                                 fsm->minimizeStable();
83                                 break;
84                 }
85         }
86 }
87
88 /* Count the transitions in the fsm by walking the state list. */
89 int countTransitions( FsmAp *fsm )
90 {
91         int numTrans = 0;
92         StateAp *state = fsm->stateList.head;
93         while ( state != 0 ) {
94                 numTrans += state->outList.length();
95                 state = state->next;
96         }
97         return numTrans;
98 }
99
100 Key makeFsmKeyHex( char *str, const InputLoc &loc, ParseData *pd )
101 {
102         /* Reset errno so we can check for overflow or underflow. In the event of
103          * an error, sets the return val to the upper or lower bound being tested
104          * against. */
105         errno = 0;
106         unsigned int size = keyOps->alphType->size;
107         bool unusedBits = size < sizeof(unsigned long);
108
109         unsigned long ul = strtoul( str, 0, 16 );
110
111         if ( errno == ERANGE || unusedBits && ul >> (size * 8) ) {
112                 error(loc) << "literal " << str << " overflows the alphabet type" << endl;
113                 ul = 1 << (size * 8);
114         }
115
116         if ( unusedBits && keyOps->alphType->isSigned && ul >> (size * 8 - 1) )
117                 ul |= (0xffffffff >> (size*8 ) ) << (size*8);
118
119         return Key( (long)ul );
120 }
121
122 Key makeFsmKeyDec( char *str, const InputLoc &loc, ParseData *pd )
123 {
124         /* Convert the number to a decimal. First reset errno so we can check
125          * for overflow or underflow. */
126         errno = 0;
127         long long minVal = keyOps->alphType->minVal;
128         long long maxVal = keyOps->alphType->maxVal;
129
130         long long ll = strtoll( str, 0, 10 );
131
132         /* Check for underflow. */
133         if ( errno == ERANGE && ll < 0 || ll < minVal) {
134                 error(loc) << "literal " << str << " underflows the alphabet type" << endl;
135                 ll = minVal;
136         }
137         /* Check for overflow. */
138         else if ( errno == ERANGE && ll > 0 || ll > maxVal ) {
139                 error(loc) << "literal " << str << " overflows the alphabet type" << endl;
140                 ll = maxVal;
141         }
142
143         if ( keyOps->alphType->isSigned )
144                 return Key( (long)ll );
145         else
146                 return Key( (unsigned long)ll );
147 }
148
149 /* Make an fsm key in int format (what the fsm graph uses) from an alphabet
150  * number returned by the parser. Validates that the number doesn't overflow
151  * the alphabet type. */
152 Key makeFsmKeyNum( char *str, const InputLoc &loc, ParseData *pd )
153 {
154         /* Switch on hex/decimal format. */
155         if ( str[0] == '0' && str[1] == 'x' )
156                 return makeFsmKeyHex( str, loc, pd );
157         else
158                 return makeFsmKeyDec( str, loc, pd );
159 }
160
161 /* Make an fsm int format (what the fsm graph uses) from a single character.
162  * Performs proper conversion depending on signed/unsigned property of the
163  * alphabet. */
164 Key makeFsmKeyChar( char c, ParseData *pd )
165 {
166         if ( keyOps->isSigned ) {
167                 /* Copy from a char type. */
168                 return Key( c );
169         }
170         else {
171                 /* Copy from an unsigned byte type. */
172                 return Key( (unsigned char)c );
173         }
174 }
175
176 /* Make an fsm key array in int format (what the fsm graph uses) from a string
177  * of characters. Performs proper conversion depending on signed/unsigned
178  * property of the alphabet. */
179 void makeFsmKeyArray( Key *result, char *data, int len, ParseData *pd )
180 {
181         if ( keyOps->isSigned ) {
182                 /* Copy from a char star type. */
183                 char *src = data;
184                 for ( int i = 0; i < len; i++ )
185                         result[i] = Key(src[i]);
186         }
187         else {
188                 /* Copy from an unsigned byte ptr type. */
189                 unsigned char *src = (unsigned char*) data;
190                 for ( int i = 0; i < len; i++ )
191                         result[i] = Key(src[i]);
192         }
193 }
194
195 /* Like makeFsmKeyArray except the result has only unique keys. They ordering
196  * will be changed. */
197 void makeFsmUniqueKeyArray( KeySet &result, char *data, int len, 
198                 bool caseInsensitive, ParseData *pd )
199 {
200         /* Use a transitions list for getting unique keys. */
201         if ( keyOps->isSigned ) {
202                 /* Copy from a char star type. */
203                 char *src = data;
204                 for ( int si = 0; si < len; si++ ) {
205                         Key key( src[si] );
206                         result.insert( key );
207                         if ( caseInsensitive ) {
208                                 if ( key.isLower() )
209                                         result.insert( key.toUpper() );
210                                 else if ( key.isUpper() )
211                                         result.insert( key.toLower() );
212                         }
213                 }
214         }
215         else {
216                 /* Copy from an unsigned byte ptr type. */
217                 unsigned char *src = (unsigned char*) data;
218                 for ( int si = 0; si < len; si++ ) {
219                         Key key( src[si] );
220                         result.insert( key );
221                         if ( caseInsensitive ) {
222                                 if ( key.isLower() )
223                                         result.insert( key.toUpper() );
224                                 else if ( key.isUpper() )
225                                         result.insert( key.toLower() );
226                         }
227                 }
228         }
229 }
230
231 FsmAp *dotFsm( ParseData *pd )
232 {
233         FsmAp *retFsm = new FsmAp();
234         retFsm->rangeFsm( keyOps->minKey, keyOps->maxKey );
235         return retFsm;
236 }
237
238 FsmAp *dotStarFsm( ParseData *pd )
239 {
240         FsmAp *retFsm = new FsmAp();
241         retFsm->rangeStarFsm( keyOps->minKey, keyOps->maxKey );
242         return retFsm;
243 }
244
245 /* Make a builtin type. Depends on the signed nature of the alphabet type. */
246 FsmAp *makeBuiltin( BuiltinMachine builtin, ParseData *pd )
247 {
248         /* FsmAp created to return. */
249         FsmAp *retFsm = 0;
250         bool isSigned = keyOps->isSigned;
251
252         switch ( builtin ) {
253         case BT_Any: {
254                 /* All characters. */
255                 retFsm = dotFsm( pd );
256                 break;
257         }
258         case BT_Ascii: {
259                 /* Ascii characters 0 to 127. */
260                 retFsm = new FsmAp();
261                 retFsm->rangeFsm( 0, 127 );
262                 break;
263         }
264         case BT_Extend: {
265                 /* Ascii extended characters. This is the full byte range. Dependent
266                  * on signed, vs no signed. If the alphabet is one byte then just use
267                  * dot fsm. */
268                 if ( isSigned ) {
269                         retFsm = new FsmAp();
270                         retFsm->rangeFsm( -128, 127 );
271                 }
272                 else {
273                         retFsm = new FsmAp();
274                         retFsm->rangeFsm( 0, 255 );
275                 }
276                 break;
277         }
278         case BT_Alpha: {
279                 /* Alpha [A-Za-z]. */
280                 FsmAp *upper = new FsmAp(), *lower = new FsmAp();
281                 upper->rangeFsm( 'A', 'Z' );
282                 lower->rangeFsm( 'a', 'z' );
283                 upper->unionOp( lower );
284                 upper->minimizePartition2();
285                 retFsm = upper;
286                 break;
287         }
288         case BT_Digit: {
289                 /* Digits [0-9]. */
290                 retFsm = new FsmAp();
291                 retFsm->rangeFsm( '0', '9' );
292                 break;
293         }
294         case BT_Alnum: {
295                 /* Alpha numerics [0-9A-Za-z]. */
296                 FsmAp *digit = new FsmAp(), *lower = new FsmAp();
297                 FsmAp *upper = new FsmAp();
298                 digit->rangeFsm( '0', '9' );
299                 upper->rangeFsm( 'A', 'Z' );
300                 lower->rangeFsm( 'a', 'z' );
301                 digit->unionOp( upper );
302                 digit->unionOp( lower );
303                 digit->minimizePartition2();
304                 retFsm = digit;
305                 break;
306         }
307         case BT_Lower: {
308                 /* Lower case characters. */
309                 retFsm = new FsmAp();
310                 retFsm->rangeFsm( 'a', 'z' );
311                 break;
312         }
313         case BT_Upper: {
314                 /* Upper case characters. */
315                 retFsm = new FsmAp();
316                 retFsm->rangeFsm( 'A', 'Z' );
317                 break;
318         }
319         case BT_Cntrl: {
320                 /* Control characters. */
321                 FsmAp *cntrl = new FsmAp();
322                 FsmAp *highChar = new FsmAp();
323                 cntrl->rangeFsm( 0, 31 );
324                 highChar->concatFsm( 127 );
325                 cntrl->unionOp( highChar );
326                 cntrl->minimizePartition2();
327                 retFsm = cntrl;
328                 break;
329         }
330         case BT_Graph: {
331                 /* Graphical ascii characters [!-~]. */
332                 retFsm = new FsmAp();
333                 retFsm->rangeFsm( '!', '~' );
334                 break;
335         }
336         case BT_Print: {
337                 /* Printable characters. Same as graph except includes space. */
338                 retFsm = new FsmAp();
339                 retFsm->rangeFsm( ' ', '~' );
340                 break;
341         }
342         case BT_Punct: {
343                 /* Punctuation. */
344                 FsmAp *range1 = new FsmAp();
345                 FsmAp *range2 = new FsmAp();
346                 FsmAp *range3 = new FsmAp(); 
347                 FsmAp *range4 = new FsmAp();
348                 range1->rangeFsm( '!', '/' );
349                 range2->rangeFsm( ':', '@' );
350                 range3->rangeFsm( '[', '`' );
351                 range4->rangeFsm( '{', '~' );
352                 range1->unionOp( range2 );
353                 range1->unionOp( range3 );
354                 range1->unionOp( range4 );
355                 range1->minimizePartition2();
356                 retFsm = range1;
357                 break;
358         }
359         case BT_Space: {
360                 /* Whitespace: [\t\v\f\n\r ]. */
361                 FsmAp *cntrl = new FsmAp();
362                 FsmAp *space = new FsmAp();
363                 cntrl->rangeFsm( '\t', '\r' );
364                 space->concatFsm( ' ' );
365                 cntrl->unionOp( space );
366                 cntrl->minimizePartition2();
367                 retFsm = cntrl;
368                 break;
369         }
370         case BT_Xdigit: {
371                 /* Hex digits [0-9A-Fa-f]. */
372                 FsmAp *digit = new FsmAp();
373                 FsmAp *upper = new FsmAp();
374                 FsmAp *lower = new FsmAp();
375                 digit->rangeFsm( '0', '9' );
376                 upper->rangeFsm( 'A', 'F' );
377                 lower->rangeFsm( 'a', 'f' );
378                 digit->unionOp( upper );
379                 digit->unionOp( lower );
380                 digit->minimizePartition2();
381                 retFsm = digit;
382                 break;
383         }
384         case BT_Lambda: {
385                 retFsm = new FsmAp();
386                 retFsm->lambdaFsm();
387                 break;
388         }
389         case BT_Empty: {
390                 retFsm = new FsmAp();
391                 retFsm->emptyFsm();
392                 break;
393         }}
394
395         return retFsm;
396 }
397
398 /* Check if this name inst or any name inst below is referenced. */
399 bool NameInst::anyRefsRec()
400 {
401         if ( numRefs > 0 )
402                 return true;
403
404         /* Recurse on children until true. */
405         for ( NameVect::Iter ch = childVect; ch.lte(); ch++ ) {
406                 if ( (*ch)->anyRefsRec() )
407                         return true;
408         }
409
410         return false;
411 }
412
413 /*
414  * ParseData
415  */
416
417 /* Initialize the structure that will collect info during the parse of a
418  * machine. */
419 ParseData::ParseData( char *fileName, char *sectionName, 
420                 const InputLoc &sectionLoc )
421 :       
422         sectionGraph(0),
423         generatingSectionSubset(false),
424         nextPriorKey(0),
425         /* 0 is reserved for global error actions. */
426         nextLocalErrKey(1),
427         nextNameId(0),
428         nextCondId(0),
429         alphTypeSet(false),
430         getKeyExpr(0),
431         accessExpr(0),
432         pExpr(0),
433         peExpr(0),
434         csExpr(0),
435         topExpr(0),
436         stackExpr(0),
437         actExpr(0),
438         tokstartExpr(0),
439         tokendExpr(0),
440         lowerNum(0),
441         upperNum(0),
442         fileName(fileName),
443         sectionName(sectionName),
444         sectionLoc(sectionLoc),
445         curActionOrd(0),
446         curPriorOrd(0),
447         rootName(0),
448         exportsRootName(0),
449         nextEpsilonResolvedLink(0),
450         nextLongestMatchId(1),
451         lmRequiresErrorState(false)
452 {
453         /* Initialize the dictionary of graphs. This is our symbol table. The
454          * initialization needs to be done on construction which happens at the
455          * beginning of a machine spec so any assignment operators can reference
456          * the builtins. */
457         initGraphDict();
458 }
459
460 /* Clean up the data collected during a parse. */
461 ParseData::~ParseData()
462 {
463         /* Delete all the nodes in the action list. Will cause all the
464          * string data that represents the actions to be deallocated. */
465         actionList.empty();
466 }
467
468 /* Make a name id in the current name instantiation scope if it is not
469  * already there. */
470 NameInst *ParseData::addNameInst( const InputLoc &loc, char *data, bool isLabel )
471 {
472         /* Create the name instantitaion object and insert it. */
473         NameInst *newNameInst = new NameInst( loc, curNameInst, data, nextNameId++, isLabel );
474         curNameInst->childVect.append( newNameInst );
475         if ( data != 0 )
476                 curNameInst->children.insertMulti( data, newNameInst );
477         return newNameInst;
478 }
479
480 void ParseData::initNameWalk()
481 {
482         curNameInst = rootName;
483         curNameChild = 0;
484 }
485
486 void ParseData::initExportsNameWalk()
487 {
488         curNameInst = exportsRootName;
489         curNameChild = 0;
490 }
491
492 /* Goes into the next child scope. The number of the child is already set up.
493  * We need this for the syncronous name tree and parse tree walk to work
494  * properly. It is reset on entry into a scope and advanced on poping of a
495  * scope. A call to enterNameScope should be accompanied by a corresponding
496  * popNameScope. */
497 NameFrame ParseData::enterNameScope( bool isLocal, int numScopes )
498 {
499         /* Save off the current data. */
500         NameFrame retFrame;
501         retFrame.prevNameInst = curNameInst;
502         retFrame.prevNameChild = curNameChild;
503         retFrame.prevLocalScope = localNameScope;
504
505         /* Enter into the new name scope. */
506         for ( int i = 0; i < numScopes; i++ ) {
507                 curNameInst = curNameInst->childVect[curNameChild];
508                 curNameChild = 0;
509         }
510
511         if ( isLocal )
512                 localNameScope = curNameInst;
513
514         return retFrame;
515 }
516
517 /* Return from a child scope to a parent. The parent info must be specified as
518  * an argument and is obtained from the corresponding call to enterNameScope.
519  * */
520 void ParseData::popNameScope( const NameFrame &frame )
521 {
522         /* Pop the name scope. */
523         curNameInst = frame.prevNameInst;
524         curNameChild = frame.prevNameChild+1;
525         localNameScope = frame.prevLocalScope;
526 }
527
528 void ParseData::resetNameScope( const NameFrame &frame )
529 {
530         /* Pop the name scope. */
531         curNameInst = frame.prevNameInst;
532         curNameChild = frame.prevNameChild;
533         localNameScope = frame.prevLocalScope;
534 }
535
536
537 void ParseData::unsetObsoleteEntries( FsmAp *graph )
538 {
539         /* Loop the reference names and increment the usage. Names that are no
540          * longer needed will be unset in graph. */
541         for ( NameVect::Iter ref = curNameInst->referencedNames; ref.lte(); ref++ ) {
542                 /* Get the name. */
543                 NameInst *name = *ref;
544                 name->numUses += 1;
545
546                 /* If the name is no longer needed unset its corresponding entry. */
547                 if ( name->numUses == name->numRefs ) {
548                         assert( graph->entryPoints.find( name->id ) != 0 );
549                         graph->unsetEntry( name->id );
550                         assert( graph->entryPoints.find( name->id ) == 0 );
551                 }
552         }
553 }
554
555 NameSet ParseData::resolvePart( NameInst *refFrom, char *data, bool recLabelsOnly )
556 {
557         /* Queue needed for breadth-first search, load it with the start node. */
558         NameInstList nameQueue;
559         nameQueue.append( refFrom );
560
561         NameSet result;
562         while ( nameQueue.length() > 0 ) {
563                 /* Pull the next from location off the queue. */
564                 NameInst *from = nameQueue.detachFirst();
565
566                 /* Look for the name. */
567                 NameMapEl *low, *high;
568                 if ( from->children.findMulti( data, low, high ) ) {
569                         /* Record all instances of the name. */
570                         for ( ; low <= high; low++ )
571                                 result.insert( low->value );
572                 }
573
574                 /* Name not there, do breadth-first operation of appending all
575                  * childrent to the processing queue. */
576                 for ( NameVect::Iter name = from->childVect; name.lte(); name++ ) {
577                         if ( !recLabelsOnly || (*name)->isLabel )
578                                 nameQueue.append( *name );
579                 }
580         }
581
582         /* Queue exhausted and name never found. */
583         return result;
584 }
585
586 void ParseData::resolveFrom( NameSet &result, NameInst *refFrom, 
587                 const NameRef &nameRef, int namePos )
588 {
589         /* Look for the name in the owning scope of the factor with aug. */
590         NameSet partResult = resolvePart( refFrom, nameRef[namePos], false );
591         
592         /* If there are more parts to the name then continue on. */
593         if ( ++namePos < nameRef.length() ) {
594                 /* There are more components to the name, search using all the part
595                  * results as the base. */
596                 for ( NameSet::Iter name = partResult; name.lte(); name++ )
597                         resolveFrom( result, *name, nameRef, namePos );
598         }
599         else {
600                 /* This is the last component, append the part results to the final
601                  * results. */
602                 result.insert( partResult );
603         }
604 }
605
606 /* Write out a name reference. */
607 ostream &operator<<( ostream &out, const NameRef &nameRef )
608 {
609         int pos = 0;
610         if ( nameRef[pos] == 0 ) {
611                 out << "::";
612                 pos += 1;
613         }
614         out << nameRef[pos++];
615         for ( ; pos < nameRef.length(); pos++ )
616                 out << "::" << nameRef[pos];
617         return out;
618 }
619
620 ostream &operator<<( ostream &out, const NameInst &nameInst )
621 {
622         /* Count the number fully qualified name parts. */
623         int numParents = 0;
624         NameInst *curParent = nameInst.parent;
625         while ( curParent != 0 ) {
626                 numParents += 1;
627                 curParent = curParent->parent;
628         }
629
630         /* Make an array and fill it in. */
631         curParent = nameInst.parent;
632         NameInst **parents = new NameInst*[numParents];
633         for ( int p = numParents-1; p >= 0; p-- ) {
634                 parents[p] = curParent;
635                 curParent = curParent->parent;
636         }
637                 
638         /* Write the parents out, skip the root. */
639         for ( int p = 1; p < numParents; p++ )
640                 out << "::" << ( parents[p]->name != 0 ? parents[p]->name : "<ANON>" );
641
642         /* Write the name and cleanup. */
643         out << "::" << ( nameInst.name != 0 ? nameInst.name : "<ANON>" );
644         delete[] parents;
645         return out;
646 }
647
648 struct CmpNameInstLoc
649 {
650         static int compare( const NameInst *ni1, const NameInst *ni2 )
651         {
652                 if ( ni1->loc.line < ni2->loc.line )
653                         return -1;
654                 else if ( ni1->loc.line > ni2->loc.line )
655                         return 1;
656                 else if ( ni1->loc.col < ni2->loc.col )
657                         return -1;
658                 else if ( ni1->loc.col > ni2->loc.col )
659                         return 1;
660                 return 0;
661         }
662 };
663
664 void errorStateLabels( const NameSet &resolved )
665 {
666         MergeSort<NameInst*, CmpNameInstLoc> mergeSort;
667         mergeSort.sort( resolved.data, resolved.length() );
668         for ( NameSet::Iter res = resolved; res.lte(); res++ )
669                 error((*res)->loc) << "  -> " << **res << endl;
670 }
671
672
673 NameInst *ParseData::resolveStateRef( const NameRef &nameRef, InputLoc &loc, Action *action )
674 {
675         NameInst *nameInst = 0;
676
677         /* Do the local search if the name is not strictly a root level name
678          * search. */
679         if ( nameRef[0] != 0 ) {
680                 /* If the action is referenced, resolve all of them. */
681                 if ( action != 0 && action->actionRefs.length() > 0 ) {
682                         /* Look for the name in all referencing scopes. */
683                         NameSet resolved;
684                         for ( ActionRefs::Iter actRef = action->actionRefs; actRef.lte(); actRef++ )
685                                 resolveFrom( resolved, *actRef, nameRef, 0 );
686
687                         if ( resolved.length() > 0 ) {
688                                 /* Take the first one. */
689                                 nameInst = resolved[0];
690                                 if ( resolved.length() > 1 ) {
691                                         /* Complain about the multiple references. */
692                                         error(loc) << "state reference " << nameRef << 
693                                                         " resolves to multiple entry points" << endl;
694                                         errorStateLabels( resolved );
695                                 }
696                         }
697                 }
698         }
699
700         /* If not found in the local scope, look in global. */
701         if ( nameInst == 0 ) {
702                 NameSet resolved;
703                 int fromPos = nameRef[0] != 0 ? 0 : 1;
704                 resolveFrom( resolved, rootName, nameRef, fromPos );
705
706                 if ( resolved.length() > 0 ) {
707                         /* Take the first. */
708                         nameInst = resolved[0];
709                         if ( resolved.length() > 1 ) {
710                                 /* Complain about the multiple references. */
711                                 error(loc) << "state reference " << nameRef << 
712                                                 " resolves to multiple entry points" << endl;
713                                 errorStateLabels( resolved );
714                         }
715                 }
716         }
717
718         if ( nameInst == 0 ) {
719                 /* If not found then complain. */
720                 error(loc) << "could not resolve state reference " << nameRef << endl;
721         }
722         return nameInst;
723 }
724
725 void ParseData::resolveNameRefs( InlineList *inlineList, Action *action )
726 {
727         for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
728                 switch ( item->type ) {
729                         case InlineItem::Entry: case InlineItem::Goto:
730                         case InlineItem::Call: case InlineItem::Next: {
731                                 /* Resolve, pass action for local search. */
732                                 NameInst *target = resolveStateRef( *item->nameRef, item->loc, action );
733
734                                 /* Check if the target goes into a longest match. */
735                                 NameInst *search = target->parent;
736                                 while ( search != 0 ) {
737                                         if ( search->isLongestMatch ) {
738                                                 error(item->loc) << "cannot enter inside a longest "
739                                                                 "match construction as an entry point" << endl;
740                                                 break;
741                                         }
742                                         search = search->parent;
743                                 }
744
745                                 /* Note the reference in the name. This will cause the entry
746                                  * point to survive to the end of the graph generating walk. */
747                                 if ( target != 0 )
748                                         target->numRefs += 1;
749                                 item->nameTarg = target;
750                                 break;
751                         }
752                         default:
753                                 break;
754                 }
755
756                 /* Some of the item types may have children. */
757                 if ( item->children != 0 )
758                         resolveNameRefs( item->children, action );
759         }
760 }
761
762 /* Resolve references to labels in actions. */
763 void ParseData::resolveActionNameRefs()
764 {
765         for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
766                 /* Only care about the actions that are referenced. */
767                 if ( act->actionRefs.length() > 0 )
768                         resolveNameRefs( act->inlineList, act );
769         }
770 }
771
772 /* Walk a name tree starting at from and fill the name index. */
773 void ParseData::fillNameIndex( NameInst *from )
774 {
775         /* Fill the value for from in the name index. */
776         nameIndex[from->id] = from;
777
778         /* Recurse on the implicit final state and then all children. */
779         if ( from->final != 0 )
780                 fillNameIndex( from->final );
781         for ( NameVect::Iter name = from->childVect; name.lte(); name++ )
782                 fillNameIndex( *name );
783 }
784
785 void ParseData::makeRootNames()
786 {
787         /* Create the root name. */
788         rootName = new NameInst( InputLoc(), 0, 0, nextNameId++, false );
789         exportsRootName = new NameInst( InputLoc(), 0, 0, nextNameId++, false );
790 }
791
792 /* Build the name tree and supporting data structures. */
793 void ParseData::makeNameTree( GraphDictEl *dictEl )
794 {
795         /* Set up curNameInst for the walk. */
796         initNameWalk();
797
798         if ( dictEl != 0 ) {
799                 /* A start location has been specified. */
800                 dictEl->value->makeNameTree( dictEl->loc, this );
801         }
802         else {
803                 /* First make the name tree. */
804                 for ( GraphList::Iter glel = instanceList; glel.lte(); glel++ ) {
805                         /* Recurse on the instance. */
806                         glel->value->makeNameTree( glel->loc, this );
807                 }
808         }
809         
810         /* The number of nodes in the tree can now be given by nextNameId */
811         nameIndex = new NameInst*[nextNameId];
812         memset( nameIndex, 0, sizeof(NameInst*)*nextNameId );
813         fillNameIndex( rootName );
814         fillNameIndex( exportsRootName );
815 }
816
817
818 void ParseData::createBuiltin( char *name, BuiltinMachine builtin )
819 {
820         Expression *expression = new Expression( builtin );
821         Join *join = new Join( expression );
822         JoinOrLm *joinOrLm = new JoinOrLm( join );
823         VarDef *varDef = new VarDef( name, joinOrLm );
824         GraphDictEl *graphDictEl = new GraphDictEl( name, varDef );
825         graphDict.insert( graphDictEl );
826 }
827
828 /* Initialize the graph dict with builtin types. */
829 void ParseData::initGraphDict( )
830 {
831         createBuiltin( "any", BT_Any );
832         createBuiltin( "ascii", BT_Ascii );
833         createBuiltin( "extend", BT_Extend );
834         createBuiltin( "alpha", BT_Alpha );
835         createBuiltin( "digit", BT_Digit );
836         createBuiltin( "alnum", BT_Alnum );
837         createBuiltin( "lower", BT_Lower );
838         createBuiltin( "upper", BT_Upper );
839         createBuiltin( "cntrl", BT_Cntrl );
840         createBuiltin( "graph", BT_Graph );
841         createBuiltin( "print", BT_Print );
842         createBuiltin( "punct", BT_Punct );
843         createBuiltin( "space", BT_Space );
844         createBuiltin( "xdigit", BT_Xdigit );
845         createBuiltin( "null", BT_Lambda );
846         createBuiltin( "zlen", BT_Lambda );
847         createBuiltin( "empty", BT_Empty );
848 }
849
850 /* Set the alphabet type. If the types are not valid returns false. */
851 bool ParseData::setAlphType( char *s1, char *s2 )
852 {
853         userAlphType = findAlphType( s1, s2 );
854         alphTypeSet = true;
855         return userAlphType != 0;
856 }
857
858 /* Set the alphabet type. If the types are not valid returns false. */
859 bool ParseData::setAlphType( char *s1 )
860 {
861         userAlphType = findAlphType( s1 );
862         alphTypeSet = true;
863         return userAlphType != 0;
864 }
865
866 bool ParseData::setVariable( char *var, InlineList *inlineList )
867 {
868         bool set = true;
869
870         if ( strcmp( var, "p" ) == 0 )
871                 pExpr = inlineList;
872         else if ( strcmp( var, "pe" ) == 0 )
873                 peExpr = inlineList;
874         else if ( strcmp( var, "cs" ) == 0 )
875                 csExpr = inlineList;
876         else if ( strcmp( var, "top" ) == 0 )
877                 topExpr = inlineList;
878         else if ( strcmp( var, "stack" ) == 0 )
879                 stackExpr = inlineList;
880         else if ( strcmp( var, "act" ) == 0 )
881                 actExpr = inlineList;
882         else if ( strcmp( var, "tokstart" ) == 0 )
883                 tokstartExpr = inlineList;
884         else if ( strcmp( var, "tokend" ) == 0 )
885                 tokendExpr = inlineList;
886         else
887                 set = false;
888
889         return set;
890 }
891
892 /* Initialize the key operators object that will be referenced by all fsms
893  * created. */
894 void ParseData::initKeyOps( )
895 {
896         /* Signedness and bounds. */
897         HostType *alphType = alphTypeSet ? userAlphType : hostLang->defaultAlphType;
898         thisKeyOps.setAlphType( alphType );
899
900         if ( lowerNum != 0 ) {
901                 /* If ranges are given then interpret the alphabet type. */
902                 thisKeyOps.minKey = makeFsmKeyNum( lowerNum, rangeLowLoc, this );
903                 thisKeyOps.maxKey = makeFsmKeyNum( upperNum, rangeHighLoc, this );
904         }
905
906         thisCondData.nextCondKey = thisKeyOps.maxKey;
907         thisCondData.nextCondKey.increment();
908 }
909
910 void ParseData::printNameInst( NameInst *nameInst, int level )
911 {
912         for ( int i = 0; i < level; i++ )
913                 cerr << "  ";
914         cerr << (nameInst->name != 0 ? nameInst->name : "<ANON>") << 
915                         "  id: " << nameInst->id << 
916                         "  refs: " << nameInst->numRefs <<
917                         "  uses: " << nameInst->numUses << endl;
918         for ( NameVect::Iter name = nameInst->childVect; name.lte(); name++ )
919                 printNameInst( *name, level+1 );
920 }
921
922 /* Remove duplicates of unique actions from an action table. */
923 void ParseData::removeDups( ActionTable &table )
924 {
925         /* Scan through the table looking for unique actions to 
926          * remove duplicates of. */
927         for ( int i = 0; i < table.length(); i++ ) {
928                 /* Remove any duplicates ahead of i. */
929                 for ( int r = i+1; r < table.length(); ) {
930                         if ( table[r].value == table[i].value )
931                                 table.vremove(r);
932                         else
933                                 r += 1;
934                 }
935         }
936 }
937
938 /* Remove duplicates from action lists. This operates only on transition and
939  * eof action lists and so should be called once all actions have been
940  * transfered to their final resting place. */
941 void ParseData::removeActionDups( FsmAp *graph )
942 {
943         /* Loop all states. */
944         for ( StateList::Iter state = graph->stateList; state.lte(); state++ ) {
945                 /* Loop all transitions. */
946                 for ( TransList::Iter trans = state->outList; trans.lte(); trans++ )
947                         removeDups( trans->actionTable );
948                 removeDups( state->toStateActionTable );
949                 removeDups( state->fromStateActionTable );
950                 removeDups( state->eofActionTable );
951         }
952 }
953
954 Action *ParseData::newAction( char *name, InlineList *inlineList )
955 {
956         InputLoc loc;
957         loc.line = 1;
958         loc.col = 1;
959         loc.fileName = "<NONE>";
960
961         Action *action = new Action( loc, name, inlineList, nextCondId++ );
962         action->actionRefs.append( rootName );
963         actionList.append( action );
964         return action;
965 }
966
967 void ParseData::initLongestMatchData()
968 {
969         if ( lmList.length() > 0 ) {
970                 /* The initTokStart action resets the token start. */
971                 InlineList *il1 = new InlineList;
972                 il1->append( new InlineItem( InputLoc(), InlineItem::LmInitTokStart ) );
973                 initTokStart = newAction( "initts", il1 );
974                 initTokStart->isLmAction = true;
975
976                 /* The initActId action gives act a default value. */
977                 InlineList *il4 = new InlineList;
978                 il4->append( new InlineItem( InputLoc(), InlineItem::LmInitAct ) );
979                 initActId = newAction( "initact", il4 );
980                 initActId->isLmAction = true;
981
982                 /* The setTokStart action sets tokstart. */
983                 InlineList *il5 = new InlineList;
984                 il5->append( new InlineItem( InputLoc(), InlineItem::LmSetTokStart ) );
985                 setTokStart = newAction( "tokstart", il5 );
986                 setTokStart->isLmAction = true;
987
988                 /* The setTokEnd action sets tokend. */
989                 InlineList *il3 = new InlineList;
990                 il3->append( new InlineItem( InputLoc(), InlineItem::LmSetTokEnd ) );
991                 setTokEnd = newAction( "tokend", il3 );
992                 setTokEnd->isLmAction = true;
993
994                 /* The action will also need an ordering: ahead of all user action
995                  * embeddings. */
996                 initTokStartOrd = curActionOrd++;
997                 initActIdOrd = curActionOrd++;
998                 setTokStartOrd = curActionOrd++;
999                 setTokEndOrd = curActionOrd++;
1000         }
1001 }
1002
1003 /* After building the graph, do some extra processing to ensure the runtime
1004  * data of the longest mactch operators is consistent. */
1005 void ParseData::setLongestMatchData( FsmAp *graph )
1006 {
1007         if ( lmList.length() > 0 ) {
1008                 /* Make sure all entry points (targets of fgoto, fcall, fnext, fentry)
1009                  * init the tokstart. */
1010                 for ( EntryMap::Iter en = graph->entryPoints; en.lte(); en++ ) {
1011                         /* This is run after duplicates are removed, we must guard against
1012                          * inserting a duplicate. */
1013                         ActionTable &actionTable = en->value->toStateActionTable;
1014                         if ( ! actionTable.hasAction( initTokStart ) )
1015                                 actionTable.setAction( initTokStartOrd, initTokStart );
1016                 }
1017
1018                 /* Find the set of states that are the target of transitions with
1019                  * actions that have calls. These states will be targeted by fret
1020                  * statements. */
1021                 StateSet states;
1022                 for ( StateList::Iter state = graph->stateList; state.lte(); state++ ) {
1023                         for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) {
1024                                 for ( ActionTable::Iter ati = trans->actionTable; ati.lte(); ati++ ) {
1025                                         if ( ati->value->anyCall && trans->toState != 0 )
1026                                                 states.insert( trans->toState );
1027                                 }
1028                         }
1029                 }
1030
1031
1032                 /* Init tokstart upon entering the above collected states. */
1033                 for ( StateSet::Iter ps = states; ps.lte(); ps++ ) {
1034                         /* This is run after duplicates are removed, we must guard against
1035                          * inserting a duplicate. */
1036                         ActionTable &actionTable = (*ps)->toStateActionTable;
1037                         if ( ! actionTable.hasAction( initTokStart ) )
1038                                 actionTable.setAction( initTokStartOrd, initTokStart );
1039                 }
1040         }
1041 }
1042
1043 /* Make the graph from a graph dict node. Does minimization and state sorting. */
1044 FsmAp *ParseData::makeInstance( GraphDictEl *gdNode )
1045 {
1046         /* Build the graph from a walk of the parse tree. */
1047         FsmAp *graph = gdNode->value->walk( this );
1048
1049         /* Resolve any labels that point to multiple states. Any labels that are
1050          * still around are referenced only by gotos and calls and they need to be
1051          * made into deterministic entry points. */
1052         graph->deterministicEntry();
1053
1054         /*
1055          * All state construction is now complete.
1056          */
1057
1058         /* Transfer global error actions. */
1059         for ( StateList::Iter state = graph->stateList; state.lte(); state++ )
1060                 graph->transferErrorActions( state, 0 );
1061         
1062         removeActionDups( graph );
1063
1064         /* Remove unreachable states. There should be no dead end states. The
1065          * subtract and intersection operators are the only places where they may
1066          * be created and those operators clean them up. */
1067         graph->removeUnreachableStates();
1068
1069         /* No more fsm operations are to be done. Action ordering numbers are
1070          * no longer of use and will just hinder minimization. Clear them. */
1071         graph->nullActionKeys();
1072
1073         /* Transition priorities are no longer of use. We can clear them
1074          * because they will just hinder minimization as well. Clear them. */
1075         graph->clearAllPriorities();
1076
1077         if ( minimizeOpt != MinimizeNone ) {
1078                 /* Minimize here even if we minimized at every op. Now that function
1079                  * keys have been cleared we may get a more minimal fsm. */
1080                 switch ( minimizeLevel ) {
1081                         case MinimizeApprox:
1082                                 graph->minimizeApproximate();
1083                                 break;
1084                         case MinimizeStable:
1085                                 graph->minimizeStable();
1086                                 break;
1087                         case MinimizePartition1:
1088                                 graph->minimizePartition1();
1089                                 break;
1090                         case MinimizePartition2:
1091                                 graph->minimizePartition2();
1092                                 break;
1093                 }
1094         }
1095
1096         graph->compressTransitions();
1097
1098         return graph;
1099 }
1100
1101 void ParseData::printNameTree()
1102 {
1103         /* Print the name instance map. */
1104         for ( NameVect::Iter name = rootName->childVect; name.lte(); name++ )
1105                 printNameInst( *name, 0 );
1106         
1107         cerr << "name index:" << endl;
1108         /* Show that the name index is correct. */
1109         for ( int ni = 0; ni < nextNameId; ni++ ) {
1110                 cerr << ni << ": ";
1111                 char *name = nameIndex[ni]->name;
1112                 cerr << ( name != 0 ? name : "<ANON>" ) << endl;
1113         }
1114 }
1115
1116 FsmAp *ParseData::makeSpecific( GraphDictEl *gdNode )
1117 {
1118         /* Build the name tree and supporting data structures. */
1119         makeNameTree( gdNode );
1120
1121         /* Resove name references from gdNode. */
1122         initNameWalk();
1123         gdNode->value->resolveNameRefs( this );
1124
1125         /* Do not resolve action references. Since we are not building the entire
1126          * graph there's a good chance that many name references will fail. This
1127          * is okay since generating part of the graph is usually only done when
1128          * inspecting the compiled machine. */
1129
1130         /* Same story for extern entry point references. */
1131
1132         /* Flag this case so that the XML code generator is aware that we haven't
1133          * looked up name references in actions. It can then avoid segfaulting. */
1134         generatingSectionSubset = true;
1135
1136         /* Just building the specified graph. */
1137         initNameWalk();
1138         FsmAp *mainGraph = makeInstance( gdNode );
1139
1140         return mainGraph;
1141 }
1142
1143 FsmAp *ParseData::makeAll()
1144 {
1145         /* Build the name tree and supporting data structures. */
1146         makeNameTree( 0 );
1147
1148         /* Resove name references in the tree. */
1149         initNameWalk();
1150         for ( GraphList::Iter glel = instanceList; glel.lte(); glel++ )
1151                 glel->value->resolveNameRefs( this );
1152
1153         /* Resolve action code name references. */
1154         resolveActionNameRefs();
1155
1156         /* Force name references to the top level instantiations. */
1157         for ( NameVect::Iter inst = rootName->childVect; inst.lte(); inst++ )
1158                 (*inst)->numRefs += 1;
1159
1160         FsmAp *mainGraph = 0;
1161         FsmAp **graphs = new FsmAp*[instanceList.length()];
1162         int numOthers = 0;
1163
1164         /* Make all the instantiations, we know that main exists in this list. */
1165         initNameWalk();
1166         for ( GraphList::Iter glel = instanceList; glel.lte();  glel++ ) {
1167                 if ( strcmp( glel->key, mainMachine ) == 0 ) {
1168                         /* Main graph is always instantiated. */
1169                         mainGraph = makeInstance( glel );
1170                 }
1171                 else {
1172                         /* Instantiate and store in others array. */
1173                         graphs[numOthers++] = makeInstance( glel );
1174                 }
1175         }
1176
1177         if ( mainGraph == 0 )
1178                 mainGraph = graphs[--numOthers];
1179
1180         if ( numOthers > 0 ) {
1181                 /* Add all the other graphs into main. */
1182                 mainGraph->globOp( graphs, numOthers );
1183         }
1184
1185         delete[] graphs;
1186         return mainGraph;
1187 }
1188
1189 void ParseData::analyzeAction( Action *action, InlineList *inlineList )
1190 {
1191         /* FIXME: Actions used as conditions should be very constrained. */
1192         for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
1193                 if ( item->type == InlineItem::Call || item->type == InlineItem::CallExpr )
1194                         action->anyCall = true;
1195
1196                 /* Need to recurse into longest match items. */
1197                 if ( item->type == InlineItem::LmSwitch ) {
1198                         LongestMatch *lm = item->longestMatch;
1199                         for ( LmPartList::Iter lmi = *lm->longestMatchList; lmi.lte(); lmi++ ) {
1200                                 if ( lmi->action != 0 )
1201                                         analyzeAction( action, lmi->action->inlineList );
1202                         }
1203                 }
1204
1205                 if ( item->type == InlineItem::LmOnLast || 
1206                                 item->type == InlineItem::LmOnNext ||
1207                                 item->type == InlineItem::LmOnLagBehind )
1208                 {
1209                         LongestMatchPart *lmi = item->longestMatchPart;
1210                         if ( lmi->action != 0 )
1211                                 analyzeAction( action, lmi->action->inlineList );
1212                 }
1213
1214                 if ( item->children != 0 )
1215                         analyzeAction( action, item->children );
1216         }
1217 }
1218
1219
1220 /* Check actions for bad uses of fsm directives. We don't go inside longest
1221  * match items in actions created by ragel, since we just want the user
1222  * actions. */
1223 void ParseData::checkInlineList( Action *act, InlineList *inlineList )
1224 {
1225         for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
1226                 /* EOF checks. */
1227                 if ( act->numEofRefs > 0 ) {
1228                         switch ( item->type ) {
1229                         case InlineItem::PChar: 
1230                                 error(item->loc) << "pointer to current element does not exist in "
1231                                                 "EOF action code" << endl;
1232                                 break;
1233                         case InlineItem::Char: 
1234                                 error(item->loc) << "current element does not exist in "
1235                                                 "EOF action code" << endl;
1236                                 break;
1237                         case InlineItem::Hold:
1238                                 error(item->loc) << "changing the current element not possible in "
1239                                                 "EOF action code" << endl;
1240                                 break;
1241                         case InlineItem::Exec:
1242                                 error(item->loc) << "changing the current element not possible in "
1243                                                 "EOF action code" << endl;
1244                                 break;
1245                         case InlineItem::Goto: case InlineItem::Call: 
1246                         case InlineItem::Next: case InlineItem::GotoExpr: 
1247                         case InlineItem::CallExpr: case InlineItem::NextExpr:
1248                         case InlineItem::Ret:
1249                                 error(item->loc) << "changing the current state not possible in "
1250                                                 "EOF action code" << endl;
1251                                 break;
1252                         default:
1253                                 break;
1254                         }
1255                 }
1256
1257                 /* Recurse. */
1258                 if ( item->children != 0 )
1259                         checkInlineList( act, item->children );
1260         }
1261 }
1262
1263 void ParseData::checkAction( Action *action )
1264 {
1265         /* Check for actions with calls that are embedded within a longest match
1266          * machine. */
1267         if ( !action->isLmAction && action->numRefs() > 0 && action->anyCall ) {
1268                 for ( ActionRefs::Iter ar = action->actionRefs; ar.lte(); ar++ ) {
1269                         NameInst *check = *ar;
1270                         while ( check != 0 ) {
1271                                 if ( check->isLongestMatch ) {
1272                                         error(action->loc) << "within a scanner, fcall is permitted"
1273                                                 " only in pattern actions" << endl;
1274                                         break;
1275                                 }
1276                                 check = check->parent;
1277                         }
1278                 }
1279         }
1280
1281         checkInlineList( action, action->inlineList );
1282 }
1283
1284
1285 void ParseData::analyzeGraph( FsmAp *graph )
1286 {
1287         for ( ActionList::Iter act = actionList; act.lte(); act++ )
1288                 analyzeAction( act, act->inlineList );
1289
1290         for ( StateList::Iter st = graph->stateList; st.lte(); st++ ) {
1291                 /* The transition list. */
1292                 for ( TransList::Iter trans = st->outList; trans.lte(); trans++ ) {
1293                         for ( ActionTable::Iter at = trans->actionTable; at.lte(); at++ )
1294                                 at->value->numTransRefs += 1;
1295                 }
1296
1297                 for ( ActionTable::Iter at = st->toStateActionTable; at.lte(); at++ )
1298                         at->value->numToStateRefs += 1;
1299
1300                 for ( ActionTable::Iter at = st->fromStateActionTable; at.lte(); at++ )
1301                         at->value->numFromStateRefs += 1;
1302
1303                 for ( ActionTable::Iter at = st->eofActionTable; at.lte(); at++ )
1304                         at->value->numEofRefs += 1;
1305
1306                 for ( StateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
1307                         for ( CondSet::Iter sci = sc->condSpace->condSet; sci.lte(); sci++ )
1308                                 (*sci)->numCondRefs += 1;
1309                 }
1310         }
1311
1312         /* Checks for bad usage of directives in action code. */
1313         for ( ActionList::Iter act = actionList; act.lte(); act++ )
1314                 checkAction( act );
1315 }
1316
1317 void ParseData::makeExportsNameTree()
1318 {
1319         /* Make a name tree for the exports. */
1320         initExportsNameWalk();
1321
1322         /* First make the name tree. */
1323         for ( GraphDict::Iter gdel = graphDict; gdel.lte(); gdel++ ) {
1324                 if ( gdel->value->isExport ) {
1325                         /* Recurse on the instance. */
1326                         gdel->value->makeNameTree( gdel->loc, this );
1327                 }
1328         }
1329 }
1330
1331 void ParseData::makeExports()
1332 {
1333         makeExportsNameTree();
1334
1335         /* Resove name references in the tree. */
1336         initExportsNameWalk();
1337         for ( GraphDict::Iter gdel = graphDict; gdel.lte(); gdel++ ) {
1338                 if ( gdel->value->isExport )
1339                         gdel->value->resolveNameRefs( this );
1340         }
1341
1342         /* Make all the instantiations, we know that main exists in this list. */
1343         initExportsNameWalk();
1344         for ( GraphDict::Iter gdel = graphDict; gdel.lte();  gdel++ ) {
1345                 /* Check if this var def is an export. */
1346                 if ( gdel->value->isExport ) {
1347                         /* Build the graph from a walk of the parse tree. */
1348                         FsmAp *graph = gdel->value->walk( this );
1349
1350                         /* Build the graph from a walk of the parse tree. */
1351                         if ( !graph->checkSingleCharMachine() ) {
1352                                 error(gdel->loc) << "bad export machine, must define "
1353                                                 "a single character" << endl;
1354                         }
1355                         else {
1356                                 /* Safe to extract the key and declare the export. */
1357                                 Key exportKey = graph->startState->outList.head->lowKey;
1358                                 exportList.append( new Export( gdel->value->name, exportKey ) );
1359                         }
1360                 }
1361         }
1362
1363 }
1364
1365 void ParseData::prepareMachineGen( GraphDictEl *graphDictEl )
1366 {
1367         beginProcessing();
1368         initKeyOps();
1369         makeRootNames();
1370         initLongestMatchData();
1371
1372         /* Make the graph, do minimization. */
1373         if ( graphDictEl == 0 )
1374                 sectionGraph = makeAll();
1375         else
1376                 sectionGraph = makeSpecific( graphDictEl );
1377         
1378         /* Compute exports from the export definitions. */
1379         makeExports();
1380
1381         /* If any errors have occured in the input file then don't write anything. */
1382         if ( gblErrorCount > 0 )
1383                 return;
1384
1385         analyzeGraph( sectionGraph );
1386
1387         /* Depends on the graph analysis. */
1388         setLongestMatchData( sectionGraph );
1389
1390         /* Decide if an error state is necessary.
1391          *  1. There is an error transition
1392          *  2. There is a gap in the transitions
1393          *  3. The longest match operator requires it. */
1394         if ( lmRequiresErrorState || sectionGraph->hasErrorTrans() )
1395                 sectionGraph->errState = sectionGraph->addState();
1396
1397         /* State numbers need to be assigned such that all final states have a
1398          * larger state id number than all non-final states. This enables the
1399          * first_final mechanism to function correctly. We also want states to be
1400          * ordered in a predictable fashion. So we first apply a depth-first
1401          * search, then do a stable sort by final state status, then assign
1402          * numbers. */
1403
1404         sectionGraph->depthFirstOrdering();
1405         sectionGraph->sortStatesByFinal();
1406         sectionGraph->setStateNumbers( 0 );
1407 }
1408
1409 void ParseData::generateXML( ostream &out )
1410 {
1411         beginProcessing();
1412
1413         /* Make the generator. */
1414         XMLCodeGen codeGen( sectionName, this, sectionGraph, out );
1415
1416         /* Write out with it. */
1417         codeGen.writeXML();
1418
1419         if ( printStatistics ) {
1420                 cerr << "fsm name  : " << sectionName << endl;
1421                 cerr << "num states: " << sectionGraph->stateList.length() << endl;
1422                 cerr << endl;
1423         }
1424 }
1425
1426 /* Send eof to all parsers. */
1427 void terminateAllParsers( )
1428 {
1429         /* FIXME: a proper token is needed here. Suppose we should use the
1430          * location of EOF in the last file that the parser was referenced in. */
1431         InputLoc loc;
1432         loc.fileName = "<EOF>";
1433         loc.line = 0;
1434         loc.col = 0;
1435         for ( ParserDict::Iter pdel = parserDict; pdel.lte(); pdel++ )
1436                 pdel->value->token( loc, _eof, 0, 0 );
1437 }
1438
1439 void writeLanguage( std::ostream &out )
1440 {
1441         out << " lang=\"";
1442         switch ( hostLang->lang ) {
1443                 case HostLang::C:    out << "C"; break;
1444                 case HostLang::D:    out << "D"; break;
1445                 case HostLang::Java: out << "Java"; break;
1446                 case HostLang::Ruby: out << "Ruby"; break;
1447         }
1448         out << "\"";
1449         
1450 }
1451
1452 void writeMachines( std::ostream &out, std::string hostData, char *inputFileName )
1453 {
1454         if ( machineSpec == 0 && machineName == 0 ) {
1455                 /* No machine spec or machine name given. Generate everything. */
1456                 for ( ParserDict::Iter parser = parserDict; parser.lte(); parser++ ) {
1457                         ParseData *pd = parser->value->pd;
1458                         if ( pd->instanceList.length() > 0 )
1459                                 pd->prepareMachineGen( 0 );
1460                 }
1461
1462                 if ( gblErrorCount == 0 ) {
1463                         out << "<ragel version=\"" VERSION "\" filename=\"" << inputFileName << "\"";
1464                         writeLanguage( out );
1465                         out << ">\n";
1466                         for ( ParserDict::Iter parser = parserDict; parser.lte(); parser++ ) {
1467                                 ParseData *pd = parser->value->pd;
1468                                 if ( pd->instanceList.length() > 0 )
1469                                         pd->generateXML( out );
1470                         }
1471                         out << hostData;
1472                         out << "</ragel>\n";
1473                 }
1474         }
1475         else if ( parserDict.length() > 0 ) {
1476                 /* There is either a machine spec or machine name given. */
1477                 ParseData *parseData = 0;
1478                 GraphDictEl *graphDictEl = 0;
1479
1480                 /* Traverse the sections, break out when we find a section/machine
1481                  * that matches the one specified. */
1482                 for ( ParserDict::Iter parser = parserDict; parser.lte(); parser++ ) {
1483                         ParseData *checkPd = parser->value->pd;
1484                         if ( machineSpec == 0 || strcmp( checkPd->sectionName, machineSpec ) == 0 ) {
1485                                 GraphDictEl *checkGdEl = 0;
1486                                 if ( machineName == 0 || (checkGdEl = 
1487                                                 checkPd->graphDict.find( machineName )) != 0 )
1488                                 {
1489                                         /* Have a machine spec and/or machine name that matches
1490                                          * the -M/-S options. */
1491                                         parseData = checkPd;
1492                                         graphDictEl = checkGdEl;
1493                                         break;
1494                                 }
1495                         }
1496                 }
1497
1498                 if ( parseData == 0 )
1499                         error() << "could not locate machine specified with -S and/or -M" << endl;
1500                 else {
1501                         /* Section/Machine to emit was found. Prepare and emit it. */
1502                         parseData->prepareMachineGen( graphDictEl );
1503                         if ( gblErrorCount == 0 ) {
1504                                 out << "<ragel version=\"" VERSION "\" filename=\"" << inputFileName << "\"";
1505                                 writeLanguage( out );
1506                                 out << ">\n";
1507                                 parseData->generateXML( out );
1508                                 out << hostData;
1509                                 out << "</ragel>\n";
1510                         }
1511                 }
1512         }
1513 }