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