2 * Copyright 2005, 2006 Adrian Thurston <thurston@cs.queensu.ca>
5 /* This file is part of Ragel.
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.
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.
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
24 #include "xmlcodegen.h"
25 #include "parsedata.h"
31 XMLCodeGen::XMLCodeGen( char *fsmName
, ParseData
*pd
, FsmAp
*fsm
,
43 void XMLCodeGen::writeActionList()
45 /* Determine which actions to write. */
47 for ( ActionList::Iter act
= pd
->actionList
; act
.lte(); act
++ ) {
48 if ( act
->numRefs() > 0 || act
->numCondRefs
> 0 )
49 act
->actionId
= nextActionId
++;
53 out
<< " <action_list length=\"" << nextActionId
<< "\">\n";
54 for ( ActionList::Iter act
= pd
->actionList
; act
.lte(); act
++ ) {
55 if ( act
->actionId
>= 0 )
58 out
<< " </action_list>\n";
61 void XMLCodeGen::writeActionTableList()
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
++ )
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
;
78 out
<< "</action_table>\n";
80 out
<< " </action_table_list>\n";
85 void XMLCodeGen::reduceActionTables()
87 /* Reduce the actions tables to a set. */
88 for ( StateList::Iter st
= fsm
->stateList
; st
.lte(); st
++ ) {
89 RedActionTable
*actionTable
= 0;
91 /* Reduce To State Actions. */
92 if ( st
->toStateActionTable
.length() > 0 ) {
93 if ( actionTableMap
.insert( st
->toStateActionTable
, &actionTable
) )
94 actionTable
->id
= nextActionTableId
++;
97 /* Reduce From State Actions. */
98 if ( st
->fromStateActionTable
.length() > 0 ) {
99 if ( actionTableMap
.insert( st
->fromStateActionTable
, &actionTable
) )
100 actionTable
->id
= nextActionTableId
++;
103 /* Reduce EOF actions. */
104 if ( st
->eofActionTable
.length() > 0 ) {
105 if ( actionTableMap
.insert( st
->eofActionTable
, &actionTable
) )
106 actionTable
->id
= nextActionTableId
++;
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
++;
119 void XMLCodeGen::appendTrans( TransListVect
&outList
, Key lowKey
,
120 Key highKey
, TransAp
*trans
)
122 if ( trans
->toState
!= 0 || trans
->actionTable
.length() > 0 )
123 outList
.append( TransEl( lowKey
, highKey
, trans
) );
126 void XMLCodeGen::writeKey( Key key
)
128 if ( keyOps
->isSigned
)
131 out
<< (unsigned long) key
.getVal();
134 void XMLCodeGen::writeTrans( Key lowKey
, Key highKey
, TransAp
*trans
)
136 /* First reduce the action. */
137 RedActionTable
*actionTable
= 0;
138 if ( trans
->actionTable
.length() > 0 )
139 actionTable
= actionTableMap
.find( trans
->actionTable
);
141 /* Write the transition. */
147 if ( trans
->toState
!= 0 )
148 out
<< " " << trans
->toState
->alg
.stateNum
;
152 if ( actionTable
!= 0 )
153 out
<< " " << actionTable
->id
;
159 void XMLCodeGen::writeTransList( StateAp
*state
)
161 TransListVect outList
;
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
);
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";
178 void XMLCodeGen::writeLmSwitch( InlineItem
*item
)
180 LongestMatch
*longestMatch
= item
->longestMatch
;
183 if ( longestMatch
->lmSwitchHandlesError
)
184 out
<< " handles_error=\"t\"";
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";
197 out
<< " </lm_switch><exec><get_tokend></get_tokend></exec>";
200 void XMLCodeGen::writeText( InlineItem
*item
)
202 if ( item
->prev
== 0 || item
->prev
->type
!= InlineItem::Text
)
204 xmlEscapeHost( out
, item
->data
, strlen(item
->data
) );
205 if ( item
->next
== 0 || item
->next
->type
!= InlineItem::Text
)
209 void XMLCodeGen::writeCtrlFlow( InlineItem
*item
, InlineItem
*context
)
211 if ( context
!= 0 ) {
212 out
<< "<sub_action>";
214 switch ( context
->type
) {
215 case InlineItem::LmOnLast
:
216 out
<< "<exec><get_tokend></get_tokend></exec>";
218 case InlineItem::LmOnNext
:
219 out
<< "<exec><get_tokend></get_tokend></exec>";
221 case InlineItem::LmOnLagBehind
:
222 out
<< "<exec><get_tokend></get_tokend></exec>";
224 case InlineItem::LmSwitch
:
225 out
<< "<exec><get_tokend></get_tokend></exec>";
231 switch ( item
->type
) {
232 case InlineItem::Goto
:
233 writeGoto( item
, context
);
235 case InlineItem::GotoExpr
:
236 writeGotoExpr( item
, context
);
238 case InlineItem::Call
:
239 writeCall( item
, context
);
241 case InlineItem::CallExpr
:
242 writeCallExpr( item
, context
);
244 case InlineItem::Next
:
245 writeNext( item
, context
);
247 case InlineItem::NextExpr
:
248 writeNextExpr( item
, context
);
250 case InlineItem::Break
:
251 out
<< "<break></break>";
253 case InlineItem::Ret
:
254 out
<< "<ret></ret>";
260 out
<< "</sub_action>";
263 void XMLCodeGen::writePtrMod( InlineItem
*item
, InlineItem
*context
)
265 if ( context
!= 0 && ( context
->type
== InlineItem::LmOnNext
||
266 context
->type
== InlineItem::LmOnLagBehind
||
267 context
->type
== InlineItem::LmSwitch
) )
269 switch ( item
->type
) {
270 case InlineItem::Hold
:
271 out
<< "<holdte></holdte>";
273 case InlineItem::Exec
:
274 writeActionExecTE( item
);
280 switch ( item
->type
) {
281 case InlineItem::Hold
:
282 out
<< "<hold></hold>";
284 case InlineItem::Exec
:
285 writeActionExec( item
);
293 void XMLCodeGen::writeGoto( InlineItem
*item
, InlineItem
*context
)
295 if ( pd
->generatingSectionSubset
)
296 out
<< "<goto>-1</goto>";
298 EntryMapEl
*targ
= fsm
->entryPoints
.find( item
->nameTarg
->id
);
299 out
<< "<goto>" << targ
->value
->alg
.stateNum
<< "</goto>";
303 void XMLCodeGen::writeCall( InlineItem
*item
, InlineItem
*context
)
305 if ( pd
->generatingSectionSubset
)
306 out
<< "<call>-1</call>";
308 EntryMapEl
*targ
= fsm
->entryPoints
.find( item
->nameTarg
->id
);
309 out
<< "<call>" << targ
->value
->alg
.stateNum
<< "</call>";
313 void XMLCodeGen::writeNext( InlineItem
*item
, InlineItem
*context
)
315 if ( pd
->generatingSectionSubset
)
316 out
<< "<next>-1</next>";
318 EntryMapEl
*targ
= fsm
->entryPoints
.find( item
->nameTarg
->id
);
319 out
<< "<next>" << targ
->value
->alg
.stateNum
<< "</next>";
323 void XMLCodeGen::writeGotoExpr( InlineItem
*item
, InlineItem
*context
)
325 out
<< "<goto_expr>";
326 writeInlineList( item
->children
, 0 );
327 out
<< "</goto_expr>";
330 void XMLCodeGen::writeCallExpr( InlineItem
*item
, InlineItem
*context
)
332 out
<< "<call_expr>";
333 writeInlineList( item
->children
, 0 );
334 out
<< "</call_expr>";
337 void XMLCodeGen::writeNextExpr( InlineItem
*item
, InlineItem
*context
)
339 out
<< "<next_expr>";
340 writeInlineList( item
->children
, 0 );
341 out
<< "</next_expr>";
344 void XMLCodeGen::writeEntry( InlineItem
* item
)
346 if ( pd
->generatingSectionSubset
)
347 out
<< "<entry>-1</entry>";
349 EntryMapEl
*targ
= fsm
->entryPoints
.find( item
->nameTarg
->id
);
350 out
<< "<entry>" << targ
->value
->alg
.stateNum
<< "</entry>";
354 void XMLCodeGen::writeActionExec( InlineItem
*item
)
357 writeInlineList( item
->children
, 0 );
361 void XMLCodeGen::writeActionExecTE( InlineItem
*item
)
364 writeInlineList( item
->children
, 0 );
368 void XMLCodeGen::writeLmOnLast( InlineItem
*item
)
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>";
376 out
<< "<exec><get_tokend></get_tokend></exec>";
379 void XMLCodeGen::writeLmOnNext( InlineItem
*item
)
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>";
387 out
<< "<exec><get_tokend></get_tokend></exec>";
390 void XMLCodeGen::writeLmOnLagBehind( InlineItem
*item
)
392 if ( item
->longestMatchPart
->action
!= 0 ) {
393 out
<< "<sub_action>";
394 writeInlineList( item
->longestMatchPart
->action
->inlineList
, item
);
395 out
<< "</sub_action>";
397 out
<< "<exec><get_tokend></get_tokend></exec>";
401 void XMLCodeGen::writeInlineList( InlineList
*inlineList
, InlineItem
*context
)
403 for ( InlineList::Iter item
= *inlineList
; item
.lte(); item
++ ) {
404 switch ( item
->type
) {
405 case InlineItem::Text
:
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
);
414 case InlineItem::PChar
:
415 out
<< "<pchar></pchar>";
417 case InlineItem::Char
:
418 out
<< "<char></char>";
420 case InlineItem::Curs
:
421 out
<< "<curs></curs>";
423 case InlineItem::Targs
:
424 out
<< "<targs></targs>";
426 case InlineItem::Entry
:
430 case InlineItem::Hold
:
431 case InlineItem::Exec
:
432 writePtrMod( item
, context
);
435 case InlineItem::LmSwitch
:
436 writeLmSwitch( item
);
438 case InlineItem::LmSetActId
:
439 out
<< "<set_act>" <<
440 item
->longestMatchPart
->longestMatchId
<<
443 case InlineItem::LmSetTokEnd
:
444 out
<< "<set_tokend>1</set_tokend>";
446 case InlineItem::LmOnLast
:
447 writeLmOnLast( item
);
449 case InlineItem::LmOnNext
:
450 writeLmOnNext( item
);
452 case InlineItem::LmOnLagBehind
:
453 writeLmOnLagBehind( item
);
455 case InlineItem::LmInitAct
:
456 out
<< "<init_act></init_act>";
458 case InlineItem::LmInitTokStart
:
459 out
<< "<init_tokstart></init_tokstart>";
461 case InlineItem::LmSetTokStart
:
462 out
<< "<set_tokstart></set_tokstart>";
468 void XMLCodeGen::writeAction( Action
*action
)
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";
478 void xmlEscapeHost( std::ostream
&out
, char *data
, long len
)
480 char *end
= data
+ len
;
481 while ( data
!= end
) {
483 case '<': out
<< "<"; break;
484 case '>': out
<< ">"; break;
485 case '&': out
<< "&"; break;
486 default: out
<< *data
; break;
492 void XMLCodeGen::writeStateActions( StateAp
*state
)
494 RedActionTable
*toStateActions
= 0;
495 if ( state
->toStateActionTable
.length() > 0 )
496 toStateActions
= actionTableMap
.find( state
->toStateActionTable
);
498 RedActionTable
*fromStateActions
= 0;
499 if ( state
->fromStateActionTable
.length() > 0 )
500 fromStateActions
= actionTableMap
.find( state
->fromStateActionTable
);
502 RedActionTable
*eofActions
= 0;
503 if ( state
->eofActionTable
.length() > 0 )
504 eofActions
= actionTableMap
.find( state
->eofActionTable
);
506 if ( toStateActions
!= 0 || fromStateActions
!= 0 || eofActions
!= 0 ) {
507 out
<< " <state_actions>";
508 if ( toStateActions
!= 0 )
509 out
<< toStateActions
->id
;
513 if ( fromStateActions
!= 0 )
514 out
<< " " << fromStateActions
->id
;
518 if ( eofActions
!= 0 )
519 out
<< " " << eofActions
->id
;
521 out
<< " x"; out
<< "</state_actions>\n";
525 void XMLCodeGen::writeStateConditions( StateAp
*state
)
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
++ ) {
531 writeKey( scdi
->lowKey
);
533 writeKey( scdi
->highKey
);
535 out
<< scdi
->condSpace
->condSpaceId
;
538 out
<< " </cond_list>\n";
542 void XMLCodeGen::writeStateList()
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\"";
552 writeStateActions( st
);
553 writeStateConditions( st
);
554 writeTransList( st
);
556 out
<< " </state>\n";
561 out
<< " </state_list>\n";
564 bool XMLCodeGen::writeNameInst( NameInst
*nameInst
)
566 bool written
= false;
567 if ( nameInst
->parent
!= 0 )
568 written
= writeNameInst( nameInst
->parent
);
570 if ( nameInst
->name
!= 0 ) {
573 out
<< nameInst
->name
;
580 void XMLCodeGen::writeEntryPoints()
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\"";
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";
596 out
<< " </entry_points>\n";
600 void XMLCodeGen::writeMachine()
602 /* Open the machine. */
603 out
<< " <machine>\n";
606 reduceActionTables();
609 writeActionTableList();
613 out
<< " <start_state>" << fsm
->startState
->alg
.stateNum
<<
617 if ( fsm
->errState
!= 0 ) {
618 out
<< " <error_state>" << fsm
->errState
->alg
.stateNum
<<
625 out
<< " </machine>\n";
628 void XMLCodeGen::writeAlphType()
630 out
<< " <alphtype>" <<
631 (keyOps
->alphType
- hostLang
->hostTypes
) << "</alphtype>\n";
634 void XMLCodeGen::writeGetKeyExpr()
637 writeInlineList( pd
->getKeyExpr
, 0 );
638 out
<< "</getkey>\n";
641 void XMLCodeGen::writeAccessExpr()
644 writeInlineList( pd
->accessExpr
, 0 );
645 out
<< "</access>\n";
648 void XMLCodeGen::writeCurStateExpr()
650 out
<< " <curstate>";
651 writeInlineList( pd
->curStateExpr
, 0 );
652 out
<< "</curstate>\n";
655 void XMLCodeGen::writeConditions()
657 if ( condData
->condSpaceMap
.length() > 0 ) {
658 long nextCondSpaceId
= 0;
659 for ( CondSpaceMap::Iter cs
= condData
->condSpaceMap
; cs
.lte(); cs
++ )
660 cs
->condSpaceId
= nextCondSpaceId
++;
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";
671 out
<< " </cond_space_list>\n";
675 void XMLCodeGen::writeExports()
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
);
684 out
<< " </exports>\n";
688 void XMLCodeGen::writeXML()
690 /* Open the definition. */
691 out
<< "<ragel_def name=\"" << fsmName
<< "\">\n";
694 if ( pd
->getKeyExpr
!= 0 )
697 if ( pd
->accessExpr
!= 0 )
700 if ( pd
->curStateExpr
!= 0 )