If -M or -S are given and we're not generating a dot file then invoke the
[ragel.git] / ragel / parsedata.cpp
blob3fae9984d544be941b9dd4dafab9c536bfe81d67
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( 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 /* 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;
746 search = search->parent;
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;
756 default:
757 break;
760 /* Some of the item types may have children. */
761 if ( item->children != 0 )
762 resolveNameRefs( item->children, action );
766 /* Resolve references to labels in actions. */
767 void ParseData::resolveActionNameRefs()
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 );
776 /* Walk a name tree starting at from and fill the name index. */
777 void ParseData::fillNameIndex( NameInst *from )
779 /* Fill the value for from in the name index. */
780 nameIndex[from->id] = from;
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 );
789 void ParseData::makeRootNames()
791 /* Create the root name. */
792 rootName = new NameInst( InputLoc(), 0, 0, nextNameId++, false );
793 exportsRootName = new NameInst( InputLoc(), 0, 0, nextNameId++, false );
796 /* Build the name tree and supporting data structures. */
797 void ParseData::makeNameTree( GraphDictEl *dictEl )
799 /* Set up curNameInst for the walk. */
800 initNameWalk();
802 if ( dictEl != 0 ) {
803 /* A start location has been specified. */
804 dictEl->value->makeNameTree( dictEl->loc, this );
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 );
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 );
822 void ParseData::createBuiltin( const char *name, BuiltinMachine builtin )
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 );
832 /* Initialize the graph dict with builtin types. */
833 void ParseData::initGraphDict( )
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 );
854 /* Set the alphabet type. If the types are not valid returns false. */
855 bool ParseData::setAlphType( const InputLoc &loc, char *s1, char *s2 )
857 alphTypeLoc = loc;
858 userAlphType = findAlphType( s1, s2 );
859 alphTypeSet = true;
860 return userAlphType != 0;
863 /* Set the alphabet type. If the types are not valid returns false. */
864 bool ParseData::setAlphType( const InputLoc &loc, char *s1 )
866 alphTypeLoc = loc;
867 userAlphType = findAlphType( s1 );
868 alphTypeSet = true;
869 return userAlphType != 0;
872 bool ParseData::setVariable( char *var, InlineList *inlineList )
874 bool set = true;
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;
899 return set;
902 /* Initialize the key operators object that will be referenced by all fsms
903 * created. */
904 void ParseData::initKeyOps( )
906 /* Signedness and bounds. */
907 HostType *alphType = alphTypeSet ? userAlphType : hostLang->defaultAlphType;
908 thisKeyOps.setAlphType( alphType );
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 );
916 thisCondData.lastCondKey = thisKeyOps.maxKey;
919 void ParseData::printNameInst( NameInst *nameInst, int level )
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 );
931 /* Remove duplicates of unique actions from an action table. */
932 void ParseData::removeDups( ActionTable &table )
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;
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 )
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 );
963 Action *ParseData::newAction( const char *name, InlineList *inlineList )
965 InputLoc loc;
966 loc.line = 1;
967 loc.col = 1;
968 loc.fileName = "<NONE>";
970 Action *action = new Action( loc, name, inlineList, nextCondId++ );
971 action->actionRefs.append( rootName );
972 actionList.append( action );
973 return action;
976 void ParseData::initLongestMatchData()
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;
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;
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;
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;
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++;
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 )
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 );
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 );
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 );
1052 /* Make the graph from a graph dict node. Does minimization and state sorting. */
1053 FsmAp *ParseData::makeInstance( GraphDictEl *gdNode )
1055 /* Build the graph from a walk of the parse tree. */
1056 FsmAp *graph = gdNode->value->walk( this );
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();
1064 * All state construction is now complete.
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 );
1071 /* Transfer global error actions. */
1072 for ( StateList::Iter state = graph->stateList; state.lte(); state++ )
1073 graph->transferErrorActions( state, 0 );
1075 removeActionDups( graph );
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();
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();
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();
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;
1109 graph->compressTransitions();
1111 return graph;
1114 void ParseData::printNameTree()
1116 /* Print the name instance map. */
1117 for ( NameVect::Iter name = rootName->childVect; name.lte(); name++ )
1118 printNameInst( *name, 0 );
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 const char *name = nameIndex[ni]->name;
1125 cerr << ( name != 0 ? name : "<ANON>" ) << endl;
1129 FsmAp *ParseData::makeSpecific( GraphDictEl *gdNode )
1131 /* Build the name tree and supporting data structures. */
1132 makeNameTree( gdNode );
1134 /* Resove name references from gdNode. */
1135 initNameWalk();
1136 gdNode->value->resolveNameRefs( this );
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. */
1143 /* Same story for extern entry point references. */
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;
1149 /* Just building the specified graph. */
1150 initNameWalk();
1151 FsmAp *mainGraph = makeInstance( gdNode );
1153 return mainGraph;
1156 FsmAp *ParseData::makeAll()
1158 /* Build the name tree and supporting data structures. */
1159 makeNameTree( 0 );
1161 /* Resove name references in the tree. */
1162 initNameWalk();
1163 for ( GraphList::Iter glel = instanceList; glel.lte(); glel++ )
1164 glel->value->resolveNameRefs( this );
1166 /* Resolve action code name references. */
1167 resolveActionNameRefs();
1169 /* Force name references to the top level instantiations. */
1170 for ( NameVect::Iter inst = rootName->childVect; inst.lte(); inst++ )
1171 (*inst)->numRefs += 1;
1173 FsmAp *mainGraph = 0;
1174 FsmAp **graphs = new FsmAp*[instanceList.length()];
1175 int numOthers = 0;
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 );
1184 else {
1185 /* Instantiate and store in others array. */
1186 graphs[numOthers++] = makeInstance( glel );
1190 if ( mainGraph == 0 )
1191 mainGraph = graphs[--numOthers];
1193 if ( numOthers > 0 ) {
1194 /* Add all the other graphs into main. */
1195 mainGraph->globOp( graphs, numOthers );
1198 delete[] graphs;
1199 return mainGraph;
1202 void ParseData::analyzeAction( Action *action, InlineList *inlineList )
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;
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 );
1218 if ( item->type == InlineItem::LmOnLast ||
1219 item->type == InlineItem::LmOnNext ||
1220 item->type == InlineItem::LmOnLagBehind )
1222 LongestMatchPart *lmi = item->longestMatchPart;
1223 if ( lmi->action != 0 )
1224 analyzeAction( action, lmi->action->inlineList );
1227 if ( item->children != 0 )
1228 analyzeAction( action, item->children );
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 )
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;
1248 /* Recurse. */
1249 if ( item->children != 0 )
1250 checkInlineList( act, item->children );
1254 void ParseData::checkAction( Action *action )
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;
1267 check = check->parent;
1272 checkInlineList( action, action->inlineList );
1276 void ParseData::analyzeGraph( FsmAp *graph )
1278 for ( ActionList::Iter act = actionList; act.lte(); act++ )
1279 analyzeAction( act, act->inlineList );
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;
1288 for ( ActionTable::Iter at = st->toStateActionTable; at.lte(); at++ )
1289 at->value->numToStateRefs += 1;
1291 for ( ActionTable::Iter at = st->fromStateActionTable; at.lte(); at++ )
1292 at->value->numFromStateRefs += 1;
1294 for ( ActionTable::Iter at = st->eofActionTable; at.lte(); at++ )
1295 at->value->numEofRefs += 1;
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;
1303 /* Checks for bad usage of directives in action code. */
1304 for ( ActionList::Iter act = actionList; act.lte(); act++ )
1305 checkAction( act );
1308 void ParseData::makeExportsNameTree()
1310 /* Make a name tree for the exports. */
1311 initExportsNameWalk();
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 );
1322 void ParseData::makeExports()
1324 makeExportsNameTree();
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 );
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 );
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;
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 ) );
1356 /* Construct the machine and catch failures which can occur during
1357 * construction. */
1358 void ParseData::prepareMachineGen( GraphDictEl *graphDictEl )
1360 try {
1361 /* This machine construction can fail. */
1362 prepareMachineGenTBWrapped( graphDictEl );
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;
1380 void ParseData::prepareMachineGenTBWrapped( GraphDictEl *graphDictEl )
1382 beginProcessing();
1383 initKeyOps();
1384 makeRootNames();
1385 initLongestMatchData();
1387 /* Make the graph, do minimization. */
1388 if ( graphDictEl == 0 )
1389 sectionGraph = makeAll();
1390 else
1391 sectionGraph = makeSpecific( graphDictEl );
1393 /* Compute exports from the export definitions. */
1394 makeExports();
1396 /* If any errors have occured in the input file then don't write anything. */
1397 if ( gblErrorCount > 0 )
1398 return;
1400 analyzeGraph( sectionGraph );
1402 /* Depends on the graph analysis. */
1403 setLongestMatchData( sectionGraph );
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();
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. */
1419 sectionGraph->depthFirstOrdering();
1420 sectionGraph->sortStatesByFinal();
1421 sectionGraph->setStateNumbers( 0 );
1424 void ParseData::generateXML( ostream &out )
1426 beginProcessing();
1428 /* Make the generator. */
1429 XMLCodeGen codeGen( sectionName, this, sectionGraph, out );
1431 /* Write out with it. */
1432 codeGen.writeXML();
1434 if ( printStatistics ) {
1435 cerr << "fsm name : " << sectionName << endl;
1436 cerr << "num states: " << sectionGraph->stateList.length() << endl;
1437 cerr << endl;
1441 /* Send eof to all parsers. */
1442 void terminateAllParsers( )
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 );
1454 void writeLanguage( std::ostream &out )
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;
1463 out << "\"";
1467 void writeMachines( std::ostream &out, std::string hostData, char *inputFileName )
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 );
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 );
1486 out << hostData;
1487 out << "</ragel>\n";
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;
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 )
1504 /* Have a machine spec and/or machine name that matches
1505 * the -M/-S options. */
1506 parseData = checkPd;
1507 graphDictEl = checkGdEl;
1508 break;
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";