Use the new import feature of Ragel for bringing in defines from the parser
[ragel.git] / ragel / xmlcodegen.cpp
blobede4d949d3a390bb48ed6c33ead4d2f4ff648dfa
1 /*
2 * Copyright 2005, 2006 Adrian Thurston <thurston@cs.queensu.ca>
3 */
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
23 #include "ragel.h"
24 #include "xmlcodegen.h"
25 #include "parsedata.h"
26 #include "fsmgraph.h"
27 #include <string.h>
29 using namespace std;
31 XMLCodeGen::XMLCodeGen( char *fsmName, ParseData *pd, FsmAp *fsm,
32 std::ostream &out )
34 fsmName(fsmName),
35 pd(pd),
36 fsm(fsm),
37 out(out),
38 nextActionTableId(0)
43 void XMLCodeGen::writeActionList()
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++;
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 );
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++ )
67 tables[at->id] = 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;
75 if ( ! atel.last() )
76 out << " ";
78 out << "</action_table>\n";
80 out << " </action_table_list>\n";
82 delete[] tables;
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 )
129 out << key.getVal();
130 else
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. */
142 out << " <t>";
143 writeKey( lowKey );
144 out << " ";
145 writeKey( highKey );
147 if ( trans->toState != 0 )
148 out << " " << trans->toState->alg.stateNum;
149 else
150 out << " x";
152 if ( actionTable != 0 )
153 out << " " << actionTable->id;
154 else
155 out << " x";
156 out << "</t>\n";
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;
182 out << "<lm_switch";
183 if ( longestMatch->lmSwitchHandlesError )
184 out << " handles_error=\"t\"";
185 out << ">\n";
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 )
203 out << "<text>";
204 xmlEscapeHost( out, item->data, strlen(item->data) );
205 if ( item->next == 0 || item->next->type != InlineItem::Text )
206 out << "</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>";
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;
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;
259 if ( context != 0 )
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>";
272 break;
273 case InlineItem::Exec:
274 writeActionExecTE( item );
275 break;
276 default: break;
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;
293 void XMLCodeGen::writeGoto( InlineItem *item, InlineItem *context )
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>";
303 void XMLCodeGen::writeCall( InlineItem *item, InlineItem *context )
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>";
313 void XMLCodeGen::writeNext( InlineItem *item, InlineItem *context )
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>";
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>";
348 else {
349 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
350 out << "<entry>" << targ->value->alg.stateNum << "</entry>";
354 void XMLCodeGen::writeActionExec( InlineItem *item )
356 out << "<exec>";
357 writeInlineList( item->children, 0 );
358 out << "</exec>";
361 void XMLCodeGen::writeActionExecTE( InlineItem *item )
363 out << "<execte>";
364 writeInlineList( item->children, 0 );
365 out << "</execte>";
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:
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;
430 case InlineItem::Hold:
431 case InlineItem::Exec:
432 writePtrMod( item, context );
433 break;
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;
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 ) {
482 switch ( *data ) {
483 case '<': out << "&lt;"; break;
484 case '>': out << "&gt;"; break;
485 case '&': out << "&amp;"; break;
486 default: out << *data; break;
488 data += 1;
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;
510 else
511 out << "x";
513 if ( fromStateActions != 0 )
514 out << " " << fromStateActions->id;
515 else
516 out << " x";
518 if ( eofActions != 0 )
519 out << " " << eofActions->id;
520 else
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++ ) {
530 out << " <c>";
531 writeKey( scdi->lowKey );
532 out << " ";
533 writeKey( scdi->highKey );
534 out << " ";
535 out << scdi->condSpace->condSpaceId;
536 out << "</c>\n";
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\"";
550 out << ">\n";
552 writeStateActions( st );
553 writeStateConditions( st );
554 writeTransList( st );
556 out << " </state>\n";
558 if ( !st.last() )
559 out << "\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 ) {
571 if ( written )
572 out << '_';
573 out << nameInst->name;
574 written = true;
577 return written;
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\"";
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";
596 out << " </entry_points>\n";
600 void XMLCodeGen::writeMachine()
602 /* Open the machine. */
603 out << " <machine>\n";
605 /* Action tables. */
606 reduceActionTables();
608 writeActionList();
609 writeActionTableList();
610 writeConditions();
612 /* Start state. */
613 out << " <start_state>" << fsm->startState->alg.stateNum <<
614 "</start_state>\n";
616 /* Error state. */
617 if ( fsm->errState != 0 ) {
618 out << " <error_state>" << fsm->errState->alg.stateNum <<
619 "</error_state>\n";
622 writeEntryPoints();
623 writeStateList();
625 out << " </machine>\n";
628 void XMLCodeGen::writeAlphType()
630 out << " <alphtype>" <<
631 (keyOps->alphType - hostLang->hostTypes) << "</alphtype>\n";
634 void XMLCodeGen::writeGetKeyExpr()
636 out << " <getkey>";
637 writeInlineList( pd->getKeyExpr, 0 );
638 out << "</getkey>\n";
641 void XMLCodeGen::writeAccessExpr()
643 out << " <access>";
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 );
682 out << "</ex>\n";
684 out << " </exports>\n";
688 void XMLCodeGen::writeXML()
690 /* Open the definition. */
691 out << "<ragel_def name=\"" << fsmName << "\">\n";
692 writeAlphType();
694 if ( pd->getKeyExpr != 0 )
695 writeGetKeyExpr();
697 if ( pd->accessExpr != 0 )
698 writeAccessExpr();
700 if ( pd->curStateExpr != 0 )
701 writeCurStateExpr();
703 writeExports();
705 writeMachine();
707 out <<
708 "</ragel_def>\n";