994fec7203adbdc4da0aea5a46a60114154cf928
[external/ragel.git] / ragel / xmlcodegen.cpp
1 /*
2  *  Copyright 2005-2007 Adrian Thurston <thurston@complang.org>
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
23 #include "ragel.h"
24 #include "xmlcodegen.h"
25 #include "parsedata.h"
26 #include "fsmgraph.h"
27 #include "gendata.h"
28 #include "inputdata.h"
29 #include <string.h>
30 #include "rlparse.h"
31 #include "version.h"
32
33 using namespace std;
34
35 GenBase::GenBase( char *fsmName, ParseData *pd, FsmAp *fsm )
36 :
37         fsmName(fsmName),
38         pd(pd),
39         fsm(fsm),
40         nextActionTableId(0)
41 {
42 }
43
44 void GenBase::appendTrans( TransListVect &outList, Key lowKey, 
45                 Key highKey, TransAp *trans )
46 {
47         if ( trans->toState != 0 || trans->actionTable.length() > 0 )
48                 outList.append( TransEl( lowKey, highKey, trans ) );
49 }
50
51 void GenBase::reduceActionTables()
52 {
53         /* Reduce the actions tables to a set. */
54         for ( StateList::Iter st = fsm->stateList; st.lte(); st++ ) {
55                 RedActionTable *actionTable = 0;
56
57                 /* Reduce To State Actions. */
58                 if ( st->toStateActionTable.length() > 0 ) {
59                         if ( actionTableMap.insert( st->toStateActionTable, &actionTable ) )
60                                 actionTable->id = nextActionTableId++;
61                 }
62
63                 /* Reduce From State Actions. */
64                 if ( st->fromStateActionTable.length() > 0 ) {
65                         if ( actionTableMap.insert( st->fromStateActionTable, &actionTable ) )
66                                 actionTable->id = nextActionTableId++;
67                 }
68
69                 /* Reduce EOF actions. */
70                 if ( st->eofActionTable.length() > 0 ) {
71                         if ( actionTableMap.insert( st->eofActionTable, &actionTable ) )
72                                 actionTable->id = nextActionTableId++;
73                 }
74
75                 /* Loop the transitions and reduce their actions. */
76                 for ( TransList::Iter trans = st->outList; trans.lte(); trans++ ) {
77                         if ( trans->actionTable.length() > 0 ) {
78                                 if ( actionTableMap.insert( trans->actionTable, &actionTable ) )
79                                         actionTable->id = nextActionTableId++;
80                         }
81                 }
82         }
83 }
84
85 XMLCodeGen::XMLCodeGen( char *fsmName, ParseData *pd, FsmAp *fsm, std::ostream &out )
86 :
87         GenBase(fsmName, pd, fsm),
88         out(out)
89 {
90 }
91
92
93 void XMLCodeGen::writeActionList()
94 {
95         /* Determine which actions to write. */
96         int nextActionId = 0;
97         for ( ActionList::Iter act = pd->actionList; act.lte(); act++ ) {
98                 if ( act->numRefs() > 0 || act->numCondRefs > 0 )
99                         act->actionId = nextActionId++;
100         }
101
102         /* Write the list. */
103         out << "    <action_list length=\"" << nextActionId << "\">\n";
104         for ( ActionList::Iter act = pd->actionList; act.lte(); act++ ) {
105                 if ( act->actionId >= 0 )
106                         writeAction( act );
107         }
108         out << "    </action_list>\n";
109 }
110
111 void XMLCodeGen::writeActionTableList()
112 {
113         /* Must first order the action tables based on their id. */
114         int numTables = nextActionTableId;
115         RedActionTable **tables = new RedActionTable*[numTables];
116         for ( ActionTableMap::Iter at = actionTableMap; at.lte(); at++ )
117                 tables[at->id] = at;
118
119         out << "    <action_table_list length=\"" << numTables << "\">\n";
120         for ( int t = 0; t < numTables; t++ ) {
121                 out << "      <action_table id=\"" << t << "\" length=\"" << 
122                                 tables[t]->key.length() << "\">";
123                 for ( ActionTable::Iter atel = tables[t]->key; atel.lte(); atel++ ) {
124                         out << atel->value->actionId;
125                         if ( ! atel.last() )
126                                 out << " ";
127                 }
128                 out << "</action_table>\n";
129         }
130         out << "    </action_table_list>\n";
131
132         delete[] tables;
133 }
134
135 void XMLCodeGen::writeKey( Key key )
136 {
137         if ( keyOps->isSigned )
138                 out << key.getVal();
139         else
140                 out << (unsigned long) key.getVal();
141 }
142
143 void XMLCodeGen::writeTrans( Key lowKey, Key highKey, TransAp *trans )
144 {
145         /* First reduce the action. */
146         RedActionTable *actionTable = 0;
147         if ( trans->actionTable.length() > 0 )
148                 actionTable = actionTableMap.find( trans->actionTable );
149
150         /* Write the transition. */
151         out << "        <t>";
152         writeKey( lowKey );
153         out << " ";
154         writeKey( highKey );
155
156         if ( trans->toState != 0 )
157                 out << " " << trans->toState->alg.stateNum;
158         else
159                 out << " x";
160
161         if ( actionTable != 0 )
162                 out << " " << actionTable->id;
163         else
164                 out << " x";
165         out << "</t>\n";
166 }
167
168 void XMLCodeGen::writeTransList( StateAp *state )
169 {
170         TransListVect outList;
171
172         /* If there is only are no ranges the task is simple. */
173         if ( state->outList.length() > 0 ) {
174                 /* Loop each source range. */
175                 for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) {
176                         /* Reduce the transition. If it reduced to anything then add it. */
177                         appendTrans( outList, trans->lowKey, trans->highKey, trans );
178                 }
179         }
180
181         out << "      <trans_list length=\"" << outList.length() << "\">\n";
182         for ( TransListVect::Iter tvi = outList; tvi.lte(); tvi++ )
183                 writeTrans( tvi->lowKey, tvi->highKey, tvi->value );
184         out << "      </trans_list>\n";
185 }
186
187 void XMLCodeGen::writeEofTrans( StateAp *state )
188 {
189         RedActionTable *eofActions = 0;
190         if ( state->eofActionTable.length() > 0 )
191                 eofActions = actionTableMap.find( state->eofActionTable );
192         
193         /* The <eof_t> is used when there is an eof target, otherwise the eof
194          * action goes into state actions. */
195         if ( state->eofTarget != 0 ) {
196                 out << "      <eof_t>" << state->eofTarget->alg.stateNum;
197
198                 if ( eofActions != 0 )
199                         out << " " << eofActions->id;
200                 else
201                         out << " x"; 
202
203                 out << "</eof_t>" << endl;
204         }
205 }
206
207 void XMLCodeGen::writeText( InlineItem *item )
208 {
209         if ( item->prev == 0 || item->prev->type != InlineItem::Text )
210                 out << "<text>";
211         xmlEscapeHost( out, item->data, strlen(item->data) );
212         if ( item->next == 0 || item->next->type != InlineItem::Text )
213                 out << "</text>";
214 }
215
216 void XMLCodeGen::writeGoto( InlineItem *item )
217 {
218         if ( pd->generatingSectionSubset )
219                 out << "<goto>-1</goto>";
220         else {
221                 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
222                 out << "<goto>" << targ->value->alg.stateNum << "</goto>";
223         }
224 }
225
226 void XMLCodeGen::writeCall( InlineItem *item )
227 {
228         if ( pd->generatingSectionSubset )
229                 out << "<call>-1</call>";
230         else {
231                 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
232                 out << "<call>" << targ->value->alg.stateNum << "</call>";
233         }
234 }
235
236 void XMLCodeGen::writeNext( InlineItem *item )
237 {
238         if ( pd->generatingSectionSubset )
239                 out << "<next>-1</next>";
240         else {
241                 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
242                 out << "<next>" << targ->value->alg.stateNum << "</next>";
243         }
244 }
245
246 void XMLCodeGen::writeGotoExpr( InlineItem *item )
247 {
248         out << "<goto_expr>";
249         writeInlineList( item->children );
250         out << "</goto_expr>";
251 }
252
253 void XMLCodeGen::writeCallExpr( InlineItem *item )
254 {
255         out << "<call_expr>";
256         writeInlineList( item->children );
257         out << "</call_expr>";
258 }
259
260 void XMLCodeGen::writeNextExpr( InlineItem *item )
261 {
262         out << "<next_expr>";
263         writeInlineList( item->children );
264         out << "</next_expr>";
265 }
266
267 void XMLCodeGen::writeEntry( InlineItem *item )
268 {
269         if ( pd->generatingSectionSubset )
270                 out << "<entry>-1</entry>";
271         else {
272                 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
273                 out << "<entry>" << targ->value->alg.stateNum << "</entry>";
274         }
275 }
276
277 void XMLCodeGen::writeActionExec( InlineItem *item )
278 {
279         out << "<exec>";
280         writeInlineList( item->children );
281         out << "</exec>";
282 }
283
284 void XMLCodeGen::writeLmOnLast( InlineItem *item )
285 {
286         out << "<set_tokend>1</set_tokend>";
287
288         if ( item->longestMatchPart->action != 0 ) {
289                 out << "<sub_action>";
290                 writeInlineList( item->longestMatchPart->action->inlineList );
291                 out << "</sub_action>";
292         }
293 }
294
295 void XMLCodeGen::writeLmOnNext( InlineItem *item )
296 {
297         out << "<set_tokend>0</set_tokend>";
298         out << "<hold></hold>";
299
300         if ( item->longestMatchPart->action != 0 ) {
301                 out << "<sub_action>";
302                 writeInlineList( item->longestMatchPart->action->inlineList );
303                 out << "</sub_action>";
304         }
305 }
306
307 void XMLCodeGen::writeLmOnLagBehind( InlineItem *item )
308 {
309         out << "<exec><get_tokend></get_tokend></exec>";
310
311         if ( item->longestMatchPart->action != 0 ) {
312                 out << "<sub_action>";
313                 writeInlineList( item->longestMatchPart->action->inlineList );
314                 out << "</sub_action>";
315         }
316 }
317
318 void XMLCodeGen::writeLmSwitch( InlineItem *item )
319 {
320         LongestMatch *longestMatch = item->longestMatch;
321         out << "<lm_switch>\n";
322
323         /* We can't put the <exec> here because we may need to handle the error
324          * case and in that case p should not be changed. Instead use a default
325          * label in the switch to adjust p when user actions are not set. An id of
326          * -1 indicates the default. */
327
328         if ( longestMatch->lmSwitchHandlesError ) {
329                 /* If the switch handles error then we should have also forced the
330                  * error state. */
331                 assert( fsm->errState != 0 );
332
333                 out << "        <sub_action id=\"0\">";
334                 out << "<goto>" << fsm->errState->alg.stateNum << "</goto>";
335                 out << "</sub_action>\n";
336         }
337         
338         bool needDefault = false;
339         for ( LmPartList::Iter lmi = *longestMatch->longestMatchList; lmi.lte(); lmi++ ) {
340                 if ( lmi->inLmSelect ) {
341                         if ( lmi->action == 0 )
342                                 needDefault = true;
343                         else {
344                                 /* Open the action. Write it with the context that sets up _p 
345                                  * when doing control flow changes from inside the machine. */
346                                 out << "        <sub_action id=\"" << lmi->longestMatchId << "\">";
347                                 out << "<exec><get_tokend></get_tokend></exec>";
348                                 writeInlineList( lmi->action->inlineList );
349                                 out << "</sub_action>\n";
350                         }
351                 }
352         }
353
354         if ( needDefault ) {
355                 out << "        <sub_action id=\"-1\"><exec><get_tokend>"
356                                 "</get_tokend></exec></sub_action>\n";
357         }
358
359         out << "    </lm_switch>";
360 }
361
362 void XMLCodeGen::writeInlineList( InlineList *inlineList )
363 {
364         for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
365                 switch ( item->type ) {
366                 case InlineItem::Text:
367                         writeText( item );
368                         break;
369                 case InlineItem::Goto:
370                         writeGoto( item );
371                         break;
372                 case InlineItem::GotoExpr:
373                         writeGotoExpr( item );
374                         break;
375                 case InlineItem::Call:
376                         writeCall( item );
377                         break;
378                 case InlineItem::CallExpr:
379                         writeCallExpr( item );
380                         break;
381                 case InlineItem::Next:
382                         writeNext( item );
383                         break;
384                 case InlineItem::NextExpr:
385                         writeNextExpr( item );
386                         break;
387                 case InlineItem::Break:
388                         out << "<break></break>";
389                         break;
390                 case InlineItem::Ret: 
391                         out << "<ret></ret>";
392                         break;
393                 case InlineItem::PChar:
394                         out << "<pchar></pchar>";
395                         break;
396                 case InlineItem::Char: 
397                         out << "<char></char>";
398                         break;
399                 case InlineItem::Curs: 
400                         out << "<curs></curs>";
401                         break;
402                 case InlineItem::Targs: 
403                         out << "<targs></targs>";
404                         break;
405                 case InlineItem::Entry:
406                         writeEntry( item );
407                         break;
408
409                 case InlineItem::Hold:
410                         out << "<hold></hold>";
411                         break;
412                 case InlineItem::Exec:
413                         writeActionExec( item );
414                         break;
415
416                 case InlineItem::LmSetActId:
417                         out << "<set_act>" << 
418                                         item->longestMatchPart->longestMatchId << 
419                                         "</set_act>";
420                         break;
421                 case InlineItem::LmSetTokEnd:
422                         out << "<set_tokend>1</set_tokend>";
423                         break;
424
425                 case InlineItem::LmOnLast:
426                         writeLmOnLast( item );
427                         break;
428                 case InlineItem::LmOnNext:
429                         writeLmOnNext( item );
430                         break;
431                 case InlineItem::LmOnLagBehind:
432                         writeLmOnLagBehind( item );
433                         break;
434                 case InlineItem::LmSwitch: 
435                         writeLmSwitch( item );
436                         break;
437
438                 case InlineItem::LmInitAct:
439                         out << "<init_act></init_act>";
440                         break;
441                 case InlineItem::LmInitTokStart:
442                         out << "<init_tokstart></init_tokstart>";
443                         break;
444                 case InlineItem::LmSetTokStart:
445                         out << "<set_tokstart></set_tokstart>";
446                         break;
447                 }
448         }
449 }
450
451 BackendGen::BackendGen( char *fsmName, ParseData *pd, FsmAp *fsm, CodeGenData *cgd )
452 :
453         GenBase(fsmName, pd, fsm),
454         cgd(cgd)
455 {
456 }
457
458
459 void BackendGen::makeText( GenInlineList *outList, InlineItem *item )
460 {
461         GenInlineItem *inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::Text );
462         inlineItem->data = item->data;
463
464         outList->append( inlineItem );
465 }
466
467 void BackendGen::makeTargetItem( GenInlineList *outList, NameInst *nameTarg, 
468                 GenInlineItem::Type type )
469 {
470         long targetState;
471         if ( pd->generatingSectionSubset )
472                 targetState = -1;
473         else {
474                 EntryMapEl *targ = fsm->entryPoints.find( nameTarg->id );
475                 targetState = targ->value->alg.stateNum;
476         }
477
478         /* Make the item. */
479         GenInlineItem *inlineItem = new GenInlineItem( InputLoc(), type );
480         inlineItem->targId = targetState;
481         outList->append( inlineItem );
482 }
483
484 /* Make a sublist item with a given type. */
485 void BackendGen::makeSubList( GenInlineList *outList, 
486                 InlineList *inlineList, GenInlineItem::Type type )
487 {
488         /* Fill the sub list. */
489         GenInlineList *subList = new GenInlineList;
490         makeGenInlineList( subList, inlineList );
491
492         /* Make the item. */
493         GenInlineItem *inlineItem = new GenInlineItem( InputLoc(), type );
494         inlineItem->children = subList;
495         outList->append( inlineItem );
496 }
497
498 void BackendGen::makeLmOnLast( GenInlineList *outList, InlineItem *item )
499 {
500         makeSetTokend( outList, 1 );
501
502         if ( item->longestMatchPart->action != 0 ) {
503                 makeSubList( outList, 
504                                 item->longestMatchPart->action->inlineList, 
505                                 GenInlineItem::SubAction );
506         }
507 }
508
509 void BackendGen::makeLmOnNext( GenInlineList *outList, InlineItem *item )
510 {
511         makeSetTokend( outList, 0 );
512         outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Hold ) );
513
514         if ( item->longestMatchPart->action != 0 ) {
515                 makeSubList( outList, 
516                         item->longestMatchPart->action->inlineList,
517                         GenInlineItem::SubAction );
518         }
519 }
520
521 void BackendGen::makeExecGetTokend( GenInlineList *outList )
522 {
523         /* Make the Exec item. */
524         GenInlineItem *execItem = new GenInlineItem( InputLoc(), GenInlineItem::Exec );
525         execItem->children = new GenInlineList;
526
527         /* Make the GetTokEnd */
528         GenInlineItem *getTokend = new GenInlineItem( InputLoc(), GenInlineItem::LmGetTokEnd );
529         execItem->children->append( getTokend );
530
531         outList->append( execItem );
532 }
533
534 void BackendGen::makeLmOnLagBehind( GenInlineList *outList, InlineItem *item )
535 {
536         /* Jump to the tokend. */
537         makeExecGetTokend( outList );
538
539         if ( item->longestMatchPart->action != 0 ) {
540                 makeSubList( outList,
541                         item->longestMatchPart->action->inlineList,
542                         GenInlineItem::SubAction );
543         }
544 }
545
546 void BackendGen::makeLmSwitch( GenInlineList *outList, InlineItem *item )
547 {
548         GenInlineItem *lmSwitch = new GenInlineItem( InputLoc(), GenInlineItem::LmSwitch );
549         GenInlineList *lmList = lmSwitch->children = new GenInlineList;
550         LongestMatch *longestMatch = item->longestMatch;
551
552         /* We can't put the <exec> here because we may need to handle the error
553          * case and in that case p should not be changed. Instead use a default
554          * label in the switch to adjust p when user actions are not set. An id of
555          * -1 indicates the default. */
556
557         if ( longestMatch->lmSwitchHandlesError ) {
558                 /* If the switch handles error then we should have also forced the
559                  * error state. */
560                 assert( fsm->errState != 0 );
561
562                 GenInlineItem *errCase = new GenInlineItem( InputLoc(), GenInlineItem::SubAction );
563                 errCase->lmId = 0;
564                 errCase->children = new GenInlineList;
565
566                 /* Make the item. */
567                 GenInlineItem *gotoItem = new GenInlineItem( InputLoc(), GenInlineItem::Goto );
568                 gotoItem->targId = fsm->errState->alg.stateNum;
569                 errCase->children->append( gotoItem );
570
571                 lmList->append( errCase );
572         }
573         
574         bool needDefault = false;
575         for ( LmPartList::Iter lmi = *longestMatch->longestMatchList; lmi.lte(); lmi++ ) {
576                 if ( lmi->inLmSelect ) {
577                         if ( lmi->action == 0 )
578                                 needDefault = true;
579                         else {
580                                 /* Open the action. Write it with the context that sets up _p 
581                                  * when doing control flow changes from inside the machine. */
582                                 GenInlineItem *lmCase = new GenInlineItem( InputLoc(), 
583                                                 GenInlineItem::SubAction );
584                                 lmCase->lmId = lmi->longestMatchId;
585                                 lmCase->children = new GenInlineList;
586
587                                 makeExecGetTokend( lmCase->children );
588                                 makeGenInlineList( lmCase->children, lmi->action->inlineList );
589
590                                 lmList->append( lmCase );
591                         }
592                 }
593         }
594
595         if ( needDefault ) {
596                 GenInlineItem *defCase = new GenInlineItem( InputLoc(), 
597                                 GenInlineItem::SubAction );
598                 defCase->lmId = -1;
599                 defCase->children = new GenInlineList;
600
601                 makeExecGetTokend( defCase->children );
602
603                 lmList->append( defCase );
604         }
605
606         outList->append( lmSwitch );
607 }
608
609 void BackendGen::makeSetTokend( GenInlineList *outList, long offset )
610 {
611         GenInlineItem *inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::LmSetTokEnd );
612         inlineItem->offset = offset;
613         outList->append( inlineItem );
614 }
615
616 void BackendGen::makeSetAct( GenInlineList *outList, long lmId )
617 {
618         GenInlineItem *inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::LmSetActId );
619         inlineItem->lmId = lmId;
620         outList->append( inlineItem );
621 }
622
623 void BackendGen::makeGenInlineList( GenInlineList *outList, InlineList *inList )
624 {
625         for ( InlineList::Iter item = *inList; item.lte(); item++ ) {
626                 switch ( item->type ) {
627                 case InlineItem::Text:
628                         makeText( outList, item );
629                         break;
630                 case InlineItem::Goto:
631                         makeTargetItem( outList, item->nameTarg, GenInlineItem::Goto );
632                         break;
633                 case InlineItem::GotoExpr:
634                         makeSubList( outList, item->children, GenInlineItem::GotoExpr );
635                         break;
636                 case InlineItem::Call:
637                         makeTargetItem( outList, item->nameTarg, GenInlineItem::Call );
638                         break;
639                 case InlineItem::CallExpr:
640                         makeSubList( outList, item->children, GenInlineItem::CallExpr );
641                         break;
642                 case InlineItem::Next:
643                         makeTargetItem( outList, item->nameTarg, GenInlineItem::Next );
644                         break;
645                 case InlineItem::NextExpr:
646                         makeSubList( outList, item->children, GenInlineItem::NextExpr );
647                         break;
648                 case InlineItem::Break:
649                         outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Break ) );
650                         break;
651                 case InlineItem::Ret: 
652                         outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Ret ) );
653                         break;
654                 case InlineItem::PChar:
655                         outList->append( new GenInlineItem( InputLoc(), GenInlineItem::PChar ) );
656                         break;
657                 case InlineItem::Char: 
658                         outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Char ) );
659                         break;
660                 case InlineItem::Curs: 
661                         outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Curs ) );
662                         break;
663                 case InlineItem::Targs: 
664                         outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Targs ) );
665                         break;
666                 case InlineItem::Entry:
667                         makeTargetItem( outList, item->nameTarg, GenInlineItem::Entry );
668                         break;
669
670                 case InlineItem::Hold:
671                         outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Hold ) );
672                         break;
673                 case InlineItem::Exec:
674                         makeSubList( outList, item->children, GenInlineItem::Exec );
675                         break;
676
677                 case InlineItem::LmSetActId:
678                         makeSetAct( outList, item->longestMatchPart->longestMatchId );
679                         break;
680                 case InlineItem::LmSetTokEnd:
681                         makeSetTokend( outList, 1 );
682                         break;
683
684                 case InlineItem::LmOnLast:
685                         makeLmOnLast( outList, item );
686                         break;
687                 case InlineItem::LmOnNext:
688                         makeLmOnNext( outList, item );
689                         break;
690                 case InlineItem::LmOnLagBehind:
691                         makeLmOnLagBehind( outList, item );
692                         break;
693                 case InlineItem::LmSwitch: 
694                         makeLmSwitch( outList, item );
695                         break;
696
697                 case InlineItem::LmInitAct:
698                         outList->append( new GenInlineItem( InputLoc(), GenInlineItem::LmInitAct ) );
699                         break;
700                 case InlineItem::LmInitTokStart:
701                         outList->append( new GenInlineItem( InputLoc(), GenInlineItem::LmInitTokStart ) );
702                         break;
703                 case InlineItem::LmSetTokStart:
704                         outList->append( new GenInlineItem( InputLoc(), GenInlineItem::LmSetTokStart ) );
705                         cgd->hasLongestMatch = true;
706                         break;
707                 }
708         }
709 }
710
711
712 void XMLCodeGen::writeAction( Action *action )
713 {
714         out << "      <action id=\"" << action->actionId << "\"";
715         if ( action->name != 0 ) 
716                 out << " name=\"" << action->name << "\"";
717         out << " line=\"" << action->loc.line << "\" col=\"" << action->loc.col << "\">";
718         writeInlineList( action->inlineList );
719         out << "</action>\n";
720 }
721
722 void xmlEscapeHost( std::ostream &out, char *data, long len )
723 {
724         char *end = data + len;
725         while ( data != end ) {
726                 switch ( *data ) {
727                 case '<': out << "&lt;"; break;
728                 case '>': out << "&gt;"; break;
729                 case '&': out << "&amp;"; break;
730                 default: out << *data; break;
731                 }
732                 data += 1;
733         }
734 }
735
736 void XMLCodeGen::writeStateActions( StateAp *state )
737 {
738         RedActionTable *toStateActions = 0;
739         if ( state->toStateActionTable.length() > 0 )
740                 toStateActions = actionTableMap.find( state->toStateActionTable );
741
742         RedActionTable *fromStateActions = 0;
743         if ( state->fromStateActionTable.length() > 0 )
744                 fromStateActions = actionTableMap.find( state->fromStateActionTable );
745
746         /* EOF actions go out here only if the state has no eof target. If it has
747          * an eof target then an eof transition will be used instead. */
748         RedActionTable *eofActions = 0;
749         if ( state->eofTarget == 0 && state->eofActionTable.length() > 0 )
750                 eofActions = actionTableMap.find( state->eofActionTable );
751         
752         if ( toStateActions != 0 || fromStateActions != 0 || eofActions != 0 ) {
753                 out << "      <state_actions>";
754                 if ( toStateActions != 0 )
755                         out << toStateActions->id;
756                 else
757                         out << "x";
758
759                 if ( fromStateActions != 0 )
760                         out << " " << fromStateActions->id;
761                 else
762                         out << " x";
763
764                 if ( eofActions != 0 )
765                         out << " " << eofActions->id;
766                 else
767                         out << " x";
768
769                 out << "</state_actions>\n";
770         }
771 }
772
773 void XMLCodeGen::writeStateConditions( StateAp *state )
774 {
775         if ( state->stateCondList.length() > 0 ) {
776                 out << "      <cond_list length=\"" << state->stateCondList.length() << "\">\n";
777                 for ( StateCondList::Iter scdi = state->stateCondList; scdi.lte(); scdi++ ) {
778                         out << "        <c>";
779                         writeKey( scdi->lowKey );
780                         out << " ";
781                         writeKey( scdi->highKey );
782                         out << " ";
783                         out << scdi->condSpace->condSpaceId;
784                         out << "</c>\n";
785                 }
786                 out << "      </cond_list>\n";
787         }
788 }
789
790 void XMLCodeGen::writeStateList()
791 {
792         /* Write the list of states. */
793         out << "    <state_list length=\"" << fsm->stateList.length() << "\">\n";
794         for ( StateList::Iter st = fsm->stateList; st.lte(); st++ ) {
795                 out << "      <state id=\"" << st->alg.stateNum << "\"";
796                 if ( st->isFinState() )
797                         out << " final=\"t\"";
798                 out << ">\n";
799
800                 writeStateActions( st );
801                 writeEofTrans( st );
802                 writeStateConditions( st );
803                 writeTransList( st );
804
805                 out << "      </state>\n";
806
807                 if ( !st.last() )
808                         out << "\n";
809         }
810         out << "    </state_list>\n";
811 }
812
813 bool XMLCodeGen::writeNameInst( NameInst *nameInst )
814 {
815         bool written = false;
816         if ( nameInst->parent != 0 )
817                 written = writeNameInst( nameInst->parent );
818         
819         if ( nameInst->name != 0 ) {
820                 if ( written )
821                         out << '_';
822                 out << nameInst->name;
823                 written = true;
824         }
825
826         return written;
827 }
828
829 void XMLCodeGen::writeEntryPoints()
830 {
831         /* List of entry points other than start state. */
832         if ( fsm->entryPoints.length() > 0 || pd->lmRequiresErrorState ) {
833                 out << "    <entry_points";
834                 if ( pd->lmRequiresErrorState )
835                         out << " error=\"t\"";
836                 out << ">\n";
837                 for ( EntryMap::Iter en = fsm->entryPoints; en.lte(); en++ ) {
838                         /* Get the name instantiation from nameIndex. */
839                         NameInst *nameInst = pd->nameIndex[en->key];
840                         StateAp *state = en->value;
841                         out << "      <entry name=\"";
842                         writeNameInst( nameInst );
843                         out << "\">" << state->alg.stateNum << "</entry>\n";
844                 }
845                 out << "    </entry_points>\n";
846         }
847 }
848
849 void XMLCodeGen::writeMachine()
850 {
851         /* Open the machine. */
852         out << "  <machine>\n"; 
853         
854         /* Action tables. */
855         reduceActionTables();
856
857         writeActionList();
858         writeActionTableList();
859         writeConditions();
860
861         /* Start state. */
862         out << "    <start_state>" << fsm->startState->alg.stateNum << 
863                         "</start_state>\n";
864         
865         /* Error state. */
866         if ( fsm->errState != 0 ) {
867                 out << "    <error_state>" << fsm->errState->alg.stateNum << 
868                         "</error_state>\n";
869         }
870
871         writeEntryPoints();
872         writeStateList();
873
874         out << "  </machine>\n";
875 }
876
877
878 void XMLCodeGen::writeConditions()
879 {
880         if ( condData->condSpaceMap.length() > 0 ) {
881                 long nextCondSpaceId = 0;
882                 for ( CondSpaceMap::Iter cs = condData->condSpaceMap; cs.lte(); cs++ )
883                         cs->condSpaceId = nextCondSpaceId++;
884
885                 out << "    <cond_space_list length=\"" << condData->condSpaceMap.length() << "\">\n";
886                 for ( CondSpaceMap::Iter cs = condData->condSpaceMap; cs.lte(); cs++ ) {
887                         out << "      <cond_space id=\"" << cs->condSpaceId << 
888                                 "\" length=\"" << cs->condSet.length() << "\">";
889                         writeKey( cs->baseKey );
890                         for ( CondSet::Iter csi = cs->condSet; csi.lte(); csi++ )
891                                 out << " " << (*csi)->actionId;
892                         out << "</cond_space>\n";
893                 }
894                 out << "    </cond_space_list>\n";
895         }
896 }
897
898 void XMLCodeGen::writeExports()
899 {
900         if ( pd->exportList.length() > 0 ) {
901                 out << "  <exports>\n";
902                 for ( ExportList::Iter exp = pd->exportList; exp.lte(); exp++ ) {
903                         out << "    <ex name=\"" << exp->name << "\">";
904                         writeKey( exp->key );
905                         out << "</ex>\n";
906                 }
907                 out << "  </exports>\n";
908         }
909 }
910
911 void XMLCodeGen::writeXML()
912 {
913         /* Open the definition. */
914         out << "<ragel_def name=\"" << fsmName << "\">\n";
915
916         /* Alphabet type. */
917         out << "  <alphtype>" << keyOps->alphType->internalName << "</alphtype>\n";
918         
919         /* Getkey expression. */
920         if ( pd->getKeyExpr != 0 ) {
921                 out << "  <getkey>";
922                 writeInlineList( pd->getKeyExpr );
923                 out << "</getkey>\n";
924         }
925
926         /* Access expression. */
927         if ( pd->accessExpr != 0 ) {
928                 out << "  <access>";
929                 writeInlineList( pd->accessExpr );
930                 out << "</access>\n";
931         }
932
933         /* PrePush expression. */
934         if ( pd->prePushExpr != 0 ) {
935                 out << "  <prepush>";
936                 writeInlineList( pd->prePushExpr );
937                 out << "</prepush>\n";
938         }
939
940         /* PostPop expression. */
941         if ( pd->postPopExpr != 0 ) {
942                 out << "  <postpop>";
943                 writeInlineList( pd->postPopExpr );
944                 out << "</postpop>\n";
945         }
946
947         /*
948          * Variable expressions.
949          */
950
951         if ( pd->pExpr != 0 ) {
952                 out << "  <p_expr>";
953                 writeInlineList( pd->pExpr );
954                 out << "</p_expr>\n";
955         }
956         
957         if ( pd->peExpr != 0 ) {
958                 out << "  <pe_expr>";
959                 writeInlineList( pd->peExpr );
960                 out << "</pe_expr>\n";
961         }
962
963         if ( pd->eofExpr != 0 ) {
964                 out << "  <eof_expr>";
965                 writeInlineList( pd->eofExpr );
966                 out << "</eof_expr>\n";
967         }
968         
969         if ( pd->csExpr != 0 ) {
970                 out << "  <cs_expr>";
971                 writeInlineList( pd->csExpr );
972                 out << "</cs_expr>\n";
973         }
974         
975         if ( pd->topExpr != 0 ) {
976                 out << "  <top_expr>";
977                 writeInlineList( pd->topExpr );
978                 out << "</top_expr>\n";
979         }
980         
981         if ( pd->stackExpr != 0 ) {
982                 out << "  <stack_expr>";
983                 writeInlineList( pd->stackExpr );
984                 out << "</stack_expr>\n";
985         }
986         
987         if ( pd->actExpr != 0 ) {
988                 out << "  <act_expr>";
989                 writeInlineList( pd->actExpr );
990                 out << "</act_expr>\n";
991         }
992         
993         if ( pd->tokstartExpr != 0 ) {
994                 out << "  <tokstart_expr>";
995                 writeInlineList( pd->tokstartExpr );
996                 out << "</tokstart_expr>\n";
997         }
998         
999         if ( pd->tokendExpr != 0 ) {
1000                 out << "  <tokend_expr>";
1001                 writeInlineList( pd->tokendExpr );
1002                 out << "</tokend_expr>\n";
1003         }
1004         
1005         if ( pd->dataExpr != 0 ) {
1006                 out << "  <data_expr>";
1007                 writeInlineList( pd->dataExpr );
1008                 out << "</data_expr>\n";
1009         }
1010         
1011         writeExports();
1012         
1013         writeMachine();
1014
1015         out <<
1016                 "</ragel_def>\n";
1017 }
1018
1019 void BackendGen::makeExports()
1020 {
1021         for ( ExportList::Iter exp = pd->exportList; exp.lte(); exp++ )
1022                 cgd->exportList.append( new Export( exp->name, exp->key ) );
1023 }
1024
1025 void BackendGen::makeAction( Action *action )
1026 {
1027         GenInlineList *genList = new GenInlineList;
1028         makeGenInlineList( genList, action->inlineList );
1029
1030         cgd->newAction( curAction++, action->name, 
1031                         action->loc.line, action->loc.col, genList );
1032 }
1033
1034
1035 void BackendGen::makeActionList()
1036 {
1037         /* Determine which actions to write. */
1038         int nextActionId = 0;
1039         for ( ActionList::Iter act = pd->actionList; act.lte(); act++ ) {
1040                 if ( act->numRefs() > 0 || act->numCondRefs > 0 )
1041                         act->actionId = nextActionId++;
1042         }
1043
1044         /* Write the list. */
1045         cgd->initActionList( nextActionId );
1046         curAction = 0;
1047
1048         for ( ActionList::Iter act = pd->actionList; act.lte(); act++ ) {
1049                 if ( act->actionId >= 0 )
1050                         makeAction( act );
1051         }
1052 }
1053
1054 void BackendGen::makeActionTableList()
1055 {
1056         /* Must first order the action tables based on their id. */
1057         int numTables = nextActionTableId;
1058         RedActionTable **tables = new RedActionTable*[numTables];
1059         for ( ActionTableMap::Iter at = actionTableMap; at.lte(); at++ )
1060                 tables[at->id] = at;
1061
1062         cgd->initActionTableList( numTables );
1063         curActionTable = 0;
1064
1065         for ( int t = 0; t < numTables; t++ ) {
1066                 long length = tables[t]->key.length();
1067
1068                 /* Collect the action table. */
1069                 RedAction *redAct = cgd->allActionTables + curActionTable;
1070                 redAct->actListId = curActionTable;
1071                 redAct->key.setAsNew( length );
1072
1073                 for ( ActionTable::Iter atel = tables[t]->key; atel.lte(); atel++ ) {
1074                         redAct->key[atel.pos()].key = 0;
1075                         redAct->key[atel.pos()].value = cgd->allActions + 
1076                                         atel->value->actionId;
1077                 }
1078
1079                 /* Insert into the action table map. */
1080                 cgd->redFsm->actionMap.insert( redAct );
1081
1082                 curActionTable += 1;
1083         }
1084
1085         delete[] tables;
1086 }
1087
1088 void BackendGen::makeConditions()
1089 {
1090         if ( condData->condSpaceMap.length() > 0 ) {
1091                 long nextCondSpaceId = 0;
1092                 for ( CondSpaceMap::Iter cs = condData->condSpaceMap; cs.lte(); cs++ )
1093                         cs->condSpaceId = nextCondSpaceId++;
1094
1095                 long listLength = condData->condSpaceMap.length();
1096                 cgd->initCondSpaceList( listLength );
1097                 curCondSpace = 0;
1098
1099                 for ( CondSpaceMap::Iter cs = condData->condSpaceMap; cs.lte(); cs++ ) {
1100                         long id = cs->condSpaceId;
1101                         cgd->newCondSpace( curCondSpace, id, cs->baseKey );
1102                         for ( CondSet::Iter csi = cs->condSet; csi.lte(); csi++ )
1103                                 cgd->condSpaceItem( curCondSpace, (*csi)->actionId );
1104                         curCondSpace += 1;
1105                 }
1106         }
1107 }
1108
1109 bool BackendGen::makeNameInst( std::string &res, NameInst *nameInst )
1110 {
1111         bool written = false;
1112         if ( nameInst->parent != 0 )
1113                 written = makeNameInst( res, nameInst->parent );
1114         
1115         if ( nameInst->name != 0 ) {
1116                 if ( written )
1117                         res += '_';
1118                 res += nameInst->name;
1119                 written = true;
1120         }
1121
1122         return written;
1123 }
1124
1125 void BackendGen::makeEntryPoints()
1126 {
1127         /* List of entry points other than start state. */
1128         if ( fsm->entryPoints.length() > 0 || pd->lmRequiresErrorState ) {
1129                 if ( pd->lmRequiresErrorState )
1130                         cgd->setForcedErrorState();
1131
1132                 for ( EntryMap::Iter en = fsm->entryPoints; en.lte(); en++ ) {
1133                         /* Get the name instantiation from nameIndex. */
1134                         NameInst *nameInst = pd->nameIndex[en->key];
1135                         std::string name;
1136                         makeNameInst( name, nameInst );
1137                         StateAp *state = en->value;
1138                         cgd->addEntryPoint( strdup(name.c_str()), state->alg.stateNum );
1139                 }
1140         }
1141 }
1142
1143 void BackendGen::makeStateActions( StateAp *state )
1144 {
1145         RedActionTable *toStateActions = 0;
1146         if ( state->toStateActionTable.length() > 0 )
1147                 toStateActions = actionTableMap.find( state->toStateActionTable );
1148
1149         RedActionTable *fromStateActions = 0;
1150         if ( state->fromStateActionTable.length() > 0 )
1151                 fromStateActions = actionTableMap.find( state->fromStateActionTable );
1152
1153         /* EOF actions go out here only if the state has no eof target. If it has
1154          * an eof target then an eof transition will be used instead. */
1155         RedActionTable *eofActions = 0;
1156         if ( state->eofTarget == 0 && state->eofActionTable.length() > 0 )
1157                 eofActions = actionTableMap.find( state->eofActionTable );
1158         
1159         if ( toStateActions != 0 || fromStateActions != 0 || eofActions != 0 ) {
1160                 long to = -1;
1161                 if ( toStateActions != 0 )
1162                         to = toStateActions->id;
1163
1164                 long from = -1;
1165                 if ( fromStateActions != 0 )
1166                         from = fromStateActions->id;
1167
1168                 long eof = -1;
1169                 if ( eofActions != 0 )
1170                         eof = eofActions->id;
1171
1172                 cgd->setStateActions( curState, to, from, eof );
1173         }
1174 }
1175
1176 void BackendGen::makeEofTrans( StateAp *state )
1177 {
1178         RedActionTable *eofActions = 0;
1179         if ( state->eofActionTable.length() > 0 )
1180                 eofActions = actionTableMap.find( state->eofActionTable );
1181         
1182         /* The EOF trans is used when there is an eof target, otherwise the eof
1183          * action goes into state actions. */
1184         if ( state->eofTarget != 0 ) {
1185                 long targ = state->eofTarget->alg.stateNum;
1186                 long action = -1;
1187                 if ( eofActions != 0 )
1188                         action = eofActions->id;
1189
1190                 cgd->setEofTrans( curState, targ, action );
1191         }
1192 }
1193
1194 void BackendGen::makeStateConditions( StateAp *state )
1195 {
1196         if ( state->stateCondList.length() > 0 ) {
1197                 long length = state->stateCondList.length();
1198                 cgd->initStateCondList( curState, length );
1199                 curStateCond = 0;
1200
1201                 for ( StateCondList::Iter scdi = state->stateCondList; scdi.lte(); scdi++ ) {
1202                         cgd->addStateCond( curState, scdi->lowKey, scdi->highKey, 
1203                                         scdi->condSpace->condSpaceId );
1204                 }
1205         }
1206 }
1207
1208 void BackendGen::makeTrans( Key lowKey, Key highKey, TransAp *trans )
1209 {
1210         /* First reduce the action. */
1211         RedActionTable *actionTable = 0;
1212         if ( trans->actionTable.length() > 0 )
1213                 actionTable = actionTableMap.find( trans->actionTable );
1214
1215         long targ = -1;
1216         if ( trans->toState != 0 )
1217                 targ = trans->toState->alg.stateNum;
1218
1219         long action = -1;
1220         if ( actionTable != 0 )
1221                 action = actionTable->id;
1222
1223         cgd->newTrans( curState, curTrans++, lowKey, highKey, targ, action );
1224 }
1225
1226 void BackendGen::makeTransList( StateAp *state )
1227 {
1228         TransListVect outList;
1229
1230         /* If there is only are no ranges the task is simple. */
1231         if ( state->outList.length() > 0 ) {
1232                 /* Loop each source range. */
1233                 for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) {
1234                         /* Reduce the transition. If it reduced to anything then add it. */
1235                         appendTrans( outList, trans->lowKey, trans->highKey, trans );
1236                 }
1237         }
1238
1239         cgd->initTransList( curState, outList.length() );
1240         curTrans = 0;
1241
1242         for ( TransListVect::Iter tvi = outList; tvi.lte(); tvi++ )
1243                 makeTrans( tvi->lowKey, tvi->highKey, tvi->value );
1244
1245         cgd->finishTransList( curState );
1246 }
1247
1248
1249 void BackendGen::makeStateList()
1250 {
1251         /* Write the list of states. */
1252         long length = fsm->stateList.length();
1253         cgd->initStateList( length );
1254         curState = 0;
1255         for ( StateList::Iter st = fsm->stateList; st.lte(); st++ ) {
1256                 makeStateActions( st );
1257                 makeEofTrans( st );
1258                 makeStateConditions( st );
1259                 makeTransList( st );
1260
1261                 long id = st->alg.stateNum;
1262                 cgd->setId( curState, id );
1263
1264                 if ( st->isFinState() )
1265                         cgd->setFinal( curState );
1266
1267                 curState += 1;
1268         }
1269 }
1270
1271
1272 void BackendGen::makeMachine()
1273 {
1274         cgd->createMachine();
1275
1276         /* Action tables. */
1277         reduceActionTables();
1278
1279         makeActionList();
1280         makeActionTableList();
1281         makeConditions();
1282
1283         /* Start State. */
1284         cgd->setStartState( fsm->startState->alg.stateNum );
1285
1286         /* Error state. */
1287         if ( fsm->errState != 0 )
1288                 cgd->setErrorState( fsm->errState->alg.stateNum );
1289
1290         makeEntryPoints();
1291         makeStateList();
1292
1293         cgd->closeMachine();
1294 }
1295
1296 void BackendGen::close_ragel_def()
1297 {
1298         /* Do this before distributing transitions out to singles and defaults
1299          * makes life easier. */
1300         cgd->redFsm->maxKey = cgd->findMaxKey();
1301
1302         cgd->redFsm->assignActionLocs();
1303
1304         /* Find the first final state (The final state with the lowest id). */
1305         cgd->redFsm->findFirstFinState();
1306
1307         /* Call the user's callback. */
1308         cgd->finishRagelDef();
1309 }
1310
1311
1312 void BackendGen::makeBackend()
1313 {
1314         /* Alphabet type. */
1315         cgd->setAlphType( keyOps->alphType->internalName );
1316         
1317         /* Getkey expression. */
1318         if ( pd->getKeyExpr != 0 ) {
1319                 cgd->getKeyExpr = new GenInlineList;
1320                 makeGenInlineList( cgd->getKeyExpr, pd->getKeyExpr );
1321         }
1322
1323         /* Access expression. */
1324         if ( pd->accessExpr != 0 ) {
1325                 cgd->accessExpr = new GenInlineList;
1326                 makeGenInlineList( cgd->accessExpr, pd->accessExpr );
1327         }
1328
1329         /* PrePush expression. */
1330         if ( pd->prePushExpr != 0 ) {
1331                 cgd->prePushExpr = new GenInlineList;
1332                 makeGenInlineList( cgd->prePushExpr, pd->prePushExpr );
1333         }
1334
1335         /* PostPop expression. */
1336         if ( pd->postPopExpr != 0 ) {
1337                 cgd->postPopExpr = new GenInlineList;
1338                 makeGenInlineList( cgd->postPopExpr, pd->postPopExpr );
1339         }
1340
1341         /*
1342          * Variable expressions.
1343          */
1344
1345         if ( pd->pExpr != 0 ) {
1346                 cgd->pExpr = new GenInlineList;
1347                 makeGenInlineList( cgd->pExpr, pd->pExpr );
1348         }
1349         
1350         if ( pd->peExpr != 0 ) {
1351                 cgd->peExpr = new GenInlineList;
1352                 makeGenInlineList( cgd->peExpr, pd->peExpr );
1353         }
1354
1355         if ( pd->eofExpr != 0 ) {
1356                 cgd->eofExpr = new GenInlineList;
1357                 makeGenInlineList( cgd->eofExpr, pd->eofExpr );
1358         }
1359         
1360         if ( pd->csExpr != 0 ) {
1361                 cgd->csExpr = new GenInlineList;
1362                 makeGenInlineList( cgd->csExpr, pd->csExpr );
1363         }
1364         
1365         if ( pd->topExpr != 0 ) {
1366                 cgd->topExpr = new GenInlineList;
1367                 makeGenInlineList( cgd->topExpr, pd->topExpr );
1368         }
1369         
1370         if ( pd->stackExpr != 0 ) {
1371                 cgd->stackExpr = new GenInlineList;
1372                 makeGenInlineList( cgd->stackExpr, pd->stackExpr );
1373         }
1374         
1375         if ( pd->actExpr != 0 ) {
1376                 cgd->actExpr = new GenInlineList;
1377                 makeGenInlineList( cgd->actExpr, pd->actExpr );
1378         }
1379         
1380         if ( pd->tokstartExpr != 0 ) {
1381                 cgd->tokstartExpr = new GenInlineList;
1382                 makeGenInlineList( cgd->tokstartExpr, pd->tokstartExpr );
1383         }
1384         
1385         if ( pd->tokendExpr != 0 ) {
1386                 cgd->tokendExpr = new GenInlineList;
1387                 makeGenInlineList( cgd->tokendExpr, pd->tokendExpr );
1388         }
1389         
1390         if ( pd->dataExpr != 0 ) {
1391                 cgd->dataExpr = new GenInlineList;
1392                 makeGenInlineList( cgd->dataExpr, pd->dataExpr );
1393         }
1394         
1395         makeExports();
1396         makeMachine();
1397
1398         close_ragel_def();
1399 }
1400
1401 void InputData::writeLanguage( std::ostream &out )
1402 {
1403         out << " lang=\"";
1404         switch ( hostLang->lang ) {
1405                 case HostLang::C:    out << "C"; break;
1406                 case HostLang::D:    out << "D"; break;
1407                 case HostLang::Java: out << "Java"; break;
1408                 case HostLang::Ruby: out << "Ruby"; break;
1409                 case HostLang::CSharp: out << "C#"; break;
1410         }
1411         out << "\"";
1412 }
1413
1414 void InputData::writeXML( std::ostream &out )
1415 {
1416         out << "<ragel version=\"" VERSION "\" filename=\"" << inputFileName << "\"";
1417         writeLanguage( out );
1418         out << ">\n";
1419
1420         for ( ParserDict::Iter parser = parserDict; parser.lte(); parser++ ) {
1421                 ParseData *pd = parser->value->pd;
1422                 if ( pd->instanceList.length() > 0 )
1423                         pd->generateXML( *outStream );
1424         }
1425
1426         out << "</ragel>\n";
1427 }