C# patch Daniel Tang.
[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( const 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         prePushExpr(0),
433         postPopExpr(0),
434         pExpr(0),
435         peExpr(0),
436         eofExpr(0),
437         csExpr(0),
438         topExpr(0),
439         stackExpr(0),
440         actExpr(0),
441         tokstartExpr(0),
442         tokendExpr(0),
443         dataExpr(0),
444         lowerNum(0),
445         upperNum(0),
446         fileName(fileName),
447         sectionName(sectionName),
448         sectionLoc(sectionLoc),
449         curActionOrd(0),
450         curPriorOrd(0),
451         rootName(0),
452         exportsRootName(0),
453         nextEpsilonResolvedLink(0),
454         nextLongestMatchId(1),
455         lmRequiresErrorState(false)
456 {
457         /* Initialize the dictionary of graphs. This is our symbol table. The
458          * initialization needs to be done on construction which happens at the
459          * beginning of a machine spec so any assignment operators can reference
460          * the builtins. */
461         initGraphDict();
462 }
463
464 /* Clean up the data collected during a parse. */
465 ParseData::~ParseData()
466 {
467         /* Delete all the nodes in the action list. Will cause all the
468          * string data that represents the actions to be deallocated. */
469         actionList.empty();
470 }
471
472 /* Make a name id in the current name instantiation scope if it is not
473  * already there. */
474 NameInst *ParseData::addNameInst( const InputLoc &loc, const char *data, bool isLabel )
475 {
476         /* Create the name instantitaion object and insert it. */
477         NameInst *newNameInst = new NameInst( loc, curNameInst, data, nextNameId++, isLabel );
478         curNameInst->childVect.append( newNameInst );
479         if ( data != 0 )
480                 curNameInst->children.insertMulti( data, newNameInst );
481         return newNameInst;
482 }
483
484 void ParseData::initNameWalk()
485 {
486         curNameInst = rootName;
487         curNameChild = 0;
488 }
489
490 void ParseData::initExportsNameWalk()
491 {
492         curNameInst = exportsRootName;
493         curNameChild = 0;
494 }
495
496 /* Goes into the next child scope. The number of the child is already set up.
497  * We need this for the syncronous name tree and parse tree walk to work
498  * properly. It is reset on entry into a scope and advanced on poping of a
499  * scope. A call to enterNameScope should be accompanied by a corresponding
500  * popNameScope. */
501 NameFrame ParseData::enterNameScope( bool isLocal, int numScopes )
502 {
503         /* Save off the current data. */
504         NameFrame retFrame;
505         retFrame.prevNameInst = curNameInst;
506         retFrame.prevNameChild = curNameChild;
507         retFrame.prevLocalScope = localNameScope;
508
509         /* Enter into the new name scope. */
510         for ( int i = 0; i < numScopes; i++ ) {
511                 curNameInst = curNameInst->childVect[curNameChild];
512                 curNameChild = 0;
513         }
514
515         if ( isLocal )
516                 localNameScope = curNameInst;
517
518         return retFrame;
519 }
520
521 /* Return from a child scope to a parent. The parent info must be specified as
522  * an argument and is obtained from the corresponding call to enterNameScope.
523  * */
524 void ParseData::popNameScope( const NameFrame &frame )
525 {
526         /* Pop the name scope. */
527         curNameInst = frame.prevNameInst;
528         curNameChild = frame.prevNameChild+1;
529         localNameScope = frame.prevLocalScope;
530 }
531
532 void ParseData::resetNameScope( const NameFrame &frame )
533 {
534         /* Pop the name scope. */
535         curNameInst = frame.prevNameInst;
536         curNameChild = frame.prevNameChild;
537         localNameScope = frame.prevLocalScope;
538 }
539
540
541 void ParseData::unsetObsoleteEntries( FsmAp *graph )
542 {
543         /* Loop the reference names and increment the usage. Names that are no
544          * longer needed will be unset in graph. */
545         for ( NameVect::Iter ref = curNameInst->referencedNames; ref.lte(); ref++ ) {
546                 /* Get the name. */
547                 NameInst *name = *ref;
548                 name->numUses += 1;
549
550                 /* If the name is no longer needed unset its corresponding entry. */
551                 if ( name->numUses == name->numRefs ) {
552                         assert( graph->entryPoints.find( name->id ) != 0 );
553                         graph->unsetEntry( name->id );
554                         assert( graph->entryPoints.find( name->id ) == 0 );
555                 }
556         }
557 }
558
559 NameSet ParseData::resolvePart( NameInst *refFrom, const char *data, bool recLabelsOnly )
560 {
561         /* Queue needed for breadth-first search, load it with the start node. */
562         NameInstList nameQueue;
563         nameQueue.append( refFrom );
564
565         NameSet result;
566         while ( nameQueue.length() > 0 ) {
567                 /* Pull the next from location off the queue. */
568                 NameInst *from = nameQueue.detachFirst();
569
570                 /* Look for the name. */
571                 NameMapEl *low, *high;
572                 if ( from->children.findMulti( data, low, high ) ) {
573                         /* Record all instances of the name. */
574                         for ( ; low <= high; low++ )
575                                 result.insert( low->value );
576                 }
577
578                 /* Name not there, do breadth-first operation of appending all
579                  * childrent to the processing queue. */
580                 for ( NameVect::Iter name = from->childVect; name.lte(); name++ ) {
581                         if ( !recLabelsOnly || (*name)->isLabel )
582                                 nameQueue.append( *name );
583                 }
584         }
585
586         /* Queue exhausted and name never found. */
587         return result;
588 }
589
590 void ParseData::resolveFrom( NameSet &result, NameInst *refFrom, 
591                 const NameRef &nameRef, int namePos )
592 {
593         /* Look for the name in the owning scope of the factor with aug. */
594         NameSet partResult = resolvePart( refFrom, nameRef[namePos], false );
595         
596         /* If there are more parts to the name then continue on. */
597         if ( ++namePos < nameRef.length() ) {
598                 /* There are more components to the name, search using all the part
599                  * results as the base. */
600                 for ( NameSet::Iter name = partResult; name.lte(); name++ )
601                         resolveFrom( result, *name, nameRef, namePos );
602         }
603         else {
604                 /* This is the last component, append the part results to the final
605                  * results. */
606                 result.insert( partResult );
607         }
608 }
609
610 /* Write out a name reference. */
611 ostream &operator<<( ostream &out, const NameRef &nameRef )
612 {
613         int pos = 0;
614         if ( nameRef[pos] == 0 ) {
615                 out << "::";
616                 pos += 1;
617         }
618         out << nameRef[pos++];
619         for ( ; pos < nameRef.length(); pos++ )
620                 out << "::" << nameRef[pos];
621         return out;
622 }
623
624 ostream &operator<<( ostream &out, const NameInst &nameInst )
625 {
626         /* Count the number fully qualified name parts. */
627         int numParents = 0;
628         NameInst *curParent = nameInst.parent;
629         while ( curParent != 0 ) {
630                 numParents += 1;
631                 curParent = curParent->parent;
632         }
633
634         /* Make an array and fill it in. */
635         curParent = nameInst.parent;
636         NameInst **parents = new NameInst*[numParents];
637         for ( int p = numParents-1; p >= 0; p-- ) {
638                 parents[p] = curParent;
639                 curParent = curParent->parent;
640         }
641                 
642         /* Write the parents out, skip the root. */
643         for ( int p = 1; p < numParents; p++ )
644                 out << "::" << ( parents[p]->name != 0 ? parents[p]->name : "<ANON>" );
645
646         /* Write the name and cleanup. */
647         out << "::" << ( nameInst.name != 0 ? nameInst.name : "<ANON>" );
648         delete[] parents;
649         return out;
650 }
651
652 struct CmpNameInstLoc
653 {
654         static int compare( const NameInst *ni1, const NameInst *ni2 )
655         {
656                 if ( ni1->loc.line < ni2->loc.line )
657                         return -1;
658                 else if ( ni1->loc.line > ni2->loc.line )
659                         return 1;
660                 else if ( ni1->loc.col < ni2->loc.col )
661                         return -1;
662                 else if ( ni1->loc.col > ni2->loc.col )
663                         return 1;
664                 return 0;
665         }
666 };
667
668 void errorStateLabels( const NameSet &resolved )
669 {
670         MergeSort<NameInst*, CmpNameInstLoc> mergeSort;
671         mergeSort.sort( resolved.data, resolved.length() );
672         for ( NameSet::Iter res = resolved; res.lte(); res++ )
673                 error((*res)->loc) << "  -> " << **res << endl;
674 }
675
676
677 NameInst *ParseData::resolveStateRef( const NameRef &nameRef, InputLoc &loc, Action *action )
678 {
679         NameInst *nameInst = 0;
680
681         /* Do the local search if the name is not strictly a root level name
682          * search. */
683         if ( nameRef[0] != 0 ) {
684                 /* If the action is referenced, resolve all of them. */
685                 if ( action != 0 && action->actionRefs.length() > 0 ) {
686                         /* Look for the name in all referencing scopes. */
687                         NameSet resolved;
688                         for ( ActionRefs::Iter actRef = action->actionRefs; actRef.lte(); actRef++ )
689                                 resolveFrom( resolved, *actRef, nameRef, 0 );
690
691                         if ( resolved.length() > 0 ) {
692                                 /* Take the first one. */
693                                 nameInst = resolved[0];
694                                 if ( resolved.length() > 1 ) {
695                                         /* Complain about the multiple references. */
696                                         error(loc) << "state reference " << nameRef << 
697                                                         " resolves to multiple entry points" << endl;
698                                         errorStateLabels( resolved );
699                                 }
700                         }
701                 }
702         }
703
704         /* If not found in the local scope, look in global. */
705         if ( nameInst == 0 ) {
706                 NameSet resolved;
707                 int fromPos = nameRef[0] != 0 ? 0 : 1;
708                 resolveFrom( resolved, rootName, nameRef, fromPos );
709
710                 if ( resolved.length() > 0 ) {
711                         /* Take the first. */
712                         nameInst = resolved[0];
713                         if ( resolved.length() > 1 ) {
714                                 /* Complain about the multiple references. */
715                                 error(loc) << "state reference " << nameRef << 
716                                                 " resolves to multiple entry points" << endl;
717                                 errorStateLabels( resolved );
718                         }
719                 }
720         }
721
722         if ( nameInst == 0 ) {
723                 /* If not found then complain. */
724                 error(loc) << "could not resolve state reference " << nameRef << endl;
725         }
726         return nameInst;
727 }
728
729 void ParseData::resolveNameRefs( InlineList *inlineList, Action *action )
730 {
731         for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
732                 switch ( item->type ) {
733                         case InlineItem::Entry: case InlineItem::Goto:
734                         case InlineItem::Call: case InlineItem::Next: {
735                                 /* Resolve, pass action for local search. */
736                                 NameInst *target = resolveStateRef( *item->nameRef, item->loc, action );
737
738                                 /* Check if the target goes into a longest match. */
739                                 NameInst *search = target->parent;
740                                 while ( search != 0 ) {
741                                         if ( search->isLongestMatch ) {
742                                                 error(item->loc) << "cannot enter inside a longest "
743                                                                 "match construction as an entry point" << endl;
744                                                 break;
745                                         }
746                                         search = search->parent;
747                                 }
748
749                                 /* Note the reference in the name. This will cause the entry
750                                  * point to survive to the end of the graph generating walk. */
751                                 if ( target != 0 )
752                                         target->numRefs += 1;
753                                 item->nameTarg = target;
754                                 break;
755                         }
756                         default:
757                                 break;
758                 }
759
760                 /* Some of the item types may have children. */
761                 if ( item->children != 0 )
762                         resolveNameRefs( item->children, action );
763         }
764 }
765
766 /* Resolve references to labels in actions. */
767 void ParseData::resolveActionNameRefs()
768 {
769         for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
770                 /* Only care about the actions that are referenced. */
771                 if ( act->actionRefs.length() > 0 )
772                         resolveNameRefs( act->inlineList, act );
773         }
774 }
775
776 /* Walk a name tree starting at from and fill the name index. */
777 void ParseData::fillNameIndex( NameInst *from )
778 {
779         /* Fill the value for from in the name index. */
780         nameIndex[from->id] = from;
781
782         /* Recurse on the implicit final state and then all children. */
783         if ( from->final != 0 )
784                 fillNameIndex( from->final );
785         for ( NameVect::Iter name = from->childVect; name.lte(); name++ )
786                 fillNameIndex( *name );
787 }
788
789 void ParseData::makeRootNames()
790 {
791         /* Create the root name. */
792         rootName = new NameInst( InputLoc(), 0, 0, nextNameId++, false );
793         exportsRootName = new NameInst( InputLoc(), 0, 0, nextNameId++, false );
794 }
795
796 /* Build the name tree and supporting data structures. */
797 void ParseData::makeNameTree( GraphDictEl *dictEl )
798 {
799         /* Set up curNameInst for the walk. */
800         initNameWalk();
801
802         if ( dictEl != 0 ) {
803                 /* A start location has been specified. */
804                 dictEl->value->makeNameTree( dictEl->loc, this );
805         }
806         else {
807                 /* First make the name tree. */
808                 for ( GraphList::Iter glel = instanceList; glel.lte(); glel++ ) {
809                         /* Recurse on the instance. */
810                         glel->value->makeNameTree( glel->loc, this );
811                 }
812         }
813         
814         /* The number of nodes in the tree can now be given by nextNameId */
815         nameIndex = new NameInst*[nextNameId];
816         memset( nameIndex, 0, sizeof(NameInst*)*nextNameId );
817         fillNameIndex( rootName );
818         fillNameIndex( exportsRootName );
819 }
820
821
822 void ParseData::createBuiltin( const char *name, BuiltinMachine builtin )
823 {
824         Expression *expression = new Expression( builtin );
825         Join *join = new Join( expression );
826         JoinOrLm *joinOrLm = new JoinOrLm( join );
827         VarDef *varDef = new VarDef( name, joinOrLm );
828         GraphDictEl *graphDictEl = new GraphDictEl( name, varDef );
829         graphDict.insert( graphDictEl );
830 }
831
832 /* Initialize the graph dict with builtin types. */
833 void ParseData::initGraphDict( )
834 {
835         createBuiltin( "any", BT_Any );
836         createBuiltin( "ascii", BT_Ascii );
837         createBuiltin( "extend", BT_Extend );
838         createBuiltin( "alpha", BT_Alpha );
839         createBuiltin( "digit", BT_Digit );
840         createBuiltin( "alnum", BT_Alnum );
841         createBuiltin( "lower", BT_Lower );
842         createBuiltin( "upper", BT_Upper );
843         createBuiltin( "cntrl", BT_Cntrl );
844         createBuiltin( "graph", BT_Graph );
845         createBuiltin( "print", BT_Print );
846         createBuiltin( "punct", BT_Punct );
847         createBuiltin( "space", BT_Space );
848         createBuiltin( "xdigit", BT_Xdigit );
849         createBuiltin( "null", BT_Lambda );
850         createBuiltin( "zlen", BT_Lambda );
851         createBuiltin( "empty", BT_Empty );
852 }
853
854 /* Set the alphabet type. If the types are not valid returns false. */
855 bool ParseData::setAlphType( const InputLoc &loc, char *s1, char *s2 )
856 {
857         alphTypeLoc = loc;
858         userAlphType = findAlphType( s1, s2 );
859         alphTypeSet = true;
860         return userAlphType != 0;
861 }
862
863 /* Set the alphabet type. If the types are not valid returns false. */
864 bool ParseData::setAlphType( const InputLoc &loc, char *s1 )
865 {
866         alphTypeLoc = loc;
867         userAlphType = findAlphType( s1 );
868         alphTypeSet = true;
869         return userAlphType != 0;
870 }
871
872 bool ParseData::setVariable( char *var, InlineList *inlineList )
873 {
874         bool set = true;
875
876         if ( strcmp( var, "p" ) == 0 )
877                 pExpr = inlineList;
878         else if ( strcmp( var, "pe" ) == 0 )
879                 peExpr = inlineList;
880         else if ( strcmp( var, "eof" ) == 0 )
881                 eofExpr = inlineList;
882         else if ( strcmp( var, "cs" ) == 0 )
883                 csExpr = inlineList;
884         else if ( strcmp( var, "data" ) == 0 )
885                 dataExpr = inlineList;
886         else if ( strcmp( var, "top" ) == 0 )
887                 topExpr = inlineList;
888         else if ( strcmp( var, "stack" ) == 0 )
889                 stackExpr = inlineList;
890         else if ( strcmp( var, "act" ) == 0 )
891                 actExpr = inlineList;
892         else if ( strcmp( var, "ts" ) == 0 )
893                 tokstartExpr = inlineList;
894         else if ( strcmp( var, "te" ) == 0 )
895                 tokendExpr = inlineList;
896         else
897                 set = false;
898
899         return set;
900 }
901
902 /* Initialize the key operators object that will be referenced by all fsms
903  * created. */
904 void ParseData::initKeyOps( )
905 {
906         /* Signedness and bounds. */
907         HostType *alphType = alphTypeSet ? userAlphType : hostLang->defaultAlphType;
908         thisKeyOps.setAlphType( alphType );
909
910         if ( lowerNum != 0 ) {
911                 /* If ranges are given then interpret the alphabet type. */
912                 thisKeyOps.minKey = makeFsmKeyNum( lowerNum, rangeLowLoc, this );
913                 thisKeyOps.maxKey = makeFsmKeyNum( upperNum, rangeHighLoc, this );
914         }
915
916         thisCondData.lastCondKey = thisKeyOps.maxKey;
917 }
918
919 void ParseData::printNameInst( NameInst *nameInst, int level )
920 {
921         for ( int i = 0; i < level; i++ )
922                 cerr << "  ";
923         cerr << (nameInst->name != 0 ? nameInst->name : "<ANON>") << 
924                         "  id: " << nameInst->id << 
925                         "  refs: " << nameInst->numRefs <<
926                         "  uses: " << nameInst->numUses << endl;
927         for ( NameVect::Iter name = nameInst->childVect; name.lte(); name++ )
928                 printNameInst( *name, level+1 );
929 }
930
931 /* Remove duplicates of unique actions from an action table. */
932 void ParseData::removeDups( ActionTable &table )
933 {
934         /* Scan through the table looking for unique actions to 
935          * remove duplicates of. */
936         for ( int i = 0; i < table.length(); i++ ) {
937                 /* Remove any duplicates ahead of i. */
938                 for ( int r = i+1; r < table.length(); ) {
939                         if ( table[r].value == table[i].value )
940                                 table.vremove(r);
941                         else
942                                 r += 1;
943                 }
944         }
945 }
946
947 /* Remove duplicates from action lists. This operates only on transition and
948  * eof action lists and so should be called once all actions have been
949  * transfered to their final resting place. */
950 void ParseData::removeActionDups( FsmAp *graph )
951 {
952         /* Loop all states. */
953         for ( StateList::Iter state = graph->stateList; state.lte(); state++ ) {
954                 /* Loop all transitions. */
955                 for ( TransList::Iter trans = state->outList; trans.lte(); trans++ )
956                         removeDups( trans->actionTable );
957                 removeDups( state->toStateActionTable );
958                 removeDups( state->fromStateActionTable );
959                 removeDups( state->eofActionTable );
960         }
961 }
962
963 Action *ParseData::newAction( const char *name, InlineList *inlineList )
964 {
965         InputLoc loc;
966         loc.line = 1;
967         loc.col = 1;
968         loc.fileName = "<NONE>";
969
970         Action *action = new Action( loc, name, inlineList, nextCondId++ );
971         action->actionRefs.append( rootName );
972         actionList.append( action );
973         return action;
974 }
975
976 void ParseData::initLongestMatchData()
977 {
978         if ( lmList.length() > 0 ) {
979                 /* The initTokStart action resets the token start. */
980                 InlineList *il1 = new InlineList;
981                 il1->append( new InlineItem( InputLoc(), InlineItem::LmInitTokStart ) );
982                 initTokStart = newAction( "initts", il1 );
983                 initTokStart->isLmAction = true;
984
985                 /* The initActId action gives act a default value. */
986                 InlineList *il4 = new InlineList;
987                 il4->append( new InlineItem( InputLoc(), InlineItem::LmInitAct ) );
988                 initActId = newAction( "initact", il4 );
989                 initActId->isLmAction = true;
990
991                 /* The setTokStart action sets tokstart. */
992                 InlineList *il5 = new InlineList;
993                 il5->append( new InlineItem( InputLoc(), InlineItem::LmSetTokStart ) );
994                 setTokStart = newAction( "ts", il5 );
995                 setTokStart->isLmAction = true;
996
997                 /* The setTokEnd action sets tokend. */
998                 InlineList *il3 = new InlineList;
999                 il3->append( new InlineItem( InputLoc(), InlineItem::LmSetTokEnd ) );
1000                 setTokEnd = newAction( "te", il3 );
1001                 setTokEnd->isLmAction = true;
1002
1003                 /* The action will also need an ordering: ahead of all user action
1004                  * embeddings. */
1005                 initTokStartOrd = curActionOrd++;
1006                 initActIdOrd = curActionOrd++;
1007                 setTokStartOrd = curActionOrd++;
1008                 setTokEndOrd = curActionOrd++;
1009         }
1010 }
1011
1012 /* After building the graph, do some extra processing to ensure the runtime
1013  * data of the longest mactch operators is consistent. */
1014 void ParseData::setLongestMatchData( FsmAp *graph )
1015 {
1016         if ( lmList.length() > 0 ) {
1017                 /* Make sure all entry points (targets of fgoto, fcall, fnext, fentry)
1018                  * init the tokstart. */
1019                 for ( EntryMap::Iter en = graph->entryPoints; en.lte(); en++ ) {
1020                         /* This is run after duplicates are removed, we must guard against
1021                          * inserting a duplicate. */
1022                         ActionTable &actionTable = en->value->toStateActionTable;
1023                         if ( ! actionTable.hasAction( initTokStart ) )
1024                                 actionTable.setAction( initTokStartOrd, initTokStart );
1025                 }
1026
1027                 /* Find the set of states that are the target of transitions with
1028                  * actions that have calls. These states will be targeted by fret
1029                  * statements. */
1030                 StateSet states;
1031                 for ( StateList::Iter state = graph->stateList; state.lte(); state++ ) {
1032                         for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) {
1033                                 for ( ActionTable::Iter ati = trans->actionTable; ati.lte(); ati++ ) {
1034                                         if ( ati->value->anyCall && trans->toState != 0 )
1035                                                 states.insert( trans->toState );
1036                                 }
1037                         }
1038                 }
1039
1040
1041                 /* Init tokstart upon entering the above collected states. */
1042                 for ( StateSet::Iter ps = states; ps.lte(); ps++ ) {
1043                         /* This is run after duplicates are removed, we must guard against
1044                          * inserting a duplicate. */
1045                         ActionTable &actionTable = (*ps)->toStateActionTable;
1046                         if ( ! actionTable.hasAction( initTokStart ) )
1047                                 actionTable.setAction( initTokStartOrd, initTokStart );
1048                 }
1049         }
1050 }
1051
1052 /* Make the graph from a graph dict node. Does minimization and state sorting. */
1053 FsmAp *ParseData::makeInstance( GraphDictEl *gdNode )
1054 {
1055         /* Build the graph from a walk of the parse tree. */
1056         FsmAp *graph = gdNode->value->walk( this );
1057
1058         /* Resolve any labels that point to multiple states. Any labels that are
1059          * still around are referenced only by gotos and calls and they need to be
1060          * made into deterministic entry points. */
1061         graph->deterministicEntry();
1062
1063         /*
1064          * All state construction is now complete.
1065          */
1066
1067         /* Transfer actions from the out action tables to eof action tables. */
1068         for ( StateSet::Iter state = graph->finStateSet; state.lte(); state++ )
1069                 graph->transferOutActions( *state );
1070
1071         /* Transfer global error actions. */
1072         for ( StateList::Iter state = graph->stateList; state.lte(); state++ )
1073                 graph->transferErrorActions( state, 0 );
1074         
1075         if ( ::wantDupsRemoved )
1076                 removeActionDups( graph );
1077
1078         /* Remove unreachable states. There should be no dead end states. The
1079          * subtract and intersection operators are the only places where they may
1080          * be created and those operators clean them up. */
1081         graph->removeUnreachableStates();
1082
1083         /* No more fsm operations are to be done. Action ordering numbers are
1084          * no longer of use and will just hinder minimization. Clear them. */
1085         graph->nullActionKeys();
1086
1087         /* Transition priorities are no longer of use. We can clear them
1088          * because they will just hinder minimization as well. Clear them. */
1089         graph->clearAllPriorities();
1090
1091         if ( minimizeOpt != MinimizeNone ) {
1092                 /* Minimize here even if we minimized at every op. Now that function
1093                  * keys have been cleared we may get a more minimal fsm. */
1094                 switch ( minimizeLevel ) {
1095                         case MinimizeApprox:
1096                                 graph->minimizeApproximate();
1097                                 break;
1098                         case MinimizeStable:
1099                                 graph->minimizeStable();
1100                                 break;
1101                         case MinimizePartition1:
1102                                 graph->minimizePartition1();
1103                                 break;
1104                         case MinimizePartition2:
1105                                 graph->minimizePartition2();
1106                                 break;
1107                 }
1108         }
1109
1110         graph->compressTransitions();
1111
1112         return graph;
1113 }
1114
1115 void ParseData::printNameTree()
1116 {
1117         /* Print the name instance map. */
1118         for ( NameVect::Iter name = rootName->childVect; name.lte(); name++ )
1119                 printNameInst( *name, 0 );
1120         
1121         cerr << "name index:" << endl;
1122         /* Show that the name index is correct. */
1123         for ( int ni = 0; ni < nextNameId; ni++ ) {
1124                 cerr << ni << ": ";
1125                 const char *name = nameIndex[ni]->name;
1126                 cerr << ( name != 0 ? name : "<ANON>" ) << endl;
1127         }
1128 }
1129
1130 FsmAp *ParseData::makeSpecific( GraphDictEl *gdNode )
1131 {
1132         /* Build the name tree and supporting data structures. */
1133         makeNameTree( gdNode );
1134
1135         /* Resove name references from gdNode. */
1136         initNameWalk();
1137         gdNode->value->resolveNameRefs( this );
1138
1139         /* Do not resolve action references. Since we are not building the entire
1140          * graph there's a good chance that many name references will fail. This
1141          * is okay since generating part of the graph is usually only done when
1142          * inspecting the compiled machine. */
1143
1144         /* Same story for extern entry point references. */
1145
1146         /* Flag this case so that the XML code generator is aware that we haven't
1147          * looked up name references in actions. It can then avoid segfaulting. */
1148         generatingSectionSubset = true;
1149
1150         /* Just building the specified graph. */
1151         initNameWalk();
1152         FsmAp *mainGraph = makeInstance( gdNode );
1153
1154         return mainGraph;
1155 }
1156
1157 FsmAp *ParseData::makeAll()
1158 {
1159         /* Build the name tree and supporting data structures. */
1160         makeNameTree( 0 );
1161
1162         /* Resove name references in the tree. */
1163         initNameWalk();
1164         for ( GraphList::Iter glel = instanceList; glel.lte(); glel++ )
1165                 glel->value->resolveNameRefs( this );
1166
1167         /* Resolve action code name references. */
1168         resolveActionNameRefs();
1169
1170         /* Force name references to the top level instantiations. */
1171         for ( NameVect::Iter inst = rootName->childVect; inst.lte(); inst++ )
1172                 (*inst)->numRefs += 1;
1173
1174         FsmAp *mainGraph = 0;
1175         FsmAp **graphs = new FsmAp*[instanceList.length()];
1176         int numOthers = 0;
1177
1178         /* Make all the instantiations, we know that main exists in this list. */
1179         initNameWalk();
1180         for ( GraphList::Iter glel = instanceList; glel.lte();  glel++ ) {
1181                 if ( strcmp( glel->key, mainMachine ) == 0 ) {
1182                         /* Main graph is always instantiated. */
1183                         mainGraph = makeInstance( glel );
1184                 }
1185                 else {
1186                         /* Instantiate and store in others array. */
1187                         graphs[numOthers++] = makeInstance( glel );
1188                 }
1189         }
1190
1191         if ( mainGraph == 0 )
1192                 mainGraph = graphs[--numOthers];
1193
1194         if ( numOthers > 0 ) {
1195                 /* Add all the other graphs into main. */
1196                 mainGraph->globOp( graphs, numOthers );
1197         }
1198
1199         delete[] graphs;
1200         return mainGraph;
1201 }
1202
1203 void ParseData::analyzeAction( Action *action, InlineList *inlineList )
1204 {
1205         /* FIXME: Actions used as conditions should be very constrained. */
1206         for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
1207                 if ( item->type == InlineItem::Call || item->type == InlineItem::CallExpr )
1208                         action->anyCall = true;
1209
1210                 /* Need to recurse into longest match items. */
1211                 if ( item->type == InlineItem::LmSwitch ) {
1212                         LongestMatch *lm = item->longestMatch;
1213                         for ( LmPartList::Iter lmi = *lm->longestMatchList; lmi.lte(); lmi++ ) {
1214                                 if ( lmi->action != 0 )
1215                                         analyzeAction( action, lmi->action->inlineList );
1216                         }
1217                 }
1218
1219                 if ( item->type == InlineItem::LmOnLast || 
1220                                 item->type == InlineItem::LmOnNext ||
1221                                 item->type == InlineItem::LmOnLagBehind )
1222                 {
1223                         LongestMatchPart *lmi = item->longestMatchPart;
1224                         if ( lmi->action != 0 )
1225                                 analyzeAction( action, lmi->action->inlineList );
1226                 }
1227
1228                 if ( item->children != 0 )
1229                         analyzeAction( action, item->children );
1230         }
1231 }
1232
1233
1234 /* Check actions for bad uses of fsm directives. We don't go inside longest
1235  * match items in actions created by ragel, since we just want the user
1236  * actions. */
1237 void ParseData::checkInlineList( Action *act, InlineList *inlineList )
1238 {
1239         for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
1240                 /* EOF checks. */
1241                 if ( act->numEofRefs > 0 ) {
1242                         switch ( item->type ) {
1243                                 /* Currently no checks. */
1244                                 default:
1245                                         break;
1246                         }
1247                 }
1248
1249                 /* Recurse. */
1250                 if ( item->children != 0 )
1251                         checkInlineList( act, item->children );
1252         }
1253 }
1254
1255 void ParseData::checkAction( Action *action )
1256 {
1257         /* Check for actions with calls that are embedded within a longest match
1258          * machine. */
1259         if ( !action->isLmAction && action->numRefs() > 0 && action->anyCall ) {
1260                 for ( ActionRefs::Iter ar = action->actionRefs; ar.lte(); ar++ ) {
1261                         NameInst *check = *ar;
1262                         while ( check != 0 ) {
1263                                 if ( check->isLongestMatch ) {
1264                                         error(action->loc) << "within a scanner, fcall is permitted"
1265                                                 " only in pattern actions" << endl;
1266                                         break;
1267                                 }
1268                                 check = check->parent;
1269                         }
1270                 }
1271         }
1272
1273         checkInlineList( action, action->inlineList );
1274 }
1275
1276
1277 void ParseData::analyzeGraph( FsmAp *graph )
1278 {
1279         for ( ActionList::Iter act = actionList; act.lte(); act++ )
1280                 analyzeAction( act, act->inlineList );
1281
1282         for ( StateList::Iter st = graph->stateList; st.lte(); st++ ) {
1283                 /* The transition list. */
1284                 for ( TransList::Iter trans = st->outList; trans.lte(); trans++ ) {
1285                         for ( ActionTable::Iter at = trans->actionTable; at.lte(); at++ )
1286                                 at->value->numTransRefs += 1;
1287                 }
1288
1289                 for ( ActionTable::Iter at = st->toStateActionTable; at.lte(); at++ )
1290                         at->value->numToStateRefs += 1;
1291
1292                 for ( ActionTable::Iter at = st->fromStateActionTable; at.lte(); at++ )
1293                         at->value->numFromStateRefs += 1;
1294
1295                 for ( ActionTable::Iter at = st->eofActionTable; at.lte(); at++ )
1296                         at->value->numEofRefs += 1;
1297
1298                 for ( StateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
1299                         for ( CondSet::Iter sci = sc->condSpace->condSet; sci.lte(); sci++ )
1300                                 (*sci)->numCondRefs += 1;
1301                 }
1302         }
1303
1304         /* Checks for bad usage of directives in action code. */
1305         for ( ActionList::Iter act = actionList; act.lte(); act++ )
1306                 checkAction( act );
1307 }
1308
1309 void ParseData::makeExportsNameTree()
1310 {
1311         /* Make a name tree for the exports. */
1312         initExportsNameWalk();
1313
1314         /* First make the name tree. */
1315         for ( GraphDict::Iter gdel = graphDict; gdel.lte(); gdel++ ) {
1316                 if ( gdel->value->isExport ) {
1317                         /* Recurse on the instance. */
1318                         gdel->value->makeNameTree( gdel->loc, this );
1319                 }
1320         }
1321 }
1322
1323 void ParseData::makeExports()
1324 {
1325         makeExportsNameTree();
1326
1327         /* Resove name references in the tree. */
1328         initExportsNameWalk();
1329         for ( GraphDict::Iter gdel = graphDict; gdel.lte(); gdel++ ) {
1330                 if ( gdel->value->isExport )
1331                         gdel->value->resolveNameRefs( this );
1332         }
1333
1334         /* Make all the instantiations, we know that main exists in this list. */
1335         initExportsNameWalk();
1336         for ( GraphDict::Iter gdel = graphDict; gdel.lte();  gdel++ ) {
1337                 /* Check if this var def is an export. */
1338                 if ( gdel->value->isExport ) {
1339                         /* Build the graph from a walk of the parse tree. */
1340                         FsmAp *graph = gdel->value->walk( this );
1341
1342                         /* Build the graph from a walk of the parse tree. */
1343                         if ( !graph->checkSingleCharMachine() ) {
1344                                 error(gdel->loc) << "bad export machine, must define "
1345                                                 "a single character" << endl;
1346                         }
1347                         else {
1348                                 /* Safe to extract the key and declare the export. */
1349                                 Key exportKey = graph->startState->outList.head->lowKey;
1350                                 exportList.append( new Export( gdel->value->name, exportKey ) );
1351                         }
1352                 }
1353         }
1354
1355 }
1356
1357 /* Construct the machine and catch failures which can occur during
1358  * construction. */
1359 void ParseData::prepareMachineGen( GraphDictEl *graphDictEl )
1360 {
1361         try {
1362                 /* This machine construction can fail. */
1363                 prepareMachineGenTBWrapped( graphDictEl );
1364         }
1365         catch ( FsmConstructFail fail ) {
1366                 switch ( fail.reason ) {
1367                         case FsmConstructFail::CondNoKeySpace: {
1368                                 InputLoc &loc = alphTypeSet ? alphTypeLoc : sectionLoc;
1369                                 error(loc) << "sorry, no more characters are "
1370                                                 "available in the alphabet space" << endl;
1371                                 error(loc) << "  for conditions, please use a "
1372                                                 "smaller alphtype or reduce" << endl;
1373                                 error(loc) << "  the span of characters on which "
1374                                                 "conditions are embedded" << endl;
1375                                 break;
1376                         }
1377                 }
1378         }
1379 }
1380
1381 void ParseData::prepareMachineGenTBWrapped( GraphDictEl *graphDictEl )
1382 {
1383         beginProcessing();
1384         initKeyOps();
1385         makeRootNames();
1386         initLongestMatchData();
1387
1388         /* Make the graph, do minimization. */
1389         if ( graphDictEl == 0 )
1390                 sectionGraph = makeAll();
1391         else
1392                 sectionGraph = makeSpecific( graphDictEl );
1393         
1394         /* Compute exports from the export definitions. */
1395         makeExports();
1396
1397         /* If any errors have occured in the input file then don't write anything. */
1398         if ( gblErrorCount > 0 )
1399                 return;
1400
1401         analyzeGraph( sectionGraph );
1402
1403         /* Depends on the graph analysis. */
1404         setLongestMatchData( sectionGraph );
1405
1406         /* Decide if an error state is necessary.
1407          *  1. There is an error transition
1408          *  2. There is a gap in the transitions
1409          *  3. The longest match operator requires it. */
1410         if ( lmRequiresErrorState || sectionGraph->hasErrorTrans() )
1411                 sectionGraph->errState = sectionGraph->addState();
1412
1413         /* State numbers need to be assigned such that all final states have a
1414          * larger state id number than all non-final states. This enables the
1415          * first_final mechanism to function correctly. We also want states to be
1416          * ordered in a predictable fashion. So we first apply a depth-first
1417          * search, then do a stable sort by final state status, then assign
1418          * numbers. */
1419
1420         sectionGraph->depthFirstOrdering();
1421         sectionGraph->sortStatesByFinal();
1422         sectionGraph->setStateNumbers( 0 );
1423 }
1424
1425 void ParseData::generateXML( ostream &out )
1426 {
1427         beginProcessing();
1428
1429         /* Make the generator. */
1430         XMLCodeGen codeGen( sectionName, this, sectionGraph, out );
1431
1432         /* Write out with it. */
1433         codeGen.writeXML();
1434
1435         if ( printStatistics ) {
1436                 cerr << "fsm name  : " << sectionName << endl;
1437                 cerr << "num states: " << sectionGraph->stateList.length() << endl;
1438                 cerr << endl;
1439         }
1440 }
1441
1442 /* Send eof to all parsers. */
1443 void terminateAllParsers( )
1444 {
1445         /* FIXME: a proper token is needed here. Suppose we should use the
1446          * location of EOF in the last file that the parser was referenced in. */
1447         InputLoc loc;
1448         loc.fileName = "<EOF>";
1449         loc.line = 0;
1450         loc.col = 0;
1451         for ( ParserDict::Iter pdel = parserDict; pdel.lte(); pdel++ )
1452                 pdel->value->token( loc, _eof, 0, 0 );
1453 }
1454
1455 void writeLanguage( std::ostream &out )
1456 {
1457         out << " lang=\"";
1458         switch ( hostLang->lang ) {
1459                 case HostLang::C:    out << "C"; break;
1460                 case HostLang::D:    out << "D"; break;
1461                 case HostLang::Java: out << "Java"; break;
1462                 case HostLang::Ruby: out << "Ruby"; break;
1463                 case HostLang::CSharp: out << "C#"; break;
1464         }
1465         out << "\"";
1466         
1467 }
1468
1469 void writeMachines( std::ostream &out, std::string hostData, char *inputFileName )
1470 {
1471         if ( machineSpec == 0 && machineName == 0 ) {
1472                 /* No machine spec or machine name given. Generate everything. */
1473                 for ( ParserDict::Iter parser = parserDict; parser.lte(); parser++ ) {
1474                         ParseData *pd = parser->value->pd;
1475                         if ( pd->instanceList.length() > 0 )
1476                                 pd->prepareMachineGen( 0 );
1477                 }
1478
1479                 if ( gblErrorCount == 0 ) {
1480                         out << "<ragel version=\"" VERSION "\" filename=\"" << inputFileName << "\"";
1481                         writeLanguage( out );
1482                         out << ">\n";
1483                         for ( ParserDict::Iter parser = parserDict; parser.lte(); parser++ ) {
1484                                 ParseData *pd = parser->value->pd;
1485                                 if ( pd->instanceList.length() > 0 )
1486                                         pd->generateXML( out );
1487                         }
1488                         out << hostData;
1489                         out << "</ragel>\n";
1490                 }
1491         }
1492         else if ( parserDict.length() > 0 ) {
1493                 /* There is either a machine spec or machine name given. */
1494                 ParseData *parseData = 0;
1495                 GraphDictEl *graphDictEl = 0;
1496
1497                 /* Traverse the sections, break out when we find a section/machine
1498                  * that matches the one specified. */
1499                 for ( ParserDict::Iter parser = parserDict; parser.lte(); parser++ ) {
1500                         ParseData *checkPd = parser->value->pd;
1501                         if ( machineSpec == 0 || strcmp( checkPd->sectionName, machineSpec ) == 0 ) {
1502                                 GraphDictEl *checkGdEl = 0;
1503                                 if ( machineName == 0 || (checkGdEl = 
1504                                                 checkPd->graphDict.find( machineName )) != 0 )
1505                                 {
1506                                         /* Have a machine spec and/or machine name that matches
1507                                          * the -M/-S options. */
1508                                         parseData = checkPd;
1509                                         graphDictEl = checkGdEl;
1510                                         break;
1511                                 }
1512                         }
1513                 }
1514
1515                 if ( parseData == 0 )
1516                         error() << "could not locate machine specified with -S and/or -M" << endl;
1517                 else {
1518                         /* Section/Machine to emit was found. Prepare and emit it. */
1519                         parseData->prepareMachineGen( graphDictEl );
1520                         if ( gblErrorCount == 0 ) {
1521                                 out << "<ragel version=\"" VERSION "\" filename=\"" << inputFileName << "\"";
1522                                 writeLanguage( out );
1523                                 out << ">\n";
1524                                 parseData->generateXML( out );
1525                                 out << hostData;
1526                                 out << "</ragel>\n";
1527                         }
1528                 }
1529         }
1530 }