More warning elimination.
[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, 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, 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( 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, "tokstart" ) == 0 )
893                 tokstartExpr = inlineList;
894         else if ( strcmp( var, "tokend" ) == 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( 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( "tokstart", 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( "tokend", 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         removeActionDups( graph );
1076
1077         /* Remove unreachable states. There should be no dead end states. The
1078          * subtract and intersection operators are the only places where they may
1079          * be created and those operators clean them up. */
1080         graph->removeUnreachableStates();
1081
1082         /* No more fsm operations are to be done. Action ordering numbers are
1083          * no longer of use and will just hinder minimization. Clear them. */
1084         graph->nullActionKeys();
1085
1086         /* Transition priorities are no longer of use. We can clear them
1087          * because they will just hinder minimization as well. Clear them. */
1088         graph->clearAllPriorities();
1089
1090         if ( minimizeOpt != MinimizeNone ) {
1091                 /* Minimize here even if we minimized at every op. Now that function
1092                  * keys have been cleared we may get a more minimal fsm. */
1093                 switch ( minimizeLevel ) {
1094                         case MinimizeApprox:
1095                                 graph->minimizeApproximate();
1096                                 break;
1097                         case MinimizeStable:
1098                                 graph->minimizeStable();
1099                                 break;
1100                         case MinimizePartition1:
1101                                 graph->minimizePartition1();
1102                                 break;
1103                         case MinimizePartition2:
1104                                 graph->minimizePartition2();
1105                                 break;
1106                 }
1107         }
1108
1109         graph->compressTransitions();
1110
1111         return graph;
1112 }
1113
1114 void ParseData::printNameTree()
1115 {
1116         /* Print the name instance map. */
1117         for ( NameVect::Iter name = rootName->childVect; name.lte(); name++ )
1118                 printNameInst( *name, 0 );
1119         
1120         cerr << "name index:" << endl;
1121         /* Show that the name index is correct. */
1122         for ( int ni = 0; ni < nextNameId; ni++ ) {
1123                 cerr << ni << ": ";
1124                 char *name = nameIndex[ni]->name;
1125                 cerr << ( name != 0 ? name : "<ANON>" ) << endl;
1126         }
1127 }
1128
1129 FsmAp *ParseData::makeSpecific( GraphDictEl *gdNode )
1130 {
1131         /* Build the name tree and supporting data structures. */
1132         makeNameTree( gdNode );
1133
1134         /* Resove name references from gdNode. */
1135         initNameWalk();
1136         gdNode->value->resolveNameRefs( this );
1137
1138         /* Do not resolve action references. Since we are not building the entire
1139          * graph there's a good chance that many name references will fail. This
1140          * is okay since generating part of the graph is usually only done when
1141          * inspecting the compiled machine. */
1142
1143         /* Same story for extern entry point references. */
1144
1145         /* Flag this case so that the XML code generator is aware that we haven't
1146          * looked up name references in actions. It can then avoid segfaulting. */
1147         generatingSectionSubset = true;
1148
1149         /* Just building the specified graph. */
1150         initNameWalk();
1151         FsmAp *mainGraph = makeInstance( gdNode );
1152
1153         return mainGraph;
1154 }
1155
1156 FsmAp *ParseData::makeAll()
1157 {
1158         /* Build the name tree and supporting data structures. */
1159         makeNameTree( 0 );
1160
1161         /* Resove name references in the tree. */
1162         initNameWalk();
1163         for ( GraphList::Iter glel = instanceList; glel.lte(); glel++ )
1164                 glel->value->resolveNameRefs( this );
1165
1166         /* Resolve action code name references. */
1167         resolveActionNameRefs();
1168
1169         /* Force name references to the top level instantiations. */
1170         for ( NameVect::Iter inst = rootName->childVect; inst.lte(); inst++ )
1171                 (*inst)->numRefs += 1;
1172
1173         FsmAp *mainGraph = 0;
1174         FsmAp **graphs = new FsmAp*[instanceList.length()];
1175         int numOthers = 0;
1176
1177         /* Make all the instantiations, we know that main exists in this list. */
1178         initNameWalk();
1179         for ( GraphList::Iter glel = instanceList; glel.lte();  glel++ ) {
1180                 if ( strcmp( glel->key, mainMachine ) == 0 ) {
1181                         /* Main graph is always instantiated. */
1182                         mainGraph = makeInstance( glel );
1183                 }
1184                 else {
1185                         /* Instantiate and store in others array. */
1186                         graphs[numOthers++] = makeInstance( glel );
1187                 }
1188         }
1189
1190         if ( mainGraph == 0 )
1191                 mainGraph = graphs[--numOthers];
1192
1193         if ( numOthers > 0 ) {
1194                 /* Add all the other graphs into main. */
1195                 mainGraph->globOp( graphs, numOthers );
1196         }
1197
1198         delete[] graphs;
1199         return mainGraph;
1200 }
1201
1202 void ParseData::analyzeAction( Action *action, InlineList *inlineList )
1203 {
1204         /* FIXME: Actions used as conditions should be very constrained. */
1205         for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
1206                 if ( item->type == InlineItem::Call || item->type == InlineItem::CallExpr )
1207                         action->anyCall = true;
1208
1209                 /* Need to recurse into longest match items. */
1210                 if ( item->type == InlineItem::LmSwitch ) {
1211                         LongestMatch *lm = item->longestMatch;
1212                         for ( LmPartList::Iter lmi = *lm->longestMatchList; lmi.lte(); lmi++ ) {
1213                                 if ( lmi->action != 0 )
1214                                         analyzeAction( action, lmi->action->inlineList );
1215                         }
1216                 }
1217
1218                 if ( item->type == InlineItem::LmOnLast || 
1219                                 item->type == InlineItem::LmOnNext ||
1220                                 item->type == InlineItem::LmOnLagBehind )
1221                 {
1222                         LongestMatchPart *lmi = item->longestMatchPart;
1223                         if ( lmi->action != 0 )
1224                                 analyzeAction( action, lmi->action->inlineList );
1225                 }
1226
1227                 if ( item->children != 0 )
1228                         analyzeAction( action, item->children );
1229         }
1230 }
1231
1232
1233 /* Check actions for bad uses of fsm directives. We don't go inside longest
1234  * match items in actions created by ragel, since we just want the user
1235  * actions. */
1236 void ParseData::checkInlineList( Action *act, InlineList *inlineList )
1237 {
1238         for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
1239                 /* EOF checks. */
1240                 if ( act->numEofRefs > 0 ) {
1241                         switch ( item->type ) {
1242                                 /* Currently no checks. */
1243                                 default:
1244                                         break;
1245                         }
1246                 }
1247
1248                 /* Recurse. */
1249                 if ( item->children != 0 )
1250                         checkInlineList( act, item->children );
1251         }
1252 }
1253
1254 void ParseData::checkAction( Action *action )
1255 {
1256         /* Check for actions with calls that are embedded within a longest match
1257          * machine. */
1258         if ( !action->isLmAction && action->numRefs() > 0 && action->anyCall ) {
1259                 for ( ActionRefs::Iter ar = action->actionRefs; ar.lte(); ar++ ) {
1260                         NameInst *check = *ar;
1261                         while ( check != 0 ) {
1262                                 if ( check->isLongestMatch ) {
1263                                         error(action->loc) << "within a scanner, fcall is permitted"
1264                                                 " only in pattern actions" << endl;
1265                                         break;
1266                                 }
1267                                 check = check->parent;
1268                         }
1269                 }
1270         }
1271
1272         checkInlineList( action, action->inlineList );
1273 }
1274
1275
1276 void ParseData::analyzeGraph( FsmAp *graph )
1277 {
1278         for ( ActionList::Iter act = actionList; act.lte(); act++ )
1279                 analyzeAction( act, act->inlineList );
1280
1281         for ( StateList::Iter st = graph->stateList; st.lte(); st++ ) {
1282                 /* The transition list. */
1283                 for ( TransList::Iter trans = st->outList; trans.lte(); trans++ ) {
1284                         for ( ActionTable::Iter at = trans->actionTable; at.lte(); at++ )
1285                                 at->value->numTransRefs += 1;
1286                 }
1287
1288                 for ( ActionTable::Iter at = st->toStateActionTable; at.lte(); at++ )
1289                         at->value->numToStateRefs += 1;
1290
1291                 for ( ActionTable::Iter at = st->fromStateActionTable; at.lte(); at++ )
1292                         at->value->numFromStateRefs += 1;
1293
1294                 for ( ActionTable::Iter at = st->eofActionTable; at.lte(); at++ )
1295                         at->value->numEofRefs += 1;
1296
1297                 for ( StateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
1298                         for ( CondSet::Iter sci = sc->condSpace->condSet; sci.lte(); sci++ )
1299                                 (*sci)->numCondRefs += 1;
1300                 }
1301         }
1302
1303         /* Checks for bad usage of directives in action code. */
1304         for ( ActionList::Iter act = actionList; act.lte(); act++ )
1305                 checkAction( act );
1306 }
1307
1308 void ParseData::makeExportsNameTree()
1309 {
1310         /* Make a name tree for the exports. */
1311         initExportsNameWalk();
1312
1313         /* First make the name tree. */
1314         for ( GraphDict::Iter gdel = graphDict; gdel.lte(); gdel++ ) {
1315                 if ( gdel->value->isExport ) {
1316                         /* Recurse on the instance. */
1317                         gdel->value->makeNameTree( gdel->loc, this );
1318                 }
1319         }
1320 }
1321
1322 void ParseData::makeExports()
1323 {
1324         makeExportsNameTree();
1325
1326         /* Resove name references in the tree. */
1327         initExportsNameWalk();
1328         for ( GraphDict::Iter gdel = graphDict; gdel.lte(); gdel++ ) {
1329                 if ( gdel->value->isExport )
1330                         gdel->value->resolveNameRefs( this );
1331         }
1332
1333         /* Make all the instantiations, we know that main exists in this list. */
1334         initExportsNameWalk();
1335         for ( GraphDict::Iter gdel = graphDict; gdel.lte();  gdel++ ) {
1336                 /* Check if this var def is an export. */
1337                 if ( gdel->value->isExport ) {
1338                         /* Build the graph from a walk of the parse tree. */
1339                         FsmAp *graph = gdel->value->walk( this );
1340
1341                         /* Build the graph from a walk of the parse tree. */
1342                         if ( !graph->checkSingleCharMachine() ) {
1343                                 error(gdel->loc) << "bad export machine, must define "
1344                                                 "a single character" << endl;
1345                         }
1346                         else {
1347                                 /* Safe to extract the key and declare the export. */
1348                                 Key exportKey = graph->startState->outList.head->lowKey;
1349                                 exportList.append( new Export( gdel->value->name, exportKey ) );
1350                         }
1351                 }
1352         }
1353
1354 }
1355
1356 /* Construct the machine and catch failures which can occur during
1357  * construction. */
1358 void ParseData::prepareMachineGen( GraphDictEl *graphDictEl )
1359 {
1360         try {
1361                 /* This machine construction can fail. */
1362                 prepareMachineGenTBWrapped( graphDictEl );
1363         }
1364         catch ( FsmConstructFail fail ) {
1365                 switch ( fail.reason ) {
1366                         case FsmConstructFail::CondNoKeySpace: {
1367                                 InputLoc &loc = alphTypeSet ? alphTypeLoc : sectionLoc;
1368                                 error(loc) << "sorry, no more characters are "
1369                                                 "available in the alphabet space" << endl;
1370                                 error(loc) << "  for conditions, please use a "
1371                                                 "smaller alphtype or reduce" << endl;
1372                                 error(loc) << "  the span of characters on which "
1373                                                 "conditions are embedded" << endl;
1374                                 break;
1375                         }
1376                 }
1377         }
1378 }
1379
1380 void ParseData::prepareMachineGenTBWrapped( GraphDictEl *graphDictEl )
1381 {
1382         beginProcessing();
1383         initKeyOps();
1384         makeRootNames();
1385         initLongestMatchData();
1386
1387         /* Make the graph, do minimization. */
1388         if ( graphDictEl == 0 )
1389                 sectionGraph = makeAll();
1390         else
1391                 sectionGraph = makeSpecific( graphDictEl );
1392         
1393         /* Compute exports from the export definitions. */
1394         makeExports();
1395
1396         /* If any errors have occured in the input file then don't write anything. */
1397         if ( gblErrorCount > 0 )
1398                 return;
1399
1400         analyzeGraph( sectionGraph );
1401
1402         /* Depends on the graph analysis. */
1403         setLongestMatchData( sectionGraph );
1404
1405         /* Decide if an error state is necessary.
1406          *  1. There is an error transition
1407          *  2. There is a gap in the transitions
1408          *  3. The longest match operator requires it. */
1409         if ( lmRequiresErrorState || sectionGraph->hasErrorTrans() )
1410                 sectionGraph->errState = sectionGraph->addState();
1411
1412         /* State numbers need to be assigned such that all final states have a
1413          * larger state id number than all non-final states. This enables the
1414          * first_final mechanism to function correctly. We also want states to be
1415          * ordered in a predictable fashion. So we first apply a depth-first
1416          * search, then do a stable sort by final state status, then assign
1417          * numbers. */
1418
1419         sectionGraph->depthFirstOrdering();
1420         sectionGraph->sortStatesByFinal();
1421         sectionGraph->setStateNumbers( 0 );
1422 }
1423
1424 void ParseData::generateXML( ostream &out )
1425 {
1426         beginProcessing();
1427
1428         /* Make the generator. */
1429         XMLCodeGen codeGen( sectionName, this, sectionGraph, out );
1430
1431         /* Write out with it. */
1432         codeGen.writeXML();
1433
1434         if ( printStatistics ) {
1435                 cerr << "fsm name  : " << sectionName << endl;
1436                 cerr << "num states: " << sectionGraph->stateList.length() << endl;
1437                 cerr << endl;
1438         }
1439 }
1440
1441 /* Send eof to all parsers. */
1442 void terminateAllParsers( )
1443 {
1444         /* FIXME: a proper token is needed here. Suppose we should use the
1445          * location of EOF in the last file that the parser was referenced in. */
1446         InputLoc loc;
1447         loc.fileName = "<EOF>";
1448         loc.line = 0;
1449         loc.col = 0;
1450         for ( ParserDict::Iter pdel = parserDict; pdel.lte(); pdel++ )
1451                 pdel->value->token( loc, _eof, 0, 0 );
1452 }
1453
1454 void writeLanguage( std::ostream &out )
1455 {
1456         out << " lang=\"";
1457         switch ( hostLang->lang ) {
1458                 case HostLang::C:    out << "C"; break;
1459                 case HostLang::D:    out << "D"; break;
1460                 case HostLang::Java: out << "Java"; break;
1461                 case HostLang::Ruby: out << "Ruby"; break;
1462         }
1463         out << "\"";
1464         
1465 }
1466
1467 void writeMachines( std::ostream &out, std::string hostData, char *inputFileName )
1468 {
1469         if ( machineSpec == 0 && machineName == 0 ) {
1470                 /* No machine spec or machine name given. Generate everything. */
1471                 for ( ParserDict::Iter parser = parserDict; parser.lte(); parser++ ) {
1472                         ParseData *pd = parser->value->pd;
1473                         if ( pd->instanceList.length() > 0 )
1474                                 pd->prepareMachineGen( 0 );
1475                 }
1476
1477                 if ( gblErrorCount == 0 ) {
1478                         out << "<ragel version=\"" VERSION "\" filename=\"" << inputFileName << "\"";
1479                         writeLanguage( out );
1480                         out << ">\n";
1481                         for ( ParserDict::Iter parser = parserDict; parser.lte(); parser++ ) {
1482                                 ParseData *pd = parser->value->pd;
1483                                 if ( pd->instanceList.length() > 0 )
1484                                         pd->generateXML( out );
1485                         }
1486                         out << hostData;
1487                         out << "</ragel>\n";
1488                 }
1489         }
1490         else if ( parserDict.length() > 0 ) {
1491                 /* There is either a machine spec or machine name given. */
1492                 ParseData *parseData = 0;
1493                 GraphDictEl *graphDictEl = 0;
1494
1495                 /* Traverse the sections, break out when we find a section/machine
1496                  * that matches the one specified. */
1497                 for ( ParserDict::Iter parser = parserDict; parser.lte(); parser++ ) {
1498                         ParseData *checkPd = parser->value->pd;
1499                         if ( machineSpec == 0 || strcmp( checkPd->sectionName, machineSpec ) == 0 ) {
1500                                 GraphDictEl *checkGdEl = 0;
1501                                 if ( machineName == 0 || (checkGdEl = 
1502                                                 checkPd->graphDict.find( machineName )) != 0 )
1503                                 {
1504                                         /* Have a machine spec and/or machine name that matches
1505                                          * the -M/-S options. */
1506                                         parseData = checkPd;
1507                                         graphDictEl = checkGdEl;
1508                                         break;
1509                                 }
1510                         }
1511                 }
1512
1513                 if ( parseData == 0 )
1514                         error() << "could not locate machine specified with -S and/or -M" << endl;
1515                 else {
1516                         /* Section/Machine to emit was found. Prepare and emit it. */
1517                         parseData->prepareMachineGen( graphDictEl );
1518                         if ( gblErrorCount == 0 ) {
1519                                 out << "<ragel version=\"" VERSION "\" filename=\"" << inputFileName << "\"";
1520                                 writeLanguage( out );
1521                                 out << ">\n";
1522                                 parseData->generateXML( out );
1523                                 out << hostData;
1524                                 out << "</ragel>\n";
1525                         }
1526                 }
1527         }
1528 }