All machine instantiations are now implicitly referenced and always generated,
[external/ragel.git] / ragel / xmlcodegen.cpp
1 /*
2  *  Copyright 2005, 2006 Adrian Thurston <thurston@cs.queensu.ca>
3  */
4
5 /*  This file is part of Ragel.
6  *
7  *  Ragel is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  * 
12  *  Ragel is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  * 
17  *  You should have received a copy of the GNU General Public License
18  *  along with Ragel; if not, write to the Free Software
19  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
20  */
21
22
23 #include "ragel.h"
24 #include "xmlcodegen.h"
25 #include "parsedata.h"
26 #include "fsmgraph.h"
27 #include <string.h>
28
29 using namespace std;
30
31 XMLCodeGen::XMLCodeGen( char *fsmName, ParseData *pd, FsmAp *fsm, 
32                 std::ostream &out )
33 :
34         fsmName(fsmName),
35         pd(pd),
36         fsm(fsm),
37         out(out),
38         nextActionTableId(0)
39 {
40 }
41
42
43 void XMLCodeGen::writeActionList()
44 {
45         /* Determine which actions to write. */
46         int nextActionId = 0;
47         for ( ActionList::Iter act = pd->actionList; act.lte(); act++ ) {
48                 if ( act->numRefs() > 0 || act->numCondRefs > 0 )
49                         act->actionId = nextActionId++;
50         }
51
52         /* Write the list. */
53         out << "    <action_list length=\"" << nextActionId << "\">\n";
54         for ( ActionList::Iter act = pd->actionList; act.lte(); act++ ) {
55                 if ( act->actionId >= 0 )
56                         writeAction( act );
57         }
58         out << "    </action_list>\n";
59 }
60
61 void XMLCodeGen::writeActionTableList()
62 {
63         /* Must first order the action tables based on their id. */
64         int numTables = nextActionTableId;
65         RedActionTable **tables = new RedActionTable*[numTables];
66         for ( ActionTableMap::Iter at = actionTableMap; at.lte(); at++ )
67                 tables[at->id] = at;
68
69         out << "    <action_table_list length=\"" << numTables << "\">\n";
70         for ( int t = 0; t < numTables; t++ ) {
71                 out << "      <action_table id=\"" << t << "\" length=\"" << 
72                                 tables[t]->key.length() << "\">";
73                 for ( ActionTable::Iter atel = tables[t]->key; atel.lte(); atel++ ) {
74                         out << atel->value->actionId;
75                         if ( ! atel.last() )
76                                 out << " ";
77                 }
78                 out << "</action_table>\n";
79         }
80         out << "    </action_table_list>\n";
81
82         delete[] tables;
83 }
84
85 void XMLCodeGen::reduceActionTables()
86 {
87         /* Reduce the actions tables to a set. */
88         for ( StateList::Iter st = fsm->stateList; st.lte(); st++ ) {
89                 RedActionTable *actionTable = 0;
90
91                 /* Reduce To State Actions. */
92                 if ( st->toStateActionTable.length() > 0 ) {
93                         if ( actionTableMap.insert( st->toStateActionTable, &actionTable ) )
94                                 actionTable->id = nextActionTableId++;
95                 }
96
97                 /* Reduce From State Actions. */
98                 if ( st->fromStateActionTable.length() > 0 ) {
99                         if ( actionTableMap.insert( st->fromStateActionTable, &actionTable ) )
100                                 actionTable->id = nextActionTableId++;
101                 }
102
103                 /* Reduce EOF actions. */
104                 if ( st->eofActionTable.length() > 0 ) {
105                         if ( actionTableMap.insert( st->eofActionTable, &actionTable ) )
106                                 actionTable->id = nextActionTableId++;
107                 }
108
109                 /* Loop the transitions and reduce their actions. */
110                 for ( TransList::Iter trans = st->outList; trans.lte(); trans++ ) {
111                         if ( trans->actionTable.length() > 0 ) {
112                                 if ( actionTableMap.insert( trans->actionTable, &actionTable ) )
113                                         actionTable->id = nextActionTableId++;
114                         }
115                 }
116         }
117 }
118
119 void XMLCodeGen::appendTrans( TransListVect &outList, Key lowKey, 
120                 Key highKey, TransAp *trans )
121 {
122         if ( trans->toState != 0 || trans->actionTable.length() > 0 )
123                 outList.append( TransEl( lowKey, highKey, trans ) );
124 }
125
126 void XMLCodeGen::writeKey( Key key )
127 {
128         if ( keyOps->isSigned )
129                 out << key.getVal();
130         else
131                 out << (unsigned long) key.getVal();
132 }
133
134 void XMLCodeGen::writeTrans( Key lowKey, Key highKey, TransAp *trans )
135 {
136         /* First reduce the action. */
137         RedActionTable *actionTable = 0;
138         if ( trans->actionTable.length() > 0 )
139                 actionTable = actionTableMap.find( trans->actionTable );
140
141         /* Write the transition. */
142         out << "        <t>";
143         writeKey( lowKey );
144         out << " ";
145         writeKey( highKey );
146
147         if ( trans->toState != 0 )
148                 out << " " << trans->toState->alg.stateNum;
149         else
150                 out << " x";
151
152         if ( actionTable != 0 )
153                 out << " " << actionTable->id;
154         else
155                 out << " x";
156         out << "</t>\n";
157 }
158
159 void XMLCodeGen::writeTransList( StateAp *state )
160 {
161         TransListVect outList;
162
163         /* If there is only are no ranges the task is simple. */
164         if ( state->outList.length() > 0 ) {
165                 /* Loop each source range. */
166                 for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) {
167                         /* Reduce the transition. If it reduced to anything then add it. */
168                         appendTrans( outList, trans->lowKey, trans->highKey, trans );
169                 }
170         }
171
172         out << "      <trans_list length=\"" << outList.length() << "\">\n";
173         for ( TransListVect::Iter tvi = outList; tvi.lte(); tvi++ )
174                 writeTrans( tvi->lowKey, tvi->highKey, tvi->value );
175         out << "      </trans_list>\n";
176 }
177
178 void XMLCodeGen::writeLmSwitch( InlineItem *item )
179 {
180         LongestMatch *longestMatch = item->longestMatch;
181
182         out << "<lm_switch";
183         if ( longestMatch->lmSwitchHandlesError )
184                 out << " handles_error=\"t\"";
185         out << ">\n";
186         
187         for ( LmPartList::Iter lmi = *longestMatch->longestMatchList; lmi.lte(); lmi++ ) {
188                 if ( lmi->inLmSelect && lmi->action != 0 ) {
189                         /* Open the action. Write it with the context that sets up _p 
190                          * when doing control flow changes from inside the machine. */
191                         out << "      <sub_action id=\"" << lmi->longestMatchId << "\">";
192                         writeInlineList( lmi->action->inlineList, item );
193                         out << "</sub_action>\n";
194                 }
195         }
196
197         out << "    </lm_switch><exec><get_tokend></get_tokend></exec>";
198 }
199
200 void XMLCodeGen::writeText( InlineItem *item )
201 {
202         if ( item->prev == 0 || item->prev->type != InlineItem::Text )
203                 out << "<text>";
204         xmlEscapeHost( out, item->data, strlen(item->data) );
205         if ( item->next == 0 || item->next->type != InlineItem::Text )
206                 out << "</text>";
207 }
208
209 void XMLCodeGen::writeCtrlFlow( InlineItem *item, InlineItem *context )
210 {
211         if ( context != 0 ) {
212                 out << "<sub_action>";
213
214                 switch ( context->type ) {
215                 case InlineItem::LmOnLast:
216                         out << "<exec><get_tokend></get_tokend></exec>";
217                         break;
218                 case InlineItem::LmOnNext:
219                         out << "<exec><get_tokend></get_tokend></exec>";
220                         break;
221                 case InlineItem::LmOnLagBehind:
222                         out << "<exec><get_tokend></get_tokend></exec>";
223                         break;
224                 case InlineItem::LmSwitch:
225                         out << "<exec><get_tokend></get_tokend></exec>";
226                         break;
227                 default: break;
228                 }
229         }
230
231         switch ( item->type ) {
232         case InlineItem::Goto:
233                 writeGoto( item, context );
234                 break;
235         case InlineItem::GotoExpr:
236                 writeGotoExpr( item, context );
237                 break;
238         case InlineItem::Call:
239                 writeCall( item, context );
240                 break;
241         case InlineItem::CallExpr:
242                 writeCallExpr( item, context );
243                 break;
244         case InlineItem::Next:
245                 writeNext( item, context );
246                 break;
247         case InlineItem::NextExpr:
248                 writeNextExpr( item, context );
249                 break;
250         case InlineItem::Break:
251                 out << "<break></break>";
252                 break;
253         case InlineItem::Ret: 
254                 out << "<ret></ret>";
255                 break;
256         default: break;
257         }
258
259         if ( context != 0 )
260                 out << "</sub_action>";
261 }
262
263 void XMLCodeGen::writePtrMod( InlineItem *item, InlineItem *context )
264 {
265         if ( context != 0 && ( context->type == InlineItem::LmOnNext ||
266                         context->type == InlineItem::LmOnLagBehind ||
267                         context->type == InlineItem::LmSwitch ) )
268         {
269                 switch ( item->type ) {
270                 case InlineItem::Hold:
271                         out << "<holdte></holdte>";
272                         break;
273                 case InlineItem::Exec:
274                         writeActionExecTE( item );
275                         break;
276                 default: break;
277                 }
278         }
279         else {
280                 switch ( item->type ) {
281                 case InlineItem::Hold:
282                         out << "<hold></hold>";
283                         break;
284                 case InlineItem::Exec:
285                         writeActionExec( item );
286                         break;
287                 default: break;
288                 }
289         }
290 }
291
292
293 void XMLCodeGen::writeGoto( InlineItem *item, InlineItem *context )
294 {
295         if ( pd->generatingSectionSubset )
296                 out << "<goto>-1</goto>";
297         else {
298                 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
299                 out << "<goto>" << targ->value->alg.stateNum << "</goto>";
300         }
301 }
302
303 void XMLCodeGen::writeCall( InlineItem *item, InlineItem *context )
304 {
305         if ( pd->generatingSectionSubset )
306                 out << "<call>-1</call>";
307         else {
308                 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
309                 out << "<call>" << targ->value->alg.stateNum << "</call>";
310         }
311 }
312
313 void XMLCodeGen::writeNext( InlineItem *item, InlineItem *context )
314 {
315         if ( pd->generatingSectionSubset )
316                 out << "<next>-1</next>";
317         else {
318                 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
319                 out << "<next>" << targ->value->alg.stateNum << "</next>";
320         }
321 }
322
323 void XMLCodeGen::writeGotoExpr( InlineItem *item, InlineItem *context )
324 {
325         out << "<goto_expr>";
326         writeInlineList( item->children, 0 );
327         out << "</goto_expr>";
328 }
329
330 void XMLCodeGen::writeCallExpr( InlineItem *item, InlineItem *context )
331 {
332         out << "<call_expr>";
333         writeInlineList( item->children, 0 );
334         out << "</call_expr>";
335 }
336
337 void XMLCodeGen::writeNextExpr( InlineItem *item, InlineItem *context )
338 {
339         out << "<next_expr>";
340         writeInlineList( item->children, 0 );
341         out << "</next_expr>";
342 }
343
344 void XMLCodeGen::writeEntry( InlineItem * item )
345 {
346         if ( pd->generatingSectionSubset )
347                 out << "<entry>-1</entry>";
348         else {
349                 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
350                 out << "<entry>" << targ->value->alg.stateNum << "</entry>";
351         }
352 }
353
354 void XMLCodeGen::writeActionExec( InlineItem *item )
355 {
356         out << "<exec>";
357         writeInlineList( item->children, 0 );
358         out << "</exec>";
359 }
360
361 void XMLCodeGen::writeActionExecTE( InlineItem *item )
362 {
363         out << "<execte>";
364         writeInlineList( item->children, 0 );
365         out << "</execte>";
366 }
367
368 void XMLCodeGen::writeLmOnLast( InlineItem *item )
369 {
370         out << "<set_tokend>1</set_tokend>";
371         if ( item->longestMatchPart->action != 0 ) {
372                 out << "<sub_action>";
373                 writeInlineList( item->longestMatchPart->action->inlineList, item );
374                 out << "</sub_action>";
375         }
376         out << "<exec><get_tokend></get_tokend></exec>";
377 }
378
379 void XMLCodeGen::writeLmOnNext( InlineItem *item )
380 {
381         out << "<set_tokend>0</set_tokend>";
382         if ( item->longestMatchPart->action != 0 ) {
383                 out << "<sub_action>";
384                 writeInlineList( item->longestMatchPart->action->inlineList, item );
385                 out << "</sub_action>";
386         }
387         out << "<exec><get_tokend></get_tokend></exec>";
388 }
389
390 void XMLCodeGen::writeLmOnLagBehind( InlineItem *item )
391 {
392         if ( item->longestMatchPart->action != 0 ) {
393                 out << "<sub_action>";
394                 writeInlineList( item->longestMatchPart->action->inlineList, item );
395                 out << "</sub_action>";
396         }
397         out << "<exec><get_tokend></get_tokend></exec>";
398 }
399
400
401 void XMLCodeGen::writeInlineList( InlineList *inlineList, InlineItem *context )
402 {
403         for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
404                 switch ( item->type ) {
405                 case InlineItem::Text:
406                         writeText( item );
407                         break;
408                 case InlineItem::Goto: case InlineItem::GotoExpr:
409                 case InlineItem::Call: case InlineItem::CallExpr:
410                 case InlineItem::Next: case InlineItem::NextExpr:
411                 case InlineItem::Break: case InlineItem::Ret: 
412                         writeCtrlFlow( item, context );
413                         break;
414                 case InlineItem::PChar:
415                         out << "<pchar></pchar>";
416                         break;
417                 case InlineItem::Char: 
418                         out << "<char></char>";
419                         break;
420                 case InlineItem::Curs: 
421                         out << "<curs></curs>";
422                         break;
423                 case InlineItem::Targs: 
424                         out << "<targs></targs>";
425                         break;
426                 case InlineItem::Entry:
427                         writeEntry( item );
428                         break;
429
430                 case InlineItem::Hold:
431                 case InlineItem::Exec:
432                         writePtrMod( item, context );
433                         break;
434
435                 case InlineItem::LmSwitch: 
436                         writeLmSwitch( item );
437                         break;
438                 case InlineItem::LmSetActId:
439                         out << "<set_act>" << 
440                                         item->longestMatchPart->longestMatchId << 
441                                         "</set_act>";
442                         break;
443                 case InlineItem::LmSetTokEnd:
444                         out << "<set_tokend>1</set_tokend>";
445                         break;
446                 case InlineItem::LmOnLast:
447                         writeLmOnLast( item );
448                         break;
449                 case InlineItem::LmOnNext:
450                         writeLmOnNext( item );
451                         break;
452                 case InlineItem::LmOnLagBehind:
453                         writeLmOnLagBehind( item );
454                         break;
455                 case InlineItem::LmInitAct:
456                         out << "<init_act></init_act>";
457                         break;
458                 case InlineItem::LmInitTokStart:
459                         out << "<init_tokstart></init_tokstart>";
460                         break;
461                 case InlineItem::LmSetTokStart:
462                         out << "<set_tokstart></set_tokstart>";
463                         break;
464                 }
465         }
466 }
467
468 void XMLCodeGen::writeAction( Action *action )
469 {
470         out << "      <action id=\"" << action->actionId << "\"";
471         if ( action->name != 0 ) 
472                 out << " name=\"" << action->name << "\"";
473         out << " line=\"" << action->loc.line << "\" col=\"" << action->loc.col << "\">";
474         writeInlineList( action->inlineList, 0 );
475         out << "</action>\n";
476 }
477
478 void xmlEscapeHost( std::ostream &out, char *data, int len )
479 {
480         char *end = data + len;
481         while ( data != end ) {
482                 switch ( *data ) {
483                 case '<': out << "&lt;"; break;
484                 case '>': out << "&gt;"; break;
485                 case '&': out << "&amp;"; break;
486                 default: out << *data; break;
487                 }
488                 data += 1;
489         }
490 }
491
492 void XMLCodeGen::writeStateActions( StateAp *state )
493 {
494         RedActionTable *toStateActions = 0;
495         if ( state->toStateActionTable.length() > 0 )
496                 toStateActions = actionTableMap.find( state->toStateActionTable );
497
498         RedActionTable *fromStateActions = 0;
499         if ( state->fromStateActionTable.length() > 0 )
500                 fromStateActions = actionTableMap.find( state->fromStateActionTable );
501
502         RedActionTable *eofActions = 0;
503         if ( state->eofActionTable.length() > 0 )
504                 eofActions = actionTableMap.find( state->eofActionTable );
505         
506         if ( toStateActions != 0 || fromStateActions != 0 || eofActions != 0 ) {
507                 out << "      <state_actions>";
508                 if ( toStateActions != 0 )
509                         out << toStateActions->id;
510                 else
511                         out << "x";
512
513                 if ( fromStateActions != 0 )
514                         out << " " << fromStateActions->id;
515                 else
516                         out << " x";
517
518                 if ( eofActions != 0 )
519                         out << " " << eofActions->id;
520                 else
521                         out << " x"; out << "</state_actions>\n";
522         }
523 }
524
525 void XMLCodeGen::writeStateConditions( StateAp *state )
526 {
527         if ( state->stateCondList.length() > 0 ) {
528                 out << "      <cond_list length=\"" << state->stateCondList.length() << "\">\n";
529                 for ( StateCondList::Iter scdi = state->stateCondList; scdi.lte(); scdi++ ) {
530                         out << "        <c>";
531                         writeKey( scdi->lowKey );
532                         out << " ";
533                         writeKey( scdi->highKey );
534                         out << " ";
535                         out << scdi->condSpace->condSpaceId;
536                         out << "</c>\n";
537                 }
538                 out << "      </cond_list>\n";
539         }
540 }
541
542 void XMLCodeGen::writeStateList()
543 {
544         /* Write the list of states. */
545         out << "    <state_list length=\"" << fsm->stateList.length() << "\">\n";
546         for ( StateList::Iter st = fsm->stateList; st.lte(); st++ ) {
547                 out << "      <state id=\"" << st->alg.stateNum << "\"";
548                 if ( st->isFinState() )
549                         out << " final=\"t\"";
550                 out << ">\n";
551
552                 writeStateActions( st );
553                 writeStateConditions( st );
554                 writeTransList( st );
555
556                 out << "      </state>\n";
557
558                 if ( !st.last() )
559                         out << "\n";
560         }
561         out << "    </state_list>\n";
562 }
563
564 bool XMLCodeGen::writeNameInst( NameInst *nameInst )
565 {
566         bool written = false;
567         if ( nameInst->parent != 0 )
568                 written = writeNameInst( nameInst->parent );
569         
570         if ( nameInst->name != 0 ) {
571                 if ( written )
572                         out << '_';
573                 out << nameInst->name;
574                 written = true;
575         }
576
577         return written;
578 }
579
580 void XMLCodeGen::writeEntryPoints()
581 {
582         /* List of entry points other than start state. */
583         if ( fsm->entryPoints.length() > 0 || pd->lmRequiresErrorState ) {
584                 out << "    <entry_points";
585                 if ( pd->lmRequiresErrorState )
586                         out << " error=\"t\"";
587                 out << ">\n";
588                 for ( EntryMap::Iter en = fsm->entryPoints; en.lte(); en++ ) {
589                         /* Get the name instantiation from nameIndex. */
590                         NameInst *nameInst = pd->nameIndex[en->key];
591                         StateAp *state = en->value;
592                         out << "      <entry name=\"";
593                         writeNameInst( nameInst );
594                         out << "\">" << state->alg.stateNum << "</entry>\n";
595                 }
596                 out << "    </entry_points>\n";
597         }
598 }
599
600 void XMLCodeGen::writeMachine()
601 {
602         /* Open the machine. */
603         out << "  <machine>\n"; 
604         
605         /* Action tables. */
606         reduceActionTables();
607
608         writeActionList();
609         writeActionTableList();
610         writeConditions();
611
612         /* Start state. */
613         out << "    <start_state>" << fsm->startState->alg.stateNum << 
614                 "</start_state>\n";
615         
616         /* Error state. */
617         if ( fsm->errState != 0 ) {
618                 out << "    <error_state>" << fsm->errState->alg.stateNum << 
619                         "</error_state>\n";
620         }
621
622         writeEntryPoints();
623         writeStateList();
624
625         out << "  </machine>\n";
626 }
627
628 void XMLCodeGen::writeAlphType()
629 {
630         out << "  <alphtype>" << 
631                 (keyOps->alphType - hostLang->hostTypes) << "</alphtype>\n";
632 }
633
634 void XMLCodeGen::writeGetKeyExpr()
635 {
636         out << "  <getkey>";
637         writeInlineList( pd->getKeyExpr, 0 );
638         out << "</getkey>\n";
639 }
640
641 void XMLCodeGen::writeAccessExpr()
642 {
643         out << "  <access>";
644         writeInlineList( pd->accessExpr, 0 );
645         out << "</access>\n";
646 }
647
648 void XMLCodeGen::writeCurStateExpr()
649 {
650         out << "  <curstate>";
651         writeInlineList( pd->curStateExpr, 0 );
652         out << "</curstate>\n";
653 }
654
655 void XMLCodeGen::writeConditions()
656 {
657         if ( condData->condSpaceMap.length() > 0 ) {
658                 long nextCondSpaceId = 0;
659                 for ( CondSpaceMap::Iter cs = condData->condSpaceMap; cs.lte(); cs++ )
660                         cs->condSpaceId = nextCondSpaceId++;
661
662                 out << "    <cond_space_list length=\"" << condData->condSpaceMap.length() << "\">\n";
663                 for ( CondSpaceMap::Iter cs = condData->condSpaceMap; cs.lte(); cs++ ) {
664                         out << "      <cond_space id=\"" << cs->condSpaceId << 
665                                 "\" length=\"" << cs->condSet.length() << "\">";
666                         writeKey( cs->baseKey );
667                         for ( CondSet::Iter csi = cs->condSet; csi.lte(); csi++ )
668                                 out << " " << (*csi)->actionId;
669                         out << "</cond_space>\n";
670                 }
671                 out << "    </cond_space_list>\n";
672         }
673 }
674
675 void XMLCodeGen::writeExports()
676 {
677         if ( pd->exportList.length() > 0 ) {
678                 out << "  <exports>\n";
679                 for ( ExportList::Iter exp = pd->exportList; exp.lte(); exp++ ) {
680                         out << "    <ex name=\"" << exp->name << "\">";
681                         writeKey( exp->key );
682                         out << "</ex>\n";
683                 }
684                 out << "  </exports>\n";
685         }
686 }
687
688 void XMLCodeGen::writeXML()
689 {
690         /* Open the definition. */
691         out << "<ragel_def name=\"" << fsmName << "\">\n";
692         writeAlphType();
693         
694         if ( pd->getKeyExpr != 0 )
695                 writeGetKeyExpr();
696
697         if ( pd->accessExpr != 0 )
698                 writeAccessExpr();
699
700         if ( pd->curStateExpr != 0 )
701                 writeCurStateExpr();
702         
703         writeExports();
704         
705         writeMachine();
706
707         out <<
708                 "</ragel_def>\n";
709 }
710