The p varialbe is now set up at the beginning of a scanner action, rather than
[external/ragel.git] / ragel / xmlcodegen.cpp
1 /*
2  *  Copyright 2005-2007 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::writeText( InlineItem *item )
179 {
180         if ( item->prev == 0 || item->prev->type != InlineItem::Text )
181                 out << "<text>";
182         xmlEscapeHost( out, item->data, strlen(item->data) );
183         if ( item->next == 0 || item->next->type != InlineItem::Text )
184                 out << "</text>";
185 }
186
187 bool isLmItem( InlineItem *context )
188 {
189         return context != 0 && (
190                 context->type == InlineItem::LmOnLast ||
191                 context->type == InlineItem::LmOnNext ||
192                 context->type == InlineItem::LmOnLagBehind ||
193                 context->type == InlineItem::LmSwitch );
194 }
195
196 void XMLCodeGen::writeCtrlFlow( InlineItem *item, InlineItem *context )
197 {
198         switch ( item->type ) {
199         case InlineItem::Goto:
200                 writeGoto( item, context );
201                 break;
202         case InlineItem::GotoExpr:
203                 writeGotoExpr( item, context );
204                 break;
205         case InlineItem::Call:
206                 writeCall( item, context );
207                 break;
208         case InlineItem::CallExpr:
209                 writeCallExpr( item, context );
210                 break;
211         case InlineItem::Next:
212                 writeNext( item, context );
213                 break;
214         case InlineItem::NextExpr:
215                 writeNextExpr( item, context );
216                 break;
217         case InlineItem::Break:
218                 out << "<break></break>";
219                 break;
220         case InlineItem::Ret: 
221                 out << "<ret></ret>";
222                 break;
223         default: break;
224         }
225 }
226
227 void XMLCodeGen::writePtrMod( InlineItem *item, InlineItem * )
228 {
229         switch ( item->type ) {
230         case InlineItem::Hold:
231                 out << "<hold></hold>";
232                 break;
233         case InlineItem::Exec:
234                 writeActionExec( item );
235                 break;
236         default: break;
237         }
238 }
239
240
241 void XMLCodeGen::writeGoto( InlineItem *item, InlineItem *context )
242 {
243         if ( pd->generatingSectionSubset )
244                 out << "<goto>-1</goto>";
245         else {
246                 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
247                 out << "<goto>" << targ->value->alg.stateNum << "</goto>";
248         }
249 }
250
251 void XMLCodeGen::writeCall( InlineItem *item, InlineItem *context )
252 {
253         if ( pd->generatingSectionSubset )
254                 out << "<call>-1</call>";
255         else {
256                 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
257                 out << "<call>" << targ->value->alg.stateNum << "</call>";
258         }
259 }
260
261 void XMLCodeGen::writeNext( InlineItem *item, InlineItem *context )
262 {
263         if ( pd->generatingSectionSubset )
264                 out << "<next>-1</next>";
265         else {
266                 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
267                 out << "<next>" << targ->value->alg.stateNum << "</next>";
268         }
269 }
270
271 void XMLCodeGen::writeGotoExpr( InlineItem *item, InlineItem *context )
272 {
273         out << "<goto_expr>";
274         writeInlineList( item->children, 0 );
275         out << "</goto_expr>";
276 }
277
278 void XMLCodeGen::writeCallExpr( InlineItem *item, InlineItem *context )
279 {
280         out << "<call_expr>";
281         writeInlineList( item->children, 0 );
282         out << "</call_expr>";
283 }
284
285 void XMLCodeGen::writeNextExpr( InlineItem *item, InlineItem *context )
286 {
287         out << "<next_expr>";
288         writeInlineList( item->children, 0 );
289         out << "</next_expr>";
290 }
291
292 void XMLCodeGen::writeEntry( InlineItem * item )
293 {
294         if ( pd->generatingSectionSubset )
295                 out << "<entry>-1</entry>";
296         else {
297                 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
298                 out << "<entry>" << targ->value->alg.stateNum << "</entry>";
299         }
300 }
301
302 void XMLCodeGen::writeActionExec( InlineItem *item )
303 {
304         out << "<exec>";
305         writeInlineList( item->children, 0 );
306         out << "</exec>";
307 }
308
309 void XMLCodeGen::writeActionExecTE( InlineItem *item )
310 {
311         out << "<execte>";
312         writeInlineList( item->children, 0 );
313         out << "</execte>";
314 }
315
316 void XMLCodeGen::writeLmOnLast( InlineItem *item )
317 {
318         out << "<set_tokend>1</set_tokend>";
319
320         if ( item->longestMatchPart->action != 0 ) {
321                 out << "<sub_action>";
322                 writeInlineList( item->longestMatchPart->action->inlineList, item );
323                 out << "</sub_action>";
324         }
325 }
326
327 void XMLCodeGen::writeLmOnNext( InlineItem *item )
328 {
329         out << "<set_tokend>0</set_tokend>";
330         out << "<hold></hold>";
331
332         if ( item->longestMatchPart->action != 0 ) {
333                 out << "<sub_action>";
334                 writeInlineList( item->longestMatchPart->action->inlineList, item );
335                 out << "</sub_action>";
336         }
337 }
338
339 void XMLCodeGen::writeLmOnLagBehind( InlineItem *item )
340 {
341         out << "<exec><get_tokend></get_tokend></exec>";
342
343         if ( item->longestMatchPart->action != 0 ) {
344                 out << "<sub_action>";
345                 writeInlineList( item->longestMatchPart->action->inlineList, item );
346                 out << "</sub_action>";
347         }
348 }
349
350 void XMLCodeGen::writeLmSwitch( InlineItem *item )
351 {
352
353         LongestMatch *longestMatch = item->longestMatch;
354         out << "<lm_switch>\n";
355
356         if ( longestMatch->lmSwitchHandlesError ) {
357                 /* If the switch handles error then we should have also forced the
358                  * error state. */
359                 assert( fsm->errState != 0 );
360
361                 out << "      <sub_action id=\"0\">";
362                 out << "<goto>" << fsm->errState->alg.stateNum << "</goto>";
363                 out << "</sub_action>\n";
364         }
365         
366         for ( LmPartList::Iter lmi = *longestMatch->longestMatchList; lmi.lte(); lmi++ ) {
367                 if ( lmi->inLmSelect && lmi->action != 0 ) {
368                         /* Open the action. Write it with the context that sets up _p 
369                          * when doing control flow changes from inside the machine. */
370                         out << "      <sub_action id=\"" << lmi->longestMatchId << "\">";
371                         out << "<exec><get_tokend></get_tokend></exec>";
372                         writeInlineList( lmi->action->inlineList, item );
373                         out << "</sub_action>\n";
374                 }
375         }
376
377         out << "    </lm_switch>";
378 }
379
380 void XMLCodeGen::writeInlineList( InlineList *inlineList, InlineItem *context )
381 {
382         for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
383                 switch ( item->type ) {
384                 case InlineItem::Text:
385                         writeText( item );
386                         break;
387                 case InlineItem::Goto: case InlineItem::GotoExpr:
388                 case InlineItem::Call: case InlineItem::CallExpr:
389                 case InlineItem::Next: case InlineItem::NextExpr:
390                 case InlineItem::Break: case InlineItem::Ret: 
391                         writeCtrlFlow( item, context );
392                         break;
393                 case InlineItem::PChar:
394                         out << "<pchar></pchar>";
395                         break;
396                 case InlineItem::Char: 
397                         out << "<char></char>";
398                         break;
399                 case InlineItem::Curs: 
400                         out << "<curs></curs>";
401                         break;
402                 case InlineItem::Targs: 
403                         out << "<targs></targs>";
404                         break;
405                 case InlineItem::Entry:
406                         writeEntry( item );
407                         break;
408
409                 case InlineItem::Hold:
410                 case InlineItem::Exec:
411                         writePtrMod( item, context );
412                         break;
413
414                 case InlineItem::LmSetActId:
415                         out << "<set_act>" << 
416                                         item->longestMatchPart->longestMatchId << 
417                                         "</set_act>";
418                         break;
419                 case InlineItem::LmSetTokEnd:
420                         out << "<set_tokend>1</set_tokend>";
421                         break;
422
423                 case InlineItem::LmOnLast:
424                         writeLmOnLast( item );
425                         break;
426                 case InlineItem::LmOnNext:
427                         writeLmOnNext( item );
428                         break;
429                 case InlineItem::LmOnLagBehind:
430                         writeLmOnLagBehind( item );
431                         break;
432                 case InlineItem::LmSwitch: 
433                         writeLmSwitch( item );
434                         break;
435
436                 case InlineItem::LmInitAct:
437                         out << "<init_act></init_act>";
438                         break;
439                 case InlineItem::LmInitTokStart:
440                         out << "<init_tokstart></init_tokstart>";
441                         break;
442                 case InlineItem::LmSetTokStart:
443                         out << "<set_tokstart></set_tokstart>";
444                         break;
445                 }
446         }
447 }
448
449 void XMLCodeGen::writeAction( Action *action )
450 {
451         out << "      <action id=\"" << action->actionId << "\"";
452         if ( action->name != 0 ) 
453                 out << " name=\"" << action->name << "\"";
454         out << " line=\"" << action->loc.line << "\" col=\"" << action->loc.col << "\">";
455         writeInlineList( action->inlineList, 0 );
456         out << "</action>\n";
457 }
458
459 void xmlEscapeHost( std::ostream &out, char *data, long len )
460 {
461         char *end = data + len;
462         while ( data != end ) {
463                 switch ( *data ) {
464                 case '<': out << "&lt;"; break;
465                 case '>': out << "&gt;"; break;
466                 case '&': out << "&amp;"; break;
467                 default: out << *data; break;
468                 }
469                 data += 1;
470         }
471 }
472
473 void XMLCodeGen::writeStateActions( StateAp *state )
474 {
475         RedActionTable *toStateActions = 0;
476         if ( state->toStateActionTable.length() > 0 )
477                 toStateActions = actionTableMap.find( state->toStateActionTable );
478
479         RedActionTable *fromStateActions = 0;
480         if ( state->fromStateActionTable.length() > 0 )
481                 fromStateActions = actionTableMap.find( state->fromStateActionTable );
482
483         RedActionTable *eofActions = 0;
484         if ( state->eofActionTable.length() > 0 )
485                 eofActions = actionTableMap.find( state->eofActionTable );
486         
487         if ( toStateActions != 0 || fromStateActions != 0 || eofActions != 0 ) {
488                 out << "      <state_actions>";
489                 if ( toStateActions != 0 )
490                         out << toStateActions->id;
491                 else
492                         out << "x";
493
494                 if ( fromStateActions != 0 )
495                         out << " " << fromStateActions->id;
496                 else
497                         out << " x";
498
499                 if ( eofActions != 0 )
500                         out << " " << eofActions->id;
501                 else
502                         out << " x"; out << "</state_actions>\n";
503         }
504 }
505
506 void XMLCodeGen::writeStateConditions( StateAp *state )
507 {
508         if ( state->stateCondList.length() > 0 ) {
509                 out << "      <cond_list length=\"" << state->stateCondList.length() << "\">\n";
510                 for ( StateCondList::Iter scdi = state->stateCondList; scdi.lte(); scdi++ ) {
511                         out << "        <c>";
512                         writeKey( scdi->lowKey );
513                         out << " ";
514                         writeKey( scdi->highKey );
515                         out << " ";
516                         out << scdi->condSpace->condSpaceId;
517                         out << "</c>\n";
518                 }
519                 out << "      </cond_list>\n";
520         }
521 }
522
523 void XMLCodeGen::writeStateList()
524 {
525         /* Write the list of states. */
526         out << "    <state_list length=\"" << fsm->stateList.length() << "\">\n";
527         for ( StateList::Iter st = fsm->stateList; st.lte(); st++ ) {
528                 out << "      <state id=\"" << st->alg.stateNum << "\"";
529                 if ( st->isFinState() )
530                         out << " final=\"t\"";
531                 out << ">\n";
532
533                 writeStateActions( st );
534                 writeStateConditions( st );
535                 writeTransList( st );
536
537                 out << "      </state>\n";
538
539                 if ( !st.last() )
540                         out << "\n";
541         }
542         out << "    </state_list>\n";
543 }
544
545 bool XMLCodeGen::writeNameInst( NameInst *nameInst )
546 {
547         bool written = false;
548         if ( nameInst->parent != 0 )
549                 written = writeNameInst( nameInst->parent );
550         
551         if ( nameInst->name != 0 ) {
552                 if ( written )
553                         out << '_';
554                 out << nameInst->name;
555                 written = true;
556         }
557
558         return written;
559 }
560
561 void XMLCodeGen::writeEntryPoints()
562 {
563         /* List of entry points other than start state. */
564         if ( fsm->entryPoints.length() > 0 || pd->lmRequiresErrorState ) {
565                 out << "    <entry_points";
566                 if ( pd->lmRequiresErrorState )
567                         out << " error=\"t\"";
568                 out << ">\n";
569                 for ( EntryMap::Iter en = fsm->entryPoints; en.lte(); en++ ) {
570                         /* Get the name instantiation from nameIndex. */
571                         NameInst *nameInst = pd->nameIndex[en->key];
572                         StateAp *state = en->value;
573                         out << "      <entry name=\"";
574                         writeNameInst( nameInst );
575                         out << "\">" << state->alg.stateNum << "</entry>\n";
576                 }
577                 out << "    </entry_points>\n";
578         }
579 }
580
581 void XMLCodeGen::writeMachine()
582 {
583         /* Open the machine. */
584         out << "  <machine>\n"; 
585         
586         /* Action tables. */
587         reduceActionTables();
588
589         writeActionList();
590         writeActionTableList();
591         writeConditions();
592
593         /* Start state. */
594         out << "    <start_state>" << fsm->startState->alg.stateNum << 
595                         "</start_state>\n";
596         
597         /* Error state. */
598         if ( fsm->errState != 0 ) {
599                 out << "    <error_state>" << fsm->errState->alg.stateNum << 
600                         "</error_state>\n";
601         }
602
603         writeEntryPoints();
604         writeStateList();
605
606         out << "  </machine>\n";
607 }
608
609
610 void XMLCodeGen::writeConditions()
611 {
612         if ( condData->condSpaceMap.length() > 0 ) {
613                 long nextCondSpaceId = 0;
614                 for ( CondSpaceMap::Iter cs = condData->condSpaceMap; cs.lte(); cs++ )
615                         cs->condSpaceId = nextCondSpaceId++;
616
617                 out << "    <cond_space_list length=\"" << condData->condSpaceMap.length() << "\">\n";
618                 for ( CondSpaceMap::Iter cs = condData->condSpaceMap; cs.lte(); cs++ ) {
619                         out << "      <cond_space id=\"" << cs->condSpaceId << 
620                                 "\" length=\"" << cs->condSet.length() << "\">";
621                         writeKey( cs->baseKey );
622                         for ( CondSet::Iter csi = cs->condSet; csi.lte(); csi++ )
623                                 out << " " << (*csi)->actionId;
624                         out << "</cond_space>\n";
625                 }
626                 out << "    </cond_space_list>\n";
627         }
628 }
629
630 void XMLCodeGen::writeExports()
631 {
632         if ( pd->exportList.length() > 0 ) {
633                 out << "  <exports>\n";
634                 for ( ExportList::Iter exp = pd->exportList; exp.lte(); exp++ ) {
635                         out << "    <ex name=\"" << exp->name << "\">";
636                         writeKey( exp->key );
637                         out << "</ex>\n";
638                 }
639                 out << "  </exports>\n";
640         }
641 }
642
643 void XMLCodeGen::writeXML()
644 {
645         /* Open the definition. */
646         out << "<ragel_def name=\"" << fsmName << "\">\n";
647
648         /* Alphabet type. */
649         out << "  <alphtype>" << keyOps->alphType->internalName << "</alphtype>\n";
650         
651         /* Getkey expression. */
652         if ( pd->getKeyExpr != 0 ) {
653                 out << "  <getkey>";
654                 writeInlineList( pd->getKeyExpr, 0 );
655                 out << "</getkey>\n";
656         }
657
658         /* Access expression. */
659         if ( pd->accessExpr != 0 ) {
660                 out << "  <access>";
661                 writeInlineList( pd->accessExpr, 0 );
662                 out << "</access>\n";
663         }
664
665         /*
666          * Variable expressions.
667          */
668
669         if ( pd->pExpr != 0 ) {
670                 out << "  <p_expr>";
671                 writeInlineList( pd->pExpr, 0 );
672                 out << "</p_expr>\n";
673         }
674         
675         if ( pd->peExpr != 0 ) {
676                 out << "  <pe_expr>";
677                 writeInlineList( pd->peExpr, 0 );
678                 out << "</pe_expr>\n";
679         }
680         
681         if ( pd->csExpr != 0 ) {
682                 out << "  <cs_expr>";
683                 writeInlineList( pd->csExpr, 0 );
684                 out << "</cs_expr>\n";
685         }
686         
687         if ( pd->topExpr != 0 ) {
688                 out << "  <top_expr>";
689                 writeInlineList( pd->topExpr, 0 );
690                 out << "</top_expr>\n";
691         }
692         
693         if ( pd->stackExpr != 0 ) {
694                 out << "  <stack_expr>";
695                 writeInlineList( pd->stackExpr, 0 );
696                 out << "</stack_expr>\n";
697         }
698         
699         if ( pd->actExpr != 0 ) {
700                 out << "  <act_expr>";
701                 writeInlineList( pd->actExpr, 0 );
702                 out << "</act_expr>\n";
703         }
704         
705         if ( pd->tokstartExpr != 0 ) {
706                 out << "  <tokstart_expr>";
707                 writeInlineList( pd->tokstartExpr, 0 );
708                 out << "</tokstart_expr>\n";
709         }
710         
711         if ( pd->tokendExpr != 0 ) {
712                 out << "  <tokend_expr>";
713                 writeInlineList( pd->tokendExpr, 0 );
714                 out << "</tokend_expr>\n";
715         }
716         
717         writeExports();
718         
719         writeMachine();
720
721         out <<
722                 "</ragel_def>\n";
723 }
724