Now supplying the XmlParser to writeMachines.
[ragel.git] / ragel / parsedata.cpp
blob73f52c6d76b8ab69e55cbb44c77915663d1fdbb0
1 /*
2 * Copyright 2001-2006 Adrian Thurston <thurston@cs.queensu.ca>
3 */
5 /* This file is part of Ragel.
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.
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.
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
22 #include <iostream>
23 #include <iomanip>
24 #include <errno.h>
25 #include <stdlib.h>
26 #include <limits.h>
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"
36 using namespace std;
38 char mainMachine[] = "main";
40 void Token::set( const char *str, int len )
42 length = len;
43 data = new char[len+1];
44 memcpy( data, str, len );
45 data[len] = 0;
48 void Token::append( const Token &other )
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;
59 /* Perform minimization after an operation according
60 * to the command line args. */
61 void afterOpMinimize( FsmAp *fsm, bool lastInSeq )
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();
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;
88 /* Count the transitions in the fsm by walking the state list. */
89 int countTransitions( FsmAp *fsm )
91 int numTrans = 0;
92 StateAp *state = fsm->stateList.head;
93 while ( state != 0 ) {
94 numTrans += state->outList.length();
95 state = state->next;
97 return numTrans;
100 Key makeFsmKeyHex( char *str, const InputLoc &loc, ParseData *pd )
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);
109 unsigned long ul = strtoul( str, 0, 16 );
111 if ( errno == ERANGE || ( unusedBits && ul >> (size * 8) ) ) {
112 error(loc) << "literal " << str << " overflows the alphabet type" << endl;
113 ul = 1 << (size * 8);
116 if ( unusedBits && keyOps->alphType->isSigned && ul >> (size * 8 - 1) )
117 ul |= (0xffffffff >> (size*8 ) ) << (size*8);
119 return Key( (long)ul );
122 Key makeFsmKeyDec( char *str, const InputLoc &loc, ParseData *pd )
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;
130 long long ll = strtoll( str, 0, 10 );
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;
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;
143 if ( keyOps->alphType->isSigned )
144 return Key( (long)ll );
145 else
146 return Key( (unsigned long)ll );
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 )
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 );
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 )
166 if ( keyOps->isSigned ) {
167 /* Copy from a char type. */
168 return Key( c );
170 else {
171 /* Copy from an unsigned byte type. */
172 return Key( (unsigned char)c );
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 )
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]);
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]);
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 )
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() );
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() );
231 FsmAp *dotFsm( ParseData *pd )
233 FsmAp *retFsm = new FsmAp();
234 retFsm->rangeFsm( keyOps->minKey, keyOps->maxKey );
235 return retFsm;
238 FsmAp *dotStarFsm( ParseData *pd )
240 FsmAp *retFsm = new FsmAp();
241 retFsm->rangeStarFsm( keyOps->minKey, keyOps->maxKey );
242 return retFsm;
245 /* Make a builtin type. Depends on the signed nature of the alphabet type. */
246 FsmAp *makeBuiltin( BuiltinMachine builtin, ParseData *pd )
248 /* FsmAp created to return. */
249 FsmAp *retFsm = 0;
250 bool isSigned = keyOps->isSigned;
252 switch ( builtin ) {
253 case BT_Any: {
254 /* All characters. */
255 retFsm = dotFsm( pd );
256 break;
258 case BT_Ascii: {
259 /* Ascii characters 0 to 127. */
260 retFsm = new FsmAp();
261 retFsm->rangeFsm( 0, 127 );
262 break;
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 );
272 else {
273 retFsm = new FsmAp();
274 retFsm->rangeFsm( 0, 255 );
276 break;
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;
288 case BT_Digit: {
289 /* Digits [0-9]. */
290 retFsm = new FsmAp();
291 retFsm->rangeFsm( '0', '9' );
292 break;
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;
307 case BT_Lower: {
308 /* Lower case characters. */
309 retFsm = new FsmAp();
310 retFsm->rangeFsm( 'a', 'z' );
311 break;
313 case BT_Upper: {
314 /* Upper case characters. */
315 retFsm = new FsmAp();
316 retFsm->rangeFsm( 'A', 'Z' );
317 break;
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;
330 case BT_Graph: {
331 /* Graphical ascii characters [!-~]. */
332 retFsm = new FsmAp();
333 retFsm->rangeFsm( '!', '~' );
334 break;
336 case BT_Print: {
337 /* Printable characters. Same as graph except includes space. */
338 retFsm = new FsmAp();
339 retFsm->rangeFsm( ' ', '~' );
340 break;
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;
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;
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;
384 case BT_Lambda: {
385 retFsm = new FsmAp();
386 retFsm->lambdaFsm();
387 break;
389 case BT_Empty: {
390 retFsm = new FsmAp();
391 retFsm->emptyFsm();
392 break;
395 return retFsm;
398 /* Check if this name inst or any name inst below is referenced. */
399 bool NameInst::anyRefsRec()
401 if ( numRefs > 0 )
402 return true;
404 /* Recurse on children until true. */
405 for ( NameVect::Iter ch = childVect; ch.lte(); ch++ ) {
406 if ( (*ch)->anyRefsRec() )
407 return true;
410 return false;
414 * ParseData
417 /* Initialize the structure that will collect info during the parse of a
418 * machine. */
419 ParseData::ParseData( const char *fileName, char *sectionName,
420 const InputLoc &sectionLoc )
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)
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();
464 /* Clean up the data collected during a parse. */
465 ParseData::~ParseData()
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();
472 /* Make a name id in the current name instantiation scope if it is not
473 * already there. */
474 NameInst *ParseData::addNameInst( const InputLoc &loc, const char *data, bool isLabel )
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;
484 void ParseData::initNameWalk()
486 curNameInst = rootName;
487 curNameChild = 0;
490 void ParseData::initExportsNameWalk()
492 curNameInst = exportsRootName;
493 curNameChild = 0;
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 )
503 /* Save off the current data. */
504 NameFrame retFrame;
505 retFrame.prevNameInst = curNameInst;
506 retFrame.prevNameChild = curNameChild;
507 retFrame.prevLocalScope = localNameScope;
509 /* Enter into the new name scope. */
510 for ( int i = 0; i < numScopes; i++ ) {
511 curNameInst = curNameInst->childVect[curNameChild];
512 curNameChild = 0;
515 if ( isLocal )
516 localNameScope = curNameInst;
518 return retFrame;
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 )
526 /* Pop the name scope. */
527 curNameInst = frame.prevNameInst;
528 curNameChild = frame.prevNameChild+1;
529 localNameScope = frame.prevLocalScope;
532 void ParseData::resetNameScope( const NameFrame &frame )
534 /* Pop the name scope. */
535 curNameInst = frame.prevNameInst;
536 curNameChild = frame.prevNameChild;
537 localNameScope = frame.prevLocalScope;
541 void ParseData::unsetObsoleteEntries( FsmAp *graph )
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;
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 );
559 NameSet ParseData::resolvePart( NameInst *refFrom, const char *data, bool recLabelsOnly )
561 /* Queue needed for breadth-first search, load it with the start node. */
562 NameInstList nameQueue;
563 nameQueue.append( refFrom );
565 NameSet result;
566 while ( nameQueue.length() > 0 ) {
567 /* Pull the next from location off the queue. */
568 NameInst *from = nameQueue.detachFirst();
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 );
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 );
586 /* Queue exhausted and name never found. */
587 return result;
590 void ParseData::resolveFrom( NameSet &result, NameInst *refFrom,
591 const NameRef &nameRef, int namePos )
593 /* Look for the name in the owning scope of the factor with aug. */
594 NameSet partResult = resolvePart( refFrom, nameRef[namePos], false );
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 );
603 else {
604 /* This is the last component, append the part results to the final
605 * results. */
606 result.insert( partResult );
610 /* Write out a name reference. */
611 ostream &operator<<( ostream &out, const NameRef &nameRef )
613 int pos = 0;
614 if ( nameRef[pos] == 0 ) {
615 out << "::";
616 pos += 1;
618 out << nameRef[pos++];
619 for ( ; pos < nameRef.length(); pos++ )
620 out << "::" << nameRef[pos];
621 return out;
624 ostream &operator<<( ostream &out, const NameInst &nameInst )
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;
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;
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>" );
646 /* Write the name and cleanup. */
647 out << "::" << ( nameInst.name != 0 ? nameInst.name : "<ANON>" );
648 delete[] parents;
649 return out;
652 struct CmpNameInstLoc
654 static int compare( const NameInst *ni1, const NameInst *ni2 )
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;
668 void errorStateLabels( const NameSet &resolved )
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;
677 NameInst *ParseData::resolveStateRef( const NameRef &nameRef, InputLoc &loc, Action *action )
679 NameInst *nameInst = 0;
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 );
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 );
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 );
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 );
722 if ( nameInst == 0 ) {
723 /* If not found then complain. */
724 error(loc) << "could not resolve state reference " << nameRef << endl;
726 return nameInst;
729 void ParseData::resolveNameRefs( InlineList *inlineList, Action *action )
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 );
738 /* Name lookup error reporting is handled by resolveStateRef. */
739 if ( target != 0 ) {
740 /* Check if the target goes into a longest match. */
741 NameInst *search = target->parent;
742 while ( search != 0 ) {
743 if ( search->isLongestMatch ) {
744 error(item->loc) << "cannot enter inside a longest "
745 "match construction as an entry point" << endl;
746 break;
748 search = search->parent;
751 /* Record the reference in the name. This will cause the
752 * entry point to survive to the end of the graph
753 * generating walk. */
754 target->numRefs += 1;
757 item->nameTarg = target;
758 break;
760 default:
761 break;
764 /* Some of the item types may have children. */
765 if ( item->children != 0 )
766 resolveNameRefs( item->children, action );
770 /* Resolve references to labels in actions. */
771 void ParseData::resolveActionNameRefs()
773 for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
774 /* Only care about the actions that are referenced. */
775 if ( act->actionRefs.length() > 0 )
776 resolveNameRefs( act->inlineList, act );
780 /* Walk a name tree starting at from and fill the name index. */
781 void ParseData::fillNameIndex( NameInst *from )
783 /* Fill the value for from in the name index. */
784 nameIndex[from->id] = from;
786 /* Recurse on the implicit final state and then all children. */
787 if ( from->final != 0 )
788 fillNameIndex( from->final );
789 for ( NameVect::Iter name = from->childVect; name.lte(); name++ )
790 fillNameIndex( *name );
793 void ParseData::makeRootNames()
795 /* Create the root name. */
796 rootName = new NameInst( InputLoc(), 0, 0, nextNameId++, false );
797 exportsRootName = new NameInst( InputLoc(), 0, 0, nextNameId++, false );
800 /* Build the name tree and supporting data structures. */
801 void ParseData::makeNameTree( GraphDictEl *dictEl )
803 /* Set up curNameInst for the walk. */
804 initNameWalk();
806 if ( dictEl != 0 ) {
807 /* A start location has been specified. */
808 dictEl->value->makeNameTree( dictEl->loc, this );
810 else {
811 /* First make the name tree. */
812 for ( GraphList::Iter glel = instanceList; glel.lte(); glel++ ) {
813 /* Recurse on the instance. */
814 glel->value->makeNameTree( glel->loc, this );
818 /* The number of nodes in the tree can now be given by nextNameId */
819 nameIndex = new NameInst*[nextNameId];
820 memset( nameIndex, 0, sizeof(NameInst*)*nextNameId );
821 fillNameIndex( rootName );
822 fillNameIndex( exportsRootName );
826 void ParseData::createBuiltin( const char *name, BuiltinMachine builtin )
828 Expression *expression = new Expression( builtin );
829 Join *join = new Join( expression );
830 JoinOrLm *joinOrLm = new JoinOrLm( join );
831 VarDef *varDef = new VarDef( name, joinOrLm );
832 GraphDictEl *graphDictEl = new GraphDictEl( name, varDef );
833 graphDict.insert( graphDictEl );
836 /* Initialize the graph dict with builtin types. */
837 void ParseData::initGraphDict( )
839 createBuiltin( "any", BT_Any );
840 createBuiltin( "ascii", BT_Ascii );
841 createBuiltin( "extend", BT_Extend );
842 createBuiltin( "alpha", BT_Alpha );
843 createBuiltin( "digit", BT_Digit );
844 createBuiltin( "alnum", BT_Alnum );
845 createBuiltin( "lower", BT_Lower );
846 createBuiltin( "upper", BT_Upper );
847 createBuiltin( "cntrl", BT_Cntrl );
848 createBuiltin( "graph", BT_Graph );
849 createBuiltin( "print", BT_Print );
850 createBuiltin( "punct", BT_Punct );
851 createBuiltin( "space", BT_Space );
852 createBuiltin( "xdigit", BT_Xdigit );
853 createBuiltin( "null", BT_Lambda );
854 createBuiltin( "zlen", BT_Lambda );
855 createBuiltin( "empty", BT_Empty );
858 /* Set the alphabet type. If the types are not valid returns false. */
859 bool ParseData::setAlphType( const InputLoc &loc, char *s1, char *s2 )
861 alphTypeLoc = loc;
862 userAlphType = findAlphType( s1, s2 );
863 alphTypeSet = true;
864 return userAlphType != 0;
867 /* Set the alphabet type. If the types are not valid returns false. */
868 bool ParseData::setAlphType( const InputLoc &loc, char *s1 )
870 alphTypeLoc = loc;
871 userAlphType = findAlphType( s1 );
872 alphTypeSet = true;
873 return userAlphType != 0;
876 bool ParseData::setVariable( char *var, InlineList *inlineList )
878 bool set = true;
880 if ( strcmp( var, "p" ) == 0 )
881 pExpr = inlineList;
882 else if ( strcmp( var, "pe" ) == 0 )
883 peExpr = inlineList;
884 else if ( strcmp( var, "eof" ) == 0 )
885 eofExpr = inlineList;
886 else if ( strcmp( var, "cs" ) == 0 )
887 csExpr = inlineList;
888 else if ( strcmp( var, "data" ) == 0 )
889 dataExpr = inlineList;
890 else if ( strcmp( var, "top" ) == 0 )
891 topExpr = inlineList;
892 else if ( strcmp( var, "stack" ) == 0 )
893 stackExpr = inlineList;
894 else if ( strcmp( var, "act" ) == 0 )
895 actExpr = inlineList;
896 else if ( strcmp( var, "ts" ) == 0 )
897 tokstartExpr = inlineList;
898 else if ( strcmp( var, "te" ) == 0 )
899 tokendExpr = inlineList;
900 else
901 set = false;
903 return set;
906 /* Initialize the key operators object that will be referenced by all fsms
907 * created. */
908 void ParseData::initKeyOps( )
910 /* Signedness and bounds. */
911 HostType *alphType = alphTypeSet ? userAlphType : hostLang->defaultAlphType;
912 thisKeyOps.setAlphType( alphType );
914 if ( lowerNum != 0 ) {
915 /* If ranges are given then interpret the alphabet type. */
916 thisKeyOps.minKey = makeFsmKeyNum( lowerNum, rangeLowLoc, this );
917 thisKeyOps.maxKey = makeFsmKeyNum( upperNum, rangeHighLoc, this );
920 thisCondData.lastCondKey = thisKeyOps.maxKey;
923 void ParseData::printNameInst( NameInst *nameInst, int level )
925 for ( int i = 0; i < level; i++ )
926 cerr << " ";
927 cerr << (nameInst->name != 0 ? nameInst->name : "<ANON>") <<
928 " id: " << nameInst->id <<
929 " refs: " << nameInst->numRefs <<
930 " uses: " << nameInst->numUses << endl;
931 for ( NameVect::Iter name = nameInst->childVect; name.lte(); name++ )
932 printNameInst( *name, level+1 );
935 /* Remove duplicates of unique actions from an action table. */
936 void ParseData::removeDups( ActionTable &table )
938 /* Scan through the table looking for unique actions to
939 * remove duplicates of. */
940 for ( int i = 0; i < table.length(); i++ ) {
941 /* Remove any duplicates ahead of i. */
942 for ( int r = i+1; r < table.length(); ) {
943 if ( table[r].value == table[i].value )
944 table.vremove(r);
945 else
946 r += 1;
951 /* Remove duplicates from action lists. This operates only on transition and
952 * eof action lists and so should be called once all actions have been
953 * transfered to their final resting place. */
954 void ParseData::removeActionDups( FsmAp *graph )
956 /* Loop all states. */
957 for ( StateList::Iter state = graph->stateList; state.lte(); state++ ) {
958 /* Loop all transitions. */
959 for ( TransList::Iter trans = state->outList; trans.lte(); trans++ )
960 removeDups( trans->actionTable );
961 removeDups( state->toStateActionTable );
962 removeDups( state->fromStateActionTable );
963 removeDups( state->eofActionTable );
967 Action *ParseData::newAction( const char *name, InlineList *inlineList )
969 InputLoc loc;
970 loc.line = 1;
971 loc.col = 1;
972 loc.fileName = "<NONE>";
974 Action *action = new Action( loc, name, inlineList, nextCondId++ );
975 action->actionRefs.append( rootName );
976 actionList.append( action );
977 return action;
980 void ParseData::initLongestMatchData()
982 if ( lmList.length() > 0 ) {
983 /* The initTokStart action resets the token start. */
984 InlineList *il1 = new InlineList;
985 il1->append( new InlineItem( InputLoc(), InlineItem::LmInitTokStart ) );
986 initTokStart = newAction( "initts", il1 );
987 initTokStart->isLmAction = true;
989 /* The initActId action gives act a default value. */
990 InlineList *il4 = new InlineList;
991 il4->append( new InlineItem( InputLoc(), InlineItem::LmInitAct ) );
992 initActId = newAction( "initact", il4 );
993 initActId->isLmAction = true;
995 /* The setTokStart action sets tokstart. */
996 InlineList *il5 = new InlineList;
997 il5->append( new InlineItem( InputLoc(), InlineItem::LmSetTokStart ) );
998 setTokStart = newAction( "ts", il5 );
999 setTokStart->isLmAction = true;
1001 /* The setTokEnd action sets tokend. */
1002 InlineList *il3 = new InlineList;
1003 il3->append( new InlineItem( InputLoc(), InlineItem::LmSetTokEnd ) );
1004 setTokEnd = newAction( "te", il3 );
1005 setTokEnd->isLmAction = true;
1007 /* The action will also need an ordering: ahead of all user action
1008 * embeddings. */
1009 initTokStartOrd = curActionOrd++;
1010 initActIdOrd = curActionOrd++;
1011 setTokStartOrd = curActionOrd++;
1012 setTokEndOrd = curActionOrd++;
1016 /* After building the graph, do some extra processing to ensure the runtime
1017 * data of the longest mactch operators is consistent. */
1018 void ParseData::setLongestMatchData( FsmAp *graph )
1020 if ( lmList.length() > 0 ) {
1021 /* Make sure all entry points (targets of fgoto, fcall, fnext, fentry)
1022 * init the tokstart. */
1023 for ( EntryMap::Iter en = graph->entryPoints; en.lte(); en++ ) {
1024 /* This is run after duplicates are removed, we must guard against
1025 * inserting a duplicate. */
1026 ActionTable &actionTable = en->value->toStateActionTable;
1027 if ( ! actionTable.hasAction( initTokStart ) )
1028 actionTable.setAction( initTokStartOrd, initTokStart );
1031 /* Find the set of states that are the target of transitions with
1032 * actions that have calls. These states will be targeted by fret
1033 * statements. */
1034 StateSet states;
1035 for ( StateList::Iter state = graph->stateList; state.lte(); state++ ) {
1036 for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) {
1037 for ( ActionTable::Iter ati = trans->actionTable; ati.lte(); ati++ ) {
1038 if ( ati->value->anyCall && trans->toState != 0 )
1039 states.insert( trans->toState );
1045 /* Init tokstart upon entering the above collected states. */
1046 for ( StateSet::Iter ps = states; ps.lte(); ps++ ) {
1047 /* This is run after duplicates are removed, we must guard against
1048 * inserting a duplicate. */
1049 ActionTable &actionTable = (*ps)->toStateActionTable;
1050 if ( ! actionTable.hasAction( initTokStart ) )
1051 actionTable.setAction( initTokStartOrd, initTokStart );
1056 /* Make the graph from a graph dict node. Does minimization and state sorting. */
1057 FsmAp *ParseData::makeInstance( GraphDictEl *gdNode )
1059 /* Build the graph from a walk of the parse tree. */
1060 FsmAp *graph = gdNode->value->walk( this );
1062 /* Resolve any labels that point to multiple states. Any labels that are
1063 * still around are referenced only by gotos and calls and they need to be
1064 * made into deterministic entry points. */
1065 graph->deterministicEntry();
1068 * All state construction is now complete.
1071 /* Transfer actions from the out action tables to eof action tables. */
1072 for ( StateSet::Iter state = graph->finStateSet; state.lte(); state++ )
1073 graph->transferOutActions( *state );
1075 /* Transfer global error actions. */
1076 for ( StateList::Iter state = graph->stateList; state.lte(); state++ )
1077 graph->transferErrorActions( state, 0 );
1079 if ( ::wantDupsRemoved )
1080 removeActionDups( graph );
1082 /* Remove unreachable states. There should be no dead end states. The
1083 * subtract and intersection operators are the only places where they may
1084 * be created and those operators clean them up. */
1085 graph->removeUnreachableStates();
1087 /* No more fsm operations are to be done. Action ordering numbers are
1088 * no longer of use and will just hinder minimization. Clear them. */
1089 graph->nullActionKeys();
1091 /* Transition priorities are no longer of use. We can clear them
1092 * because they will just hinder minimization as well. Clear them. */
1093 graph->clearAllPriorities();
1095 if ( minimizeOpt != MinimizeNone ) {
1096 /* Minimize here even if we minimized at every op. Now that function
1097 * keys have been cleared we may get a more minimal fsm. */
1098 switch ( minimizeLevel ) {
1099 case MinimizeApprox:
1100 graph->minimizeApproximate();
1101 break;
1102 case MinimizeStable:
1103 graph->minimizeStable();
1104 break;
1105 case MinimizePartition1:
1106 graph->minimizePartition1();
1107 break;
1108 case MinimizePartition2:
1109 graph->minimizePartition2();
1110 break;
1114 graph->compressTransitions();
1116 return graph;
1119 void ParseData::printNameTree()
1121 /* Print the name instance map. */
1122 for ( NameVect::Iter name = rootName->childVect; name.lte(); name++ )
1123 printNameInst( *name, 0 );
1125 cerr << "name index:" << endl;
1126 /* Show that the name index is correct. */
1127 for ( int ni = 0; ni < nextNameId; ni++ ) {
1128 cerr << ni << ": ";
1129 const char *name = nameIndex[ni]->name;
1130 cerr << ( name != 0 ? name : "<ANON>" ) << endl;
1134 FsmAp *ParseData::makeSpecific( GraphDictEl *gdNode )
1136 /* Build the name tree and supporting data structures. */
1137 makeNameTree( gdNode );
1139 /* Resove name references from gdNode. */
1140 initNameWalk();
1141 gdNode->value->resolveNameRefs( this );
1143 /* Do not resolve action references. Since we are not building the entire
1144 * graph there's a good chance that many name references will fail. This
1145 * is okay since generating part of the graph is usually only done when
1146 * inspecting the compiled machine. */
1148 /* Same story for extern entry point references. */
1150 /* Flag this case so that the XML code generator is aware that we haven't
1151 * looked up name references in actions. It can then avoid segfaulting. */
1152 generatingSectionSubset = true;
1154 /* Just building the specified graph. */
1155 initNameWalk();
1156 FsmAp *mainGraph = makeInstance( gdNode );
1158 return mainGraph;
1161 FsmAp *ParseData::makeAll()
1163 /* Build the name tree and supporting data structures. */
1164 makeNameTree( 0 );
1166 /* Resove name references in the tree. */
1167 initNameWalk();
1168 for ( GraphList::Iter glel = instanceList; glel.lte(); glel++ )
1169 glel->value->resolveNameRefs( this );
1171 /* Resolve action code name references. */
1172 resolveActionNameRefs();
1174 /* Force name references to the top level instantiations. */
1175 for ( NameVect::Iter inst = rootName->childVect; inst.lte(); inst++ )
1176 (*inst)->numRefs += 1;
1178 FsmAp *mainGraph = 0;
1179 FsmAp **graphs = new FsmAp*[instanceList.length()];
1180 int numOthers = 0;
1182 /* Make all the instantiations, we know that main exists in this list. */
1183 initNameWalk();
1184 for ( GraphList::Iter glel = instanceList; glel.lte(); glel++ ) {
1185 if ( strcmp( glel->key, mainMachine ) == 0 ) {
1186 /* Main graph is always instantiated. */
1187 mainGraph = makeInstance( glel );
1189 else {
1190 /* Instantiate and store in others array. */
1191 graphs[numOthers++] = makeInstance( glel );
1195 if ( mainGraph == 0 )
1196 mainGraph = graphs[--numOthers];
1198 if ( numOthers > 0 ) {
1199 /* Add all the other graphs into main. */
1200 mainGraph->globOp( graphs, numOthers );
1203 delete[] graphs;
1204 return mainGraph;
1207 void ParseData::analyzeAction( Action *action, InlineList *inlineList )
1209 /* FIXME: Actions used as conditions should be very constrained. */
1210 for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
1211 if ( item->type == InlineItem::Call || item->type == InlineItem::CallExpr )
1212 action->anyCall = true;
1214 /* Need to recurse into longest match items. */
1215 if ( item->type == InlineItem::LmSwitch ) {
1216 LongestMatch *lm = item->longestMatch;
1217 for ( LmPartList::Iter lmi = *lm->longestMatchList; lmi.lte(); lmi++ ) {
1218 if ( lmi->action != 0 )
1219 analyzeAction( action, lmi->action->inlineList );
1223 if ( item->type == InlineItem::LmOnLast ||
1224 item->type == InlineItem::LmOnNext ||
1225 item->type == InlineItem::LmOnLagBehind )
1227 LongestMatchPart *lmi = item->longestMatchPart;
1228 if ( lmi->action != 0 )
1229 analyzeAction( action, lmi->action->inlineList );
1232 if ( item->children != 0 )
1233 analyzeAction( action, item->children );
1238 /* Check actions for bad uses of fsm directives. We don't go inside longest
1239 * match items in actions created by ragel, since we just want the user
1240 * actions. */
1241 void ParseData::checkInlineList( Action *act, InlineList *inlineList )
1243 for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
1244 /* EOF checks. */
1245 if ( act->numEofRefs > 0 ) {
1246 switch ( item->type ) {
1247 /* Currently no checks. */
1248 default:
1249 break;
1253 /* Recurse. */
1254 if ( item->children != 0 )
1255 checkInlineList( act, item->children );
1259 void ParseData::checkAction( Action *action )
1261 /* Check for actions with calls that are embedded within a longest match
1262 * machine. */
1263 if ( !action->isLmAction && action->numRefs() > 0 && action->anyCall ) {
1264 for ( ActionRefs::Iter ar = action->actionRefs; ar.lte(); ar++ ) {
1265 NameInst *check = *ar;
1266 while ( check != 0 ) {
1267 if ( check->isLongestMatch ) {
1268 error(action->loc) << "within a scanner, fcall is permitted"
1269 " only in pattern actions" << endl;
1270 break;
1272 check = check->parent;
1277 checkInlineList( action, action->inlineList );
1281 void ParseData::analyzeGraph( FsmAp *graph )
1283 for ( ActionList::Iter act = actionList; act.lte(); act++ )
1284 analyzeAction( act, act->inlineList );
1286 for ( StateList::Iter st = graph->stateList; st.lte(); st++ ) {
1287 /* The transition list. */
1288 for ( TransList::Iter trans = st->outList; trans.lte(); trans++ ) {
1289 for ( ActionTable::Iter at = trans->actionTable; at.lte(); at++ )
1290 at->value->numTransRefs += 1;
1293 for ( ActionTable::Iter at = st->toStateActionTable; at.lte(); at++ )
1294 at->value->numToStateRefs += 1;
1296 for ( ActionTable::Iter at = st->fromStateActionTable; at.lte(); at++ )
1297 at->value->numFromStateRefs += 1;
1299 for ( ActionTable::Iter at = st->eofActionTable; at.lte(); at++ )
1300 at->value->numEofRefs += 1;
1302 for ( StateCondList::Iter sc = st->stateCondList; sc.lte(); sc++ ) {
1303 for ( CondSet::Iter sci = sc->condSpace->condSet; sci.lte(); sci++ )
1304 (*sci)->numCondRefs += 1;
1308 /* Checks for bad usage of directives in action code. */
1309 for ( ActionList::Iter act = actionList; act.lte(); act++ )
1310 checkAction( act );
1313 void ParseData::makeExportsNameTree()
1315 /* Make a name tree for the exports. */
1316 initExportsNameWalk();
1318 /* First make the name tree. */
1319 for ( GraphDict::Iter gdel = graphDict; gdel.lte(); gdel++ ) {
1320 if ( gdel->value->isExport ) {
1321 /* Recurse on the instance. */
1322 gdel->value->makeNameTree( gdel->loc, this );
1327 void ParseData::makeExports()
1329 makeExportsNameTree();
1331 /* Resove name references in the tree. */
1332 initExportsNameWalk();
1333 for ( GraphDict::Iter gdel = graphDict; gdel.lte(); gdel++ ) {
1334 if ( gdel->value->isExport )
1335 gdel->value->resolveNameRefs( this );
1338 /* Make all the instantiations, we know that main exists in this list. */
1339 initExportsNameWalk();
1340 for ( GraphDict::Iter gdel = graphDict; gdel.lte(); gdel++ ) {
1341 /* Check if this var def is an export. */
1342 if ( gdel->value->isExport ) {
1343 /* Build the graph from a walk of the parse tree. */
1344 FsmAp *graph = gdel->value->walk( this );
1346 /* Build the graph from a walk of the parse tree. */
1347 if ( !graph->checkSingleCharMachine() ) {
1348 error(gdel->loc) << "bad export machine, must define "
1349 "a single character" << endl;
1351 else {
1352 /* Safe to extract the key and declare the export. */
1353 Key exportKey = graph->startState->outList.head->lowKey;
1354 exportList.append( new Export( gdel->value->name, exportKey ) );
1361 /* Construct the machine and catch failures which can occur during
1362 * construction. */
1363 void ParseData::prepareMachineGen( GraphDictEl *graphDictEl )
1365 try {
1366 /* This machine construction can fail. */
1367 prepareMachineGenTBWrapped( graphDictEl );
1369 catch ( FsmConstructFail fail ) {
1370 switch ( fail.reason ) {
1371 case FsmConstructFail::CondNoKeySpace: {
1372 InputLoc &loc = alphTypeSet ? alphTypeLoc : sectionLoc;
1373 error(loc) << "sorry, no more characters are "
1374 "available in the alphabet space" << endl;
1375 error(loc) << " for conditions, please use a "
1376 "smaller alphtype or reduce" << endl;
1377 error(loc) << " the span of characters on which "
1378 "conditions are embedded" << endl;
1379 break;
1385 void ParseData::prepareMachineGenTBWrapped( GraphDictEl *graphDictEl )
1387 beginProcessing();
1388 initKeyOps();
1389 makeRootNames();
1390 initLongestMatchData();
1392 /* Make the graph, do minimization. */
1393 if ( graphDictEl == 0 )
1394 sectionGraph = makeAll();
1395 else
1396 sectionGraph = makeSpecific( graphDictEl );
1398 /* Compute exports from the export definitions. */
1399 makeExports();
1401 /* If any errors have occured in the input file then don't write anything. */
1402 if ( gblErrorCount > 0 )
1403 return;
1405 analyzeGraph( sectionGraph );
1407 /* Depends on the graph analysis. */
1408 setLongestMatchData( sectionGraph );
1410 /* Decide if an error state is necessary.
1411 * 1. There is an error transition
1412 * 2. There is a gap in the transitions
1413 * 3. The longest match operator requires it. */
1414 if ( lmRequiresErrorState || sectionGraph->hasErrorTrans() )
1415 sectionGraph->errState = sectionGraph->addState();
1417 /* State numbers need to be assigned such that all final states have a
1418 * larger state id number than all non-final states. This enables the
1419 * first_final mechanism to function correctly. We also want states to be
1420 * ordered in a predictable fashion. So we first apply a depth-first
1421 * search, then do a stable sort by final state status, then assign
1422 * numbers. */
1424 sectionGraph->depthFirstOrdering();
1425 sectionGraph->sortStatesByFinal();
1426 sectionGraph->setStateNumbers( 0 );
1429 void ParseData::generateXML( ostream &out )
1431 beginProcessing();
1433 /* Make the generator. */
1434 XMLCodeGen codeGen( sectionName, this, sectionGraph, out );
1436 /* Write out with it. */
1437 codeGen.writeXML();
1439 if ( printStatistics ) {
1440 cerr << "fsm name : " << sectionName << endl;
1441 cerr << "num states: " << sectionGraph->stateList.length() << endl;
1442 cerr << endl;
1446 /* Send eof to all parsers. */
1447 void terminateAllParsers( )
1449 /* FIXME: a proper token is needed here. Suppose we should use the
1450 * location of EOF in the last file that the parser was referenced in. */
1451 InputLoc loc;
1452 loc.fileName = "<EOF>";
1453 loc.line = 0;
1454 loc.col = 0;
1455 for ( ParserDict::Iter pdel = parserDict; pdel.lte(); pdel++ )
1456 pdel->value->token( loc, _eof, 0, 0 );
1459 void writeLanguage( std::ostream &out )
1461 out << " lang=\"";
1462 switch ( hostLang->lang ) {
1463 case HostLang::C: out << "C"; break;
1464 case HostLang::D: out << "D"; break;
1465 case HostLang::Java: out << "Java"; break;
1466 case HostLang::Ruby: out << "Ruby"; break;
1467 case HostLang::CSharp: out << "C#"; break;
1469 out << "\"";
1473 void writeMachines( std::ostream &out, std::string hostData,
1474 const char *inputFileName, XmlParser &xmlParser )
1476 if ( machineSpec == 0 && machineName == 0 ) {
1477 /* No machine spec or machine name given. Generate everything. */
1478 for ( ParserDict::Iter parser = parserDict; parser.lte(); parser++ ) {
1479 ParseData *pd = parser->value->pd;
1480 if ( pd->instanceList.length() > 0 )
1481 pd->prepareMachineGen( 0 );
1484 if ( gblErrorCount == 0 ) {
1485 out << "<ragel version=\"" VERSION "\" filename=\"" << inputFileName << "\"";
1486 writeLanguage( out );
1487 out << ">\n";
1488 for ( ParserDict::Iter parser = parserDict; parser.lte(); parser++ ) {
1489 ParseData *pd = parser->value->pd;
1490 if ( pd->instanceList.length() > 0 )
1491 pd->generateXML( out );
1493 out << hostData;
1494 out << "</ragel>\n";
1497 else if ( parserDict.length() > 0 ) {
1498 /* There is either a machine spec or machine name given. */
1499 ParseData *parseData = 0;
1500 GraphDictEl *graphDictEl = 0;
1502 /* Traverse the sections, break out when we find a section/machine
1503 * that matches the one specified. */
1504 for ( ParserDict::Iter parser = parserDict; parser.lte(); parser++ ) {
1505 ParseData *checkPd = parser->value->pd;
1506 if ( machineSpec == 0 || strcmp( checkPd->sectionName, machineSpec ) == 0 ) {
1507 GraphDictEl *checkGdEl = 0;
1508 if ( machineName == 0 || (checkGdEl =
1509 checkPd->graphDict.find( machineName )) != 0 )
1511 /* Have a machine spec and/or machine name that matches
1512 * the -M/-S options. */
1513 parseData = checkPd;
1514 graphDictEl = checkGdEl;
1515 break;
1520 if ( parseData == 0 )
1521 error() << "could not locate machine specified with -S and/or -M" << endl;
1522 else {
1523 /* Section/Machine to emit was found. Prepare and emit it. */
1524 parseData->prepareMachineGen( graphDictEl );
1525 if ( gblErrorCount == 0 ) {
1526 out << "<ragel version=\"" VERSION "\" filename=\"" << inputFileName << "\"";
1527 writeLanguage( out );
1528 out << ">\n";
1529 parseData->generateXML( out );
1530 out << hostData;
1531 out << "</ragel>\n";