Implemented makeLmSwitch and started making calls to makeGenInlineList.
[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 "xmlparse.h"
26 #include "parsedata.h"
27 #include "fsmgraph.h"
28 #include "gendata.h"
29 #include <string.h>
30
31 using namespace std;
32
33 XMLCodeGen::XMLCodeGen( char *fsmName, ParseData *pd, FsmAp *fsm, 
34                 std::ostream &out, XmlParser &xmlParser )
35 :
36         fsmName(fsmName),
37         pd(pd),
38         fsm(fsm),
39         out(out),
40         xmlParser(xmlParser),
41         nextActionTableId(0)
42 {
43 }
44
45
46 void XMLCodeGen::writeActionList()
47 {
48         /* Determine which actions to write. */
49         int nextActionId = 0;
50         for ( ActionList::Iter act = pd->actionList; act.lte(); act++ ) {
51                 if ( act->numRefs() > 0 || act->numCondRefs > 0 )
52                         act->actionId = nextActionId++;
53         }
54
55         /* Write the list. */
56         out << "    <action_list length=\"" << nextActionId << "\">\n";
57         for ( ActionList::Iter act = pd->actionList; act.lte(); act++ ) {
58                 if ( act->actionId >= 0 )
59                         writeAction( act );
60         }
61         out << "    </action_list>\n";
62 }
63
64 void XMLCodeGen::writeActionTableList()
65 {
66         /* Must first order the action tables based on their id. */
67         int numTables = nextActionTableId;
68         RedActionTable **tables = new RedActionTable*[numTables];
69         for ( ActionTableMap::Iter at = actionTableMap; at.lte(); at++ )
70                 tables[at->id] = at;
71
72         out << "    <action_table_list length=\"" << numTables << "\">\n";
73         for ( int t = 0; t < numTables; t++ ) {
74                 out << "      <action_table id=\"" << t << "\" length=\"" << 
75                                 tables[t]->key.length() << "\">";
76                 for ( ActionTable::Iter atel = tables[t]->key; atel.lte(); atel++ ) {
77                         out << atel->value->actionId;
78                         if ( ! atel.last() )
79                                 out << " ";
80                 }
81                 out << "</action_table>\n";
82         }
83         out << "    </action_table_list>\n";
84
85         delete[] tables;
86 }
87
88 void XMLCodeGen::reduceActionTables()
89 {
90         /* Reduce the actions tables to a set. */
91         for ( StateList::Iter st = fsm->stateList; st.lte(); st++ ) {
92                 RedActionTable *actionTable = 0;
93
94                 /* Reduce To State Actions. */
95                 if ( st->toStateActionTable.length() > 0 ) {
96                         if ( actionTableMap.insert( st->toStateActionTable, &actionTable ) )
97                                 actionTable->id = nextActionTableId++;
98                 }
99
100                 /* Reduce From State Actions. */
101                 if ( st->fromStateActionTable.length() > 0 ) {
102                         if ( actionTableMap.insert( st->fromStateActionTable, &actionTable ) )
103                                 actionTable->id = nextActionTableId++;
104                 }
105
106                 /* Reduce EOF actions. */
107                 if ( st->eofActionTable.length() > 0 ) {
108                         if ( actionTableMap.insert( st->eofActionTable, &actionTable ) )
109                                 actionTable->id = nextActionTableId++;
110                 }
111
112                 /* Loop the transitions and reduce their actions. */
113                 for ( TransList::Iter trans = st->outList; trans.lte(); trans++ ) {
114                         if ( trans->actionTable.length() > 0 ) {
115                                 if ( actionTableMap.insert( trans->actionTable, &actionTable ) )
116                                         actionTable->id = nextActionTableId++;
117                         }
118                 }
119         }
120 }
121
122 void XMLCodeGen::appendTrans( TransListVect &outList, Key lowKey, 
123                 Key highKey, TransAp *trans )
124 {
125         if ( trans->toState != 0 || trans->actionTable.length() > 0 )
126                 outList.append( TransEl( lowKey, highKey, trans ) );
127 }
128
129 void XMLCodeGen::writeKey( Key key )
130 {
131         if ( keyOps->isSigned )
132                 out << key.getVal();
133         else
134                 out << (unsigned long) key.getVal();
135 }
136
137 void XMLCodeGen::writeTrans( Key lowKey, Key highKey, TransAp *trans )
138 {
139         /* First reduce the action. */
140         RedActionTable *actionTable = 0;
141         if ( trans->actionTable.length() > 0 )
142                 actionTable = actionTableMap.find( trans->actionTable );
143
144         /* Write the transition. */
145         out << "        <t>";
146         writeKey( lowKey );
147         out << " ";
148         writeKey( highKey );
149
150         if ( trans->toState != 0 )
151                 out << " " << trans->toState->alg.stateNum;
152         else
153                 out << " x";
154
155         if ( actionTable != 0 )
156                 out << " " << actionTable->id;
157         else
158                 out << " x";
159         out << "</t>\n";
160 }
161
162 void XMLCodeGen::writeTransList( StateAp *state )
163 {
164         TransListVect outList;
165
166         /* If there is only are no ranges the task is simple. */
167         if ( state->outList.length() > 0 ) {
168                 /* Loop each source range. */
169                 for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) {
170                         /* Reduce the transition. If it reduced to anything then add it. */
171                         appendTrans( outList, trans->lowKey, trans->highKey, trans );
172                 }
173         }
174
175         out << "      <trans_list length=\"" << outList.length() << "\">\n";
176         for ( TransListVect::Iter tvi = outList; tvi.lte(); tvi++ )
177                 writeTrans( tvi->lowKey, tvi->highKey, tvi->value );
178         out << "      </trans_list>\n";
179 }
180
181 void XMLCodeGen::writeEofTrans( StateAp *state )
182 {
183         RedActionTable *eofActions = 0;
184         if ( state->eofActionTable.length() > 0 )
185                 eofActions = actionTableMap.find( state->eofActionTable );
186         
187         /* The <eof_t> is used when there is an eof target, otherwise the eof
188          * action goes into state actions. */
189         if ( state->eofTarget != 0 ) {
190                 out << "      <eof_t>" << state->eofTarget->alg.stateNum;
191
192                 if ( eofActions != 0 )
193                         out << " " << eofActions->id;
194                 else
195                         out << " x"; 
196
197                 out << "</eof_t>" << endl;
198         }
199 }
200
201 void XMLCodeGen::writeText( InlineItem *item )
202 {
203         if ( item->prev == 0 || item->prev->type != InlineItem::Text )
204                 out << "<text>";
205         xmlEscapeHost( out, item->data, strlen(item->data) );
206         if ( item->next == 0 || item->next->type != InlineItem::Text )
207                 out << "</text>";
208 }
209
210 void XMLCodeGen::writeGoto( InlineItem *item )
211 {
212         if ( pd->generatingSectionSubset )
213                 out << "<goto>-1</goto>";
214         else {
215                 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
216                 out << "<goto>" << targ->value->alg.stateNum << "</goto>";
217         }
218 }
219
220 void XMLCodeGen::writeCall( InlineItem *item )
221 {
222         if ( pd->generatingSectionSubset )
223                 out << "<call>-1</call>";
224         else {
225                 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
226                 out << "<call>" << targ->value->alg.stateNum << "</call>";
227         }
228 }
229
230 void XMLCodeGen::writeNext( InlineItem *item )
231 {
232         if ( pd->generatingSectionSubset )
233                 out << "<next>-1</next>";
234         else {
235                 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
236                 out << "<next>" << targ->value->alg.stateNum << "</next>";
237         }
238 }
239
240 void XMLCodeGen::writeGotoExpr( InlineItem *item )
241 {
242         out << "<goto_expr>";
243         writeInlineList( item->children );
244         out << "</goto_expr>";
245 }
246
247 void XMLCodeGen::writeCallExpr( InlineItem *item )
248 {
249         out << "<call_expr>";
250         writeInlineList( item->children );
251         out << "</call_expr>";
252 }
253
254 void XMLCodeGen::writeNextExpr( InlineItem *item )
255 {
256         out << "<next_expr>";
257         writeInlineList( item->children );
258         out << "</next_expr>";
259 }
260
261 void XMLCodeGen::writeEntry( InlineItem *item )
262 {
263         if ( pd->generatingSectionSubset )
264                 out << "<entry>-1</entry>";
265         else {
266                 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
267                 out << "<entry>" << targ->value->alg.stateNum << "</entry>";
268         }
269 }
270
271 void XMLCodeGen::writeActionExec( InlineItem *item )
272 {
273         out << "<exec>";
274         writeInlineList( item->children );
275         out << "</exec>";
276 }
277
278 void XMLCodeGen::writeLmOnLast( InlineItem *item )
279 {
280         out << "<set_tokend>1</set_tokend>";
281
282         if ( item->longestMatchPart->action != 0 ) {
283                 out << "<sub_action>";
284                 writeInlineList( item->longestMatchPart->action->inlineList );
285                 out << "</sub_action>";
286         }
287 }
288
289 void XMLCodeGen::writeLmOnNext( InlineItem *item )
290 {
291         out << "<set_tokend>0</set_tokend>";
292         out << "<hold></hold>";
293
294         if ( item->longestMatchPart->action != 0 ) {
295                 out << "<sub_action>";
296                 writeInlineList( item->longestMatchPart->action->inlineList );
297                 out << "</sub_action>";
298         }
299 }
300
301 void XMLCodeGen::writeLmOnLagBehind( InlineItem *item )
302 {
303         out << "<exec><get_tokend></get_tokend></exec>";
304
305         if ( item->longestMatchPart->action != 0 ) {
306                 out << "<sub_action>";
307                 writeInlineList( item->longestMatchPart->action->inlineList );
308                 out << "</sub_action>";
309         }
310 }
311
312 void XMLCodeGen::writeLmSwitch( InlineItem *item )
313 {
314         LongestMatch *longestMatch = item->longestMatch;
315         out << "<lm_switch>\n";
316
317         /* We can't put the <exec> here because we may need to handle the error
318          * case and in that case p should not be changed. Instead use a default
319          * label in the switch to adjust p when user actions are not set. An id of
320          * -1 indicates the default. */
321
322         if ( longestMatch->lmSwitchHandlesError ) {
323                 /* If the switch handles error then we should have also forced the
324                  * error state. */
325                 assert( fsm->errState != 0 );
326
327                 out << "        <sub_action id=\"0\">";
328                 out << "<goto>" << fsm->errState->alg.stateNum << "</goto>";
329                 out << "</sub_action>\n";
330         }
331         
332         bool needDefault = false;
333         for ( LmPartList::Iter lmi = *longestMatch->longestMatchList; lmi.lte(); lmi++ ) {
334                 if ( lmi->inLmSelect ) {
335                         if ( lmi->action == 0 )
336                                 needDefault = true;
337                         else {
338                                 /* Open the action. Write it with the context that sets up _p 
339                                  * when doing control flow changes from inside the machine. */
340                                 out << "        <sub_action id=\"" << lmi->longestMatchId << "\">";
341                                 out << "<exec><get_tokend></get_tokend></exec>";
342                                 writeInlineList( lmi->action->inlineList );
343                                 out << "</sub_action>\n";
344                         }
345                 }
346         }
347
348         if ( needDefault ) {
349                 out << "        <sub_action id=\"-1\"><exec><get_tokend>"
350                                 "</get_tokend></exec></sub_action>\n";
351         }
352
353         out << "    </lm_switch>";
354 }
355
356 void XMLCodeGen::writeInlineList( InlineList *inlineList )
357 {
358         for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
359                 switch ( item->type ) {
360                 case InlineItem::Text:
361                         writeText( item );
362                         break;
363                 case InlineItem::Goto:
364                         writeGoto( item );
365                         break;
366                 case InlineItem::GotoExpr:
367                         writeGotoExpr( item );
368                         break;
369                 case InlineItem::Call:
370                         writeCall( item );
371                         break;
372                 case InlineItem::CallExpr:
373                         writeCallExpr( item );
374                         break;
375                 case InlineItem::Next:
376                         writeNext( item );
377                         break;
378                 case InlineItem::NextExpr:
379                         writeNextExpr( item );
380                         break;
381                 case InlineItem::Break:
382                         out << "<break></break>";
383                         break;
384                 case InlineItem::Ret: 
385                         out << "<ret></ret>";
386                         break;
387                 case InlineItem::PChar:
388                         out << "<pchar></pchar>";
389                         break;
390                 case InlineItem::Char: 
391                         out << "<char></char>";
392                         break;
393                 case InlineItem::Curs: 
394                         out << "<curs></curs>";
395                         break;
396                 case InlineItem::Targs: 
397                         out << "<targs></targs>";
398                         break;
399                 case InlineItem::Entry:
400                         writeEntry( item );
401                         break;
402
403                 case InlineItem::Hold:
404                         out << "<hold></hold>";
405                         break;
406                 case InlineItem::Exec:
407                         writeActionExec( item );
408                         break;
409
410                 case InlineItem::LmSetActId:
411                         out << "<set_act>" << 
412                                         item->longestMatchPart->longestMatchId << 
413                                         "</set_act>";
414                         break;
415                 case InlineItem::LmSetTokEnd:
416                         out << "<set_tokend>1</set_tokend>";
417                         break;
418
419                 case InlineItem::LmOnLast:
420                         writeLmOnLast( item );
421                         break;
422                 case InlineItem::LmOnNext:
423                         writeLmOnNext( item );
424                         break;
425                 case InlineItem::LmOnLagBehind:
426                         writeLmOnLagBehind( item );
427                         break;
428                 case InlineItem::LmSwitch: 
429                         writeLmSwitch( item );
430                         break;
431
432                 case InlineItem::LmInitAct:
433                         out << "<init_act></init_act>";
434                         break;
435                 case InlineItem::LmInitTokStart:
436                         out << "<init_tokstart></init_tokstart>";
437                         break;
438                 case InlineItem::LmSetTokStart:
439                         out << "<set_tokstart></set_tokstart>";
440                         break;
441                 }
442         }
443 }
444
445 void XMLCodeGen::makeKey( GenInlineList *outList, Key key )
446 {
447 }
448
449 void XMLCodeGen::makeText( GenInlineList *outList, InlineItem *item )
450 {
451         GenInlineItem *inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::Text );
452         inlineItem->data = item->data;
453
454         outList->append( inlineItem );
455 }
456
457 void XMLCodeGen::makeTargetItem( GenInlineList *outList, long targetId, GenInlineItem::Type type )
458 {
459         long targetState;
460         if ( pd->generatingSectionSubset )
461                 targetState = -1;
462         else {
463                 EntryMapEl *targ = fsm->entryPoints.find( targetId );
464                 targetState = targ->value->alg.stateNum;
465         }
466
467         /* Make the item. */
468         GenInlineItem *inlineItem = new GenInlineItem( GenInputLoc(), type );
469         inlineItem->targId = targetState;
470         outList->append( inlineItem );
471 }
472
473 /* Make a sublist item with a given type. */
474 void XMLCodeGen::makeSubList( GenInlineList *outList, 
475                 InlineList *inlineList, GenInlineItem::Type type )
476 {
477         /* Fill the sub list. */
478         GenInlineList *subList = new GenInlineList;
479         makeGenInlineList( subList, inlineList );
480
481         /* Make the item. */
482         GenInlineItem *inlineItem = new GenInlineItem( GenInputLoc(), type );
483         inlineItem->children = subList;
484         outList->append( inlineItem );
485 }
486
487 void XMLCodeGen::makeLmOnLast( GenInlineList *outList, InlineItem *item )
488 {
489         makeSetTokend( outList, 1 );
490
491         if ( item->longestMatchPart->action != 0 ) {
492                 makeSubList( outList, 
493                                 item->longestMatchPart->action->inlineList, 
494                                 GenInlineItem::SubAction );
495         }
496 }
497
498 void XMLCodeGen::makeLmOnNext( GenInlineList *outList, InlineItem *item )
499 {
500         makeSetTokend( outList, 0 );
501         outList->append( new GenInlineItem( GenInputLoc(), GenInlineItem::Hold ) );
502
503         if ( item->longestMatchPart->action != 0 ) {
504                 makeSubList( outList, 
505                         item->longestMatchPart->action->inlineList,
506                         GenInlineItem::SubAction );
507         }
508 }
509
510 void XMLCodeGen::makeExecGetTokend( GenInlineList *outList )
511 {
512         /* Make the Exec item. */
513         GenInlineItem *execItem = new GenInlineItem( GenInputLoc(), GenInlineItem::Exec );
514         execItem->children = new GenInlineList;
515
516         /* Make the GetTokEnd */
517         GenInlineItem *getTokend = new GenInlineItem( GenInputLoc(), GenInlineItem::LmGetTokEnd );
518         execItem->children->append( getTokend );
519
520         outList->append( execItem );
521 }
522
523 void XMLCodeGen::makeLmOnLagBehind( GenInlineList *outList, InlineItem *item )
524 {
525         /* Jump to the tokend. */
526         makeExecGetTokend( outList );
527
528         if ( item->longestMatchPart->action != 0 ) {
529                 makeSubList( outList,
530                         item->longestMatchPart->action->inlineList,
531                         GenInlineItem::SubAction );
532         }
533 }
534
535 void XMLCodeGen::makeLmSwitch( GenInlineList *outList, InlineItem *item )
536 {
537         GenInlineItem *lmSwitch = new GenInlineItem( GenInputLoc(), GenInlineItem::LmSwitch );
538         GenInlineList *lmList = lmSwitch->children = new GenInlineList;
539         LongestMatch *longestMatch = item->longestMatch;
540
541         /* We can't put the <exec> here because we may need to handle the error
542          * case and in that case p should not be changed. Instead use a default
543          * label in the switch to adjust p when user actions are not set. An id of
544          * -1 indicates the default. */
545
546         if ( longestMatch->lmSwitchHandlesError ) {
547                 /* If the switch handles error then we should have also forced the
548                  * error state. */
549                 assert( fsm->errState != 0 );
550
551                 GenInlineItem *errCase = new GenInlineItem( GenInputLoc(), GenInlineItem::SubAction );
552                 errCase->lmId = 0;
553                 errCase->children = new GenInlineList;
554
555                 makeTargetItem( errCase->children, 
556                                 fsm->errState->alg.stateNum, GenInlineItem::Goto );
557
558                 lmList->append( errCase );
559         }
560         
561         bool needDefault = false;
562         for ( LmPartList::Iter lmi = *longestMatch->longestMatchList; lmi.lte(); lmi++ ) {
563                 if ( lmi->inLmSelect ) {
564                         if ( lmi->action == 0 )
565                                 needDefault = true;
566                         else {
567                                 /* Open the action. Write it with the context that sets up _p 
568                                  * when doing control flow changes from inside the machine. */
569                                 GenInlineItem *lmCase = new GenInlineItem( GenInputLoc(), 
570                                                 GenInlineItem::SubAction );
571                                 lmCase->lmId = lmi->longestMatchId;
572                                 lmCase->children = new GenInlineList;
573
574                                 makeExecGetTokend( lmCase->children );
575                                 makeGenInlineList( lmCase->children, lmi->action->inlineList );
576
577                                 lmList->append( lmCase );
578                         }
579                 }
580         }
581
582         if ( needDefault ) {
583                 GenInlineItem *defCase = new GenInlineItem( GenInputLoc(), 
584                                 GenInlineItem::SubAction );
585                 defCase->lmId = -1;
586                 defCase->children = new GenInlineList;
587
588                 makeExecGetTokend( defCase->children );
589
590                 lmList->append( defCase );
591         }
592
593         outList->append( lmSwitch );
594 }
595
596 void XMLCodeGen::makeSetTokend( GenInlineList *outList, long offset )
597 {
598         GenInlineItem *inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::LmSetTokEnd );
599         inlineItem->offset = offset;
600         outList->append( inlineItem );
601 }
602
603 void XMLCodeGen::makeSetAct( GenInlineList *outList, long lmId )
604 {
605         GenInlineItem *inlineItem = new GenInlineItem( GenInputLoc(), GenInlineItem::LmSetActId );
606         inlineItem->lmId = lmId;
607         outList->append( inlineItem );
608 }
609
610 void XMLCodeGen::makeGenInlineList( GenInlineList *outList, InlineList *inList )
611 {
612         for ( InlineList::Iter item = *inList; item.lte(); item++ ) {
613                 switch ( item->type ) {
614                 case InlineItem::Text:
615                         makeText( outList, item );
616                         break;
617                 case InlineItem::Goto:
618                         makeTargetItem( outList, item->nameTarg->id, GenInlineItem::Goto );
619                         break;
620                 case InlineItem::GotoExpr:
621                         makeSubList( outList, item->children, GenInlineItem::GotoExpr );
622                         break;
623                 case InlineItem::Call:
624                         makeTargetItem( outList, item->nameTarg->id, GenInlineItem::Call );
625                         break;
626                 case InlineItem::CallExpr:
627                         makeSubList( outList, item->children, GenInlineItem::CallExpr );
628                         break;
629                 case InlineItem::Next:
630                         makeTargetItem( outList, item->nameTarg->id, GenInlineItem::Next );
631                         break;
632                 case InlineItem::NextExpr:
633                         makeSubList( outList, item->children, GenInlineItem::NextExpr );
634                         break;
635                 case InlineItem::Break:
636                         outList->append( new GenInlineItem( GenInputLoc(), GenInlineItem::Break ) );
637                         break;
638                 case InlineItem::Ret: 
639                         outList->append( new GenInlineItem( GenInputLoc(), GenInlineItem::Ret ) );
640                         break;
641                 case InlineItem::PChar:
642                         outList->append( new GenInlineItem( GenInputLoc(), GenInlineItem::PChar ) );
643                         break;
644                 case InlineItem::Char: 
645                         outList->append( new GenInlineItem( GenInputLoc(), GenInlineItem::Char ) );
646                         break;
647                 case InlineItem::Curs: 
648                         outList->append( new GenInlineItem( GenInputLoc(), GenInlineItem::Curs ) );
649                         break;
650                 case InlineItem::Targs: 
651                         outList->append( new GenInlineItem( GenInputLoc(), GenInlineItem::Targs ) );
652                         break;
653                 case InlineItem::Entry:
654                         makeTargetItem( outList, item->nameTarg->id, GenInlineItem::Entry );
655                         break;
656
657                 case InlineItem::Hold:
658                         outList->append( new GenInlineItem( GenInputLoc(), GenInlineItem::Hold ) );
659                         break;
660                 case InlineItem::Exec:
661                         makeSubList( outList, item->children, GenInlineItem::Exec );
662                         break;
663
664                 case InlineItem::LmSetActId:
665                         makeSetAct( outList, item->longestMatchPart->longestMatchId );
666                         break;
667                 case InlineItem::LmSetTokEnd:
668                         makeSetTokend( outList, 1 );
669                         break;
670
671                 case InlineItem::LmOnLast:
672                         makeLmOnLast( outList, item );
673                         break;
674                 case InlineItem::LmOnNext:
675                         makeLmOnNext( outList, item );
676                         break;
677                 case InlineItem::LmOnLagBehind:
678                         makeLmOnLagBehind( outList, item );
679                         break;
680                 case InlineItem::LmSwitch: 
681                         makeLmSwitch( outList, item );
682                         break;
683
684                 case InlineItem::LmInitAct:
685                         outList->append( new GenInlineItem( GenInputLoc(), GenInlineItem::LmInitAct ) );
686                         break;
687                 case InlineItem::LmInitTokStart:
688                         outList->append( new GenInlineItem( GenInputLoc(), GenInlineItem::LmInitTokStart ) );
689                         break;
690                 case InlineItem::LmSetTokStart:
691                         outList->append( new GenInlineItem( GenInputLoc(), GenInlineItem::LmSetTokStart ) );
692                         xmlParser.cgd->hasLongestMatch = true;
693                         break;
694                 }
695         }
696 }
697
698
699 void XMLCodeGen::writeAction( Action *action )
700 {
701         out << "      <action id=\"" << action->actionId << "\"";
702         if ( action->name != 0 ) 
703                 out << " name=\"" << action->name << "\"";
704         out << " line=\"" << action->loc.line << "\" col=\"" << action->loc.col << "\">";
705         writeInlineList( action->inlineList );
706         out << "</action>\n";
707 }
708
709 void xmlEscapeHost( std::ostream &out, char *data, long len )
710 {
711         char *end = data + len;
712         while ( data != end ) {
713                 switch ( *data ) {
714                 case '<': out << "&lt;"; break;
715                 case '>': out << "&gt;"; break;
716                 case '&': out << "&amp;"; break;
717                 default: out << *data; break;
718                 }
719                 data += 1;
720         }
721 }
722
723 void XMLCodeGen::writeStateActions( StateAp *state )
724 {
725         RedActionTable *toStateActions = 0;
726         if ( state->toStateActionTable.length() > 0 )
727                 toStateActions = actionTableMap.find( state->toStateActionTable );
728
729         RedActionTable *fromStateActions = 0;
730         if ( state->fromStateActionTable.length() > 0 )
731                 fromStateActions = actionTableMap.find( state->fromStateActionTable );
732
733         /* EOF actions go out here only if the state has no eof target. If it has
734          * an eof target then an eof transition will be used instead. */
735         RedActionTable *eofActions = 0;
736         if ( state->eofTarget == 0 && state->eofActionTable.length() > 0 )
737                 eofActions = actionTableMap.find( state->eofActionTable );
738         
739         if ( toStateActions != 0 || fromStateActions != 0 || eofActions != 0 ) {
740                 out << "      <state_actions>";
741                 if ( toStateActions != 0 )
742                         out << toStateActions->id;
743                 else
744                         out << "x";
745
746                 if ( fromStateActions != 0 )
747                         out << " " << fromStateActions->id;
748                 else
749                         out << " x";
750
751                 if ( eofActions != 0 )
752                         out << " " << eofActions->id;
753                 else
754                         out << " x";
755
756                 out << "</state_actions>\n";
757         }
758 }
759
760 void XMLCodeGen::writeStateConditions( StateAp *state )
761 {
762         if ( state->stateCondList.length() > 0 ) {
763                 out << "      <cond_list length=\"" << state->stateCondList.length() << "\">\n";
764                 for ( StateCondList::Iter scdi = state->stateCondList; scdi.lte(); scdi++ ) {
765                         out << "        <c>";
766                         writeKey( scdi->lowKey );
767                         out << " ";
768                         writeKey( scdi->highKey );
769                         out << " ";
770                         out << scdi->condSpace->condSpaceId;
771                         out << "</c>\n";
772                 }
773                 out << "      </cond_list>\n";
774         }
775 }
776
777 void XMLCodeGen::writeStateList()
778 {
779         /* Write the list of states. */
780         out << "    <state_list length=\"" << fsm->stateList.length() << "\">\n";
781         for ( StateList::Iter st = fsm->stateList; st.lte(); st++ ) {
782                 out << "      <state id=\"" << st->alg.stateNum << "\"";
783                 if ( st->isFinState() )
784                         out << " final=\"t\"";
785                 out << ">\n";
786
787                 writeStateActions( st );
788                 writeEofTrans( st );
789                 writeStateConditions( st );
790                 writeTransList( st );
791
792                 out << "      </state>\n";
793
794                 if ( !st.last() )
795                         out << "\n";
796         }
797         out << "    </state_list>\n";
798 }
799
800 bool XMLCodeGen::writeNameInst( NameInst *nameInst )
801 {
802         bool written = false;
803         if ( nameInst->parent != 0 )
804                 written = writeNameInst( nameInst->parent );
805         
806         if ( nameInst->name != 0 ) {
807                 if ( written )
808                         out << '_';
809                 out << nameInst->name;
810                 written = true;
811         }
812
813         return written;
814 }
815
816 void XMLCodeGen::writeEntryPoints()
817 {
818         /* List of entry points other than start state. */
819         if ( fsm->entryPoints.length() > 0 || pd->lmRequiresErrorState ) {
820                 out << "    <entry_points";
821                 if ( pd->lmRequiresErrorState )
822                         out << " error=\"t\"";
823                 out << ">\n";
824                 for ( EntryMap::Iter en = fsm->entryPoints; en.lte(); en++ ) {
825                         /* Get the name instantiation from nameIndex. */
826                         NameInst *nameInst = pd->nameIndex[en->key];
827                         StateAp *state = en->value;
828                         out << "      <entry name=\"";
829                         writeNameInst( nameInst );
830                         out << "\">" << state->alg.stateNum << "</entry>\n";
831                 }
832                 out << "    </entry_points>\n";
833         }
834 }
835
836 void XMLCodeGen::writeMachine()
837 {
838         /* Open the machine. */
839         out << "  <machine>\n"; 
840         
841         /* Action tables. */
842         reduceActionTables();
843
844         writeActionList();
845         writeActionTableList();
846         writeConditions();
847
848         /* Start state. */
849         out << "    <start_state>" << fsm->startState->alg.stateNum << 
850                         "</start_state>\n";
851         
852         /* Error state. */
853         if ( fsm->errState != 0 ) {
854                 out << "    <error_state>" << fsm->errState->alg.stateNum << 
855                         "</error_state>\n";
856         }
857
858         writeEntryPoints();
859         writeStateList();
860
861         out << "  </machine>\n";
862 }
863
864
865 void XMLCodeGen::writeConditions()
866 {
867         if ( condData->condSpaceMap.length() > 0 ) {
868                 long nextCondSpaceId = 0;
869                 for ( CondSpaceMap::Iter cs = condData->condSpaceMap; cs.lte(); cs++ )
870                         cs->condSpaceId = nextCondSpaceId++;
871
872                 out << "    <cond_space_list length=\"" << condData->condSpaceMap.length() << "\">\n";
873                 for ( CondSpaceMap::Iter cs = condData->condSpaceMap; cs.lte(); cs++ ) {
874                         out << "      <cond_space id=\"" << cs->condSpaceId << 
875                                 "\" length=\"" << cs->condSet.length() << "\">";
876                         writeKey( cs->baseKey );
877                         for ( CondSet::Iter csi = cs->condSet; csi.lte(); csi++ )
878                                 out << " " << (*csi)->actionId;
879                         out << "</cond_space>\n";
880                 }
881                 out << "    </cond_space_list>\n";
882         }
883 }
884
885 void XMLCodeGen::writeExports()
886 {
887         if ( pd->exportList.length() > 0 ) {
888                 out << "  <exports>\n";
889                 for ( ExportList::Iter exp = pd->exportList; exp.lte(); exp++ ) {
890                         out << "    <ex name=\"" << exp->name << "\">";
891                         writeKey( exp->key );
892                         out << "</ex>\n";
893                 }
894                 out << "  </exports>\n";
895         }
896 }
897
898 void XMLCodeGen::writeXML()
899 {
900         /* Open the definition. */
901         out << "<ragel_def name=\"" << fsmName << "\">\n";
902
903         /* Alphabet type. */
904         out << "  <alphtype>" << keyOps->alphType->internalName << "</alphtype>\n";
905         
906         /* Getkey expression. */
907         if ( pd->getKeyExpr != 0 ) {
908                 out << "  <getkey>";
909                 writeInlineList( pd->getKeyExpr );
910                 out << "</getkey>\n";
911         }
912
913         /* Access expression. */
914         if ( pd->accessExpr != 0 ) {
915                 out << "  <access>";
916                 writeInlineList( pd->accessExpr );
917                 out << "</access>\n";
918         }
919
920         /* PrePush expression. */
921         if ( pd->prePushExpr != 0 ) {
922                 out << "  <prepush>";
923                 writeInlineList( pd->prePushExpr );
924                 out << "</prepush>\n";
925         }
926
927         /* PostPop expression. */
928         if ( pd->postPopExpr != 0 ) {
929                 out << "  <postpop>";
930                 writeInlineList( pd->postPopExpr );
931                 out << "</postpop>\n";
932         }
933
934         /*
935          * Variable expressions.
936          */
937
938         if ( pd->pExpr != 0 ) {
939                 out << "  <p_expr>";
940                 writeInlineList( pd->pExpr );
941                 out << "</p_expr>\n";
942         }
943         
944         if ( pd->peExpr != 0 ) {
945                 out << "  <pe_expr>";
946                 writeInlineList( pd->peExpr );
947                 out << "</pe_expr>\n";
948         }
949
950         if ( pd->eofExpr != 0 ) {
951                 out << "  <eof_expr>";
952                 writeInlineList( pd->eofExpr );
953                 out << "</eof_expr>\n";
954         }
955         
956         if ( pd->csExpr != 0 ) {
957                 out << "  <cs_expr>";
958                 writeInlineList( pd->csExpr );
959                 out << "</cs_expr>\n";
960         }
961         
962         if ( pd->topExpr != 0 ) {
963                 out << "  <top_expr>";
964                 writeInlineList( pd->topExpr );
965                 out << "</top_expr>\n";
966         }
967         
968         if ( pd->stackExpr != 0 ) {
969                 out << "  <stack_expr>";
970                 writeInlineList( pd->stackExpr );
971                 out << "</stack_expr>\n";
972         }
973         
974         if ( pd->actExpr != 0 ) {
975                 out << "  <act_expr>";
976                 writeInlineList( pd->actExpr );
977                 out << "</act_expr>\n";
978         }
979         
980         if ( pd->tokstartExpr != 0 ) {
981                 out << "  <tokstart_expr>";
982                 writeInlineList( pd->tokstartExpr );
983                 out << "</tokstart_expr>\n";
984         }
985         
986         if ( pd->tokendExpr != 0 ) {
987                 out << "  <tokend_expr>";
988                 writeInlineList( pd->tokendExpr );
989                 out << "</tokend_expr>\n";
990         }
991         
992         if ( pd->dataExpr != 0 ) {
993                 out << "  <data_expr>";
994                 writeInlineList( pd->dataExpr );
995                 out << "</data_expr>\n";
996         }
997         
998         writeExports();
999         
1000         writeMachine();
1001
1002         out <<
1003                 "</ragel_def>\n";
1004 }
1005
1006 void XMLCodeGen::makeBackend()
1007 {
1008         /* Open the definition. */
1009         xmlParser.open_ragel_def( fsmName );
1010
1011         /* Alphabet type. */
1012         xmlParser.cgd->setAlphType( keyOps->alphType->internalName );
1013         
1014         /* Getkey expression. */
1015         if ( pd->getKeyExpr != 0 ) {
1016                 xmlParser.cgd->getKeyExpr = new GenInlineList;
1017                 makeGenInlineList( xmlParser.cgd->getKeyExpr, pd->getKeyExpr );
1018         }
1019
1020         /* Access expression. */
1021         if ( pd->accessExpr != 0 ) {
1022                 xmlParser.cgd->accessExpr = new GenInlineList;
1023                 makeGenInlineList( xmlParser.cgd->accessExpr, pd->accessExpr );
1024         }
1025
1026         /* PrePush expression. */
1027         if ( pd->prePushExpr != 0 ) {
1028                 xmlParser.cgd->prePushExpr = new GenInlineList;
1029                 makeGenInlineList( xmlParser.cgd->prePushExpr, pd->prePushExpr );
1030         }
1031
1032         /* PostPop expression. */
1033         if ( pd->postPopExpr != 0 ) {
1034                 xmlParser.cgd->postPopExpr = new GenInlineList;
1035                 makeGenInlineList( xmlParser.cgd->postPopExpr, pd->postPopExpr );
1036         }
1037
1038         /*
1039          * Variable expressions.
1040          */
1041
1042         if ( pd->pExpr != 0 ) {
1043                 xmlParser.cgd->pExpr = new GenInlineList;
1044                 makeGenInlineList( xmlParser.cgd->pExpr, pd->pExpr );
1045         }
1046         
1047         if ( pd->peExpr != 0 ) {
1048                 xmlParser.cgd->peExpr = new GenInlineList;
1049                 makeGenInlineList( xmlParser.cgd->peExpr, pd->peExpr );
1050         }
1051
1052         if ( pd->eofExpr != 0 ) {
1053                 xmlParser.cgd->eofExpr = new GenInlineList;
1054                 makeGenInlineList( xmlParser.cgd->eofExpr, pd->eofExpr );
1055         }
1056         
1057         if ( pd->csExpr != 0 ) {
1058                 xmlParser.cgd->csExpr = new GenInlineList;
1059                 makeGenInlineList( xmlParser.cgd->csExpr, pd->csExpr );
1060         }
1061         
1062         if ( pd->topExpr != 0 ) {
1063                 xmlParser.cgd->topExpr = new GenInlineList;
1064                 makeGenInlineList( xmlParser.cgd->topExpr, pd->topExpr );
1065         }
1066         
1067         if ( pd->stackExpr != 0 ) {
1068                 xmlParser.cgd->stackExpr = new GenInlineList;
1069                 makeGenInlineList( xmlParser.cgd->stackExpr, pd->stackExpr );
1070         }
1071         
1072         if ( pd->actExpr != 0 ) {
1073                 xmlParser.cgd->actExpr = new GenInlineList;
1074                 makeGenInlineList( xmlParser.cgd->actExpr, pd->actExpr );
1075         }
1076         
1077         if ( pd->tokstartExpr != 0 ) {
1078                 xmlParser.cgd->tokstartExpr = new GenInlineList;
1079                 makeGenInlineList( xmlParser.cgd->tokstartExpr, pd->tokstartExpr );
1080         }
1081         
1082         if ( pd->tokendExpr != 0 ) {
1083                 xmlParser.cgd->tokendExpr = new GenInlineList;
1084                 makeGenInlineList( xmlParser.cgd->tokendExpr, pd->tokendExpr );
1085         }
1086         
1087         if ( pd->dataExpr != 0 ) {
1088                 xmlParser.cgd->dataExpr = new GenInlineList;
1089                 makeGenInlineList( xmlParser.cgd->dataExpr, pd->dataExpr );
1090         }
1091         
1092 #if 0
1093         writeExports();
1094         
1095         writeMachine();
1096
1097         out <<
1098                 "</ragel_def>\n";
1099 #endif
1100 }
1101
1102