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