2 * Copyright 2005-2007 Adrian Thurston <thurston@complang.org>
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"
26 #include "parsedata.h"
32 XMLCodeGen::XMLCodeGen( char *fsmName, ParseData *pd, FsmAp *fsm,
33 std::ostream &out, XmlParser &xmlParser )
45 void XMLCodeGen::writeActionList()
47 /* Determine which actions to write. */
49 for ( ActionList::Iter act = pd->actionList; act.lte(); act++ ) {
50 if ( act->numRefs() > 0 || act->numCondRefs > 0 )
51 act->actionId = nextActionId++;
55 out << " <action_list length=\"" << nextActionId << "\">\n";
56 for ( ActionList::Iter act = pd->actionList; act.lte(); act++ ) {
57 if ( act->actionId >= 0 )
60 out << " </action_list>\n";
63 void XMLCodeGen::writeActionTableList()
65 /* Must first order the action tables based on their id. */
66 int numTables = nextActionTableId;
67 RedActionTable **tables = new RedActionTable*[numTables];
68 for ( ActionTableMap::Iter at = actionTableMap; at.lte(); at++ )
71 out << " <action_table_list length=\"" << numTables << "\">\n";
72 for ( int t = 0; t < numTables; t++ ) {
73 out << " <action_table id=\"" << t << "\" length=\"" <<
74 tables[t]->key.length() << "\">";
75 for ( ActionTable::Iter atel = tables[t]->key; atel.lte(); atel++ ) {
76 out << atel->value->actionId;
80 out << "</action_table>\n";
82 out << " </action_table_list>\n";
87 void XMLCodeGen::reduceActionTables()
89 /* Reduce the actions tables to a set. */
90 for ( StateList::Iter st = fsm->stateList; st.lte(); st++ ) {
91 RedActionTable *actionTable = 0;
93 /* Reduce To State Actions. */
94 if ( st->toStateActionTable.length() > 0 ) {
95 if ( actionTableMap.insert( st->toStateActionTable, &actionTable ) )
96 actionTable->id = nextActionTableId++;
99 /* Reduce From State Actions. */
100 if ( st->fromStateActionTable.length() > 0 ) {
101 if ( actionTableMap.insert( st->fromStateActionTable, &actionTable ) )
102 actionTable->id = nextActionTableId++;
105 /* Reduce EOF actions. */
106 if ( st->eofActionTable.length() > 0 ) {
107 if ( actionTableMap.insert( st->eofActionTable, &actionTable ) )
108 actionTable->id = nextActionTableId++;
111 /* Loop the transitions and reduce their actions. */
112 for ( TransList::Iter trans = st->outList; trans.lte(); trans++ ) {
113 if ( trans->actionTable.length() > 0 ) {
114 if ( actionTableMap.insert( trans->actionTable, &actionTable ) )
115 actionTable->id = nextActionTableId++;
121 void XMLCodeGen::appendTrans( TransListVect &outList, Key lowKey,
122 Key highKey, TransAp *trans )
124 if ( trans->toState != 0 || trans->actionTable.length() > 0 )
125 outList.append( TransEl( lowKey, highKey, trans ) );
128 void XMLCodeGen::writeKey( Key key )
130 if ( keyOps->isSigned )
133 out << (unsigned long) key.getVal();
136 void XMLCodeGen::writeTrans( Key lowKey, Key highKey, TransAp *trans )
138 /* First reduce the action. */
139 RedActionTable *actionTable = 0;
140 if ( trans->actionTable.length() > 0 )
141 actionTable = actionTableMap.find( trans->actionTable );
143 /* Write the transition. */
149 if ( trans->toState != 0 )
150 out << " " << trans->toState->alg.stateNum;
154 if ( actionTable != 0 )
155 out << " " << actionTable->id;
161 void XMLCodeGen::writeTransList( StateAp *state )
163 TransListVect outList;
165 /* If there is only are no ranges the task is simple. */
166 if ( state->outList.length() > 0 ) {
167 /* Loop each source range. */
168 for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) {
169 /* Reduce the transition. If it reduced to anything then add it. */
170 appendTrans( outList, trans->lowKey, trans->highKey, trans );
174 out << " <trans_list length=\"" << outList.length() << "\">\n";
175 for ( TransListVect::Iter tvi = outList; tvi.lte(); tvi++ )
176 writeTrans( tvi->lowKey, tvi->highKey, tvi->value );
177 out << " </trans_list>\n";
180 void XMLCodeGen::writeEofTrans( StateAp *state )
182 RedActionTable *eofActions = 0;
183 if ( state->eofActionTable.length() > 0 )
184 eofActions = actionTableMap.find( state->eofActionTable );
186 /* The <eof_t> is used when there is an eof target, otherwise the eof
187 * action goes into state actions. */
188 if ( state->eofTarget != 0 ) {
189 out << " <eof_t>" << state->eofTarget->alg.stateNum;
191 if ( eofActions != 0 )
192 out << " " << eofActions->id;
196 out << "</eof_t>" << endl;
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::writeGoto( InlineItem *item )
211 if ( pd->generatingSectionSubset )
212 out << "<goto>-1</goto>";
214 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
215 out << "<goto>" << targ->value->alg.stateNum << "</goto>";
219 void XMLCodeGen::writeCall( InlineItem *item )
221 if ( pd->generatingSectionSubset )
222 out << "<call>-1</call>";
224 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
225 out << "<call>" << targ->value->alg.stateNum << "</call>";
229 void XMLCodeGen::writeNext( InlineItem *item )
231 if ( pd->generatingSectionSubset )
232 out << "<next>-1</next>";
234 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
235 out << "<next>" << targ->value->alg.stateNum << "</next>";
239 void XMLCodeGen::writeGotoExpr( InlineItem *item )
241 out << "<goto_expr>";
242 writeInlineList( item->children );
243 out << "</goto_expr>";
246 void XMLCodeGen::writeCallExpr( InlineItem *item )
248 out << "<call_expr>";
249 writeInlineList( item->children );
250 out << "</call_expr>";
253 void XMLCodeGen::writeNextExpr( InlineItem *item )
255 out << "<next_expr>";
256 writeInlineList( item->children );
257 out << "</next_expr>";
260 void XMLCodeGen::writeEntry( InlineItem *item )
262 if ( pd->generatingSectionSubset )
263 out << "<entry>-1</entry>";
265 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
266 out << "<entry>" << targ->value->alg.stateNum << "</entry>";
270 void XMLCodeGen::writeActionExec( InlineItem *item )
273 writeInlineList( item->children );
277 void XMLCodeGen::writeLmOnLast( InlineItem *item )
279 out << "<set_tokend>1</set_tokend>";
281 if ( item->longestMatchPart->action != 0 ) {
282 out << "<sub_action>";
283 writeInlineList( item->longestMatchPart->action->inlineList );
284 out << "</sub_action>";
288 void XMLCodeGen::writeLmOnNext( InlineItem *item )
290 out << "<set_tokend>0</set_tokend>";
291 out << "<hold></hold>";
293 if ( item->longestMatchPart->action != 0 ) {
294 out << "<sub_action>";
295 writeInlineList( item->longestMatchPart->action->inlineList );
296 out << "</sub_action>";
300 void XMLCodeGen::writeLmOnLagBehind( InlineItem *item )
302 out << "<exec><get_tokend></get_tokend></exec>";
304 if ( item->longestMatchPart->action != 0 ) {
305 out << "<sub_action>";
306 writeInlineList( item->longestMatchPart->action->inlineList );
307 out << "</sub_action>";
311 void XMLCodeGen::writeLmSwitch( InlineItem *item )
313 LongestMatch *longestMatch = item->longestMatch;
314 out << "<lm_switch>\n";
316 /* We can't put the <exec> here because we may need to handle the error
317 * case and in that case p should not be changed. Instead use a default
318 * label in the switch to adjust p when user actions are not set. An id of
319 * -1 indicates the default. */
321 if ( longestMatch->lmSwitchHandlesError ) {
322 /* If the switch handles error then we should have also forced the
324 assert( fsm->errState != 0 );
326 out << " <sub_action id=\"0\">";
327 out << "<goto>" << fsm->errState->alg.stateNum << "</goto>";
328 out << "</sub_action>\n";
331 bool needDefault = false;
332 for ( LmPartList::Iter lmi = *longestMatch->longestMatchList; lmi.lte(); lmi++ ) {
333 if ( lmi->inLmSelect ) {
334 if ( lmi->action == 0 )
337 /* Open the action. Write it with the context that sets up _p
338 * when doing control flow changes from inside the machine. */
339 out << " <sub_action id=\"" << lmi->longestMatchId << "\">";
340 out << "<exec><get_tokend></get_tokend></exec>";
341 writeInlineList( lmi->action->inlineList );
342 out << "</sub_action>\n";
348 out << " <sub_action id=\"-1\"><exec><get_tokend>"
349 "</get_tokend></exec></sub_action>\n";
352 out << " </lm_switch>";
355 void XMLCodeGen::writeInlineList( InlineList *inlineList )
357 for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
358 switch ( item->type ) {
359 case InlineItem::Text:
362 case InlineItem::Goto:
365 case InlineItem::GotoExpr:
366 writeGotoExpr( item );
368 case InlineItem::Call:
371 case InlineItem::CallExpr:
372 writeCallExpr( item );
374 case InlineItem::Next:
377 case InlineItem::NextExpr:
378 writeNextExpr( item );
380 case InlineItem::Break:
381 out << "<break></break>";
383 case InlineItem::Ret:
384 out << "<ret></ret>";
386 case InlineItem::PChar:
387 out << "<pchar></pchar>";
389 case InlineItem::Char:
390 out << "<char></char>";
392 case InlineItem::Curs:
393 out << "<curs></curs>";
395 case InlineItem::Targs:
396 out << "<targs></targs>";
398 case InlineItem::Entry:
402 case InlineItem::Hold:
403 out << "<hold></hold>";
405 case InlineItem::Exec:
406 writeActionExec( item );
409 case InlineItem::LmSetActId:
410 out << "<set_act>" <<
411 item->longestMatchPart->longestMatchId <<
414 case InlineItem::LmSetTokEnd:
415 out << "<set_tokend>1</set_tokend>";
418 case InlineItem::LmOnLast:
419 writeLmOnLast( item );
421 case InlineItem::LmOnNext:
422 writeLmOnNext( item );
424 case InlineItem::LmOnLagBehind:
425 writeLmOnLagBehind( item );
427 case InlineItem::LmSwitch:
428 writeLmSwitch( item );
431 case InlineItem::LmInitAct:
432 out << "<init_act></init_act>";
434 case InlineItem::LmInitTokStart:
435 out << "<init_tokstart></init_tokstart>";
437 case InlineItem::LmSetTokStart:
438 out << "<set_tokstart></set_tokstart>";
444 void XMLCodeGen::writeAction( Action *action )
446 out << " <action id=\"" << action->actionId << "\"";
447 if ( action->name != 0 )
448 out << " name=\"" << action->name << "\"";
449 out << " line=\"" << action->loc.line << "\" col=\"" << action->loc.col << "\">";
450 writeInlineList( action->inlineList );
451 out << "</action>\n";
454 void xmlEscapeHost( std::ostream &out, char *data, long len )
456 char *end = data + len;
457 while ( data != end ) {
459 case '<': out << "<"; break;
460 case '>': out << ">"; break;
461 case '&': out << "&"; break;
462 default: out << *data; break;
468 void XMLCodeGen::writeStateActions( StateAp *state )
470 RedActionTable *toStateActions = 0;
471 if ( state->toStateActionTable.length() > 0 )
472 toStateActions = actionTableMap.find( state->toStateActionTable );
474 RedActionTable *fromStateActions = 0;
475 if ( state->fromStateActionTable.length() > 0 )
476 fromStateActions = actionTableMap.find( state->fromStateActionTable );
478 /* EOF actions go out here only if the state has no eof target. If it has
479 * an eof target then an eof transition will be used instead. */
480 RedActionTable *eofActions = 0;
481 if ( state->eofTarget == 0 && state->eofActionTable.length() > 0 )
482 eofActions = actionTableMap.find( state->eofActionTable );
484 if ( toStateActions != 0 || fromStateActions != 0 || eofActions != 0 ) {
485 out << " <state_actions>";
486 if ( toStateActions != 0 )
487 out << toStateActions->id;
491 if ( fromStateActions != 0 )
492 out << " " << fromStateActions->id;
496 if ( eofActions != 0 )
497 out << " " << eofActions->id;
501 out << "</state_actions>\n";
505 void XMLCodeGen::writeStateConditions( StateAp *state )
507 if ( state->stateCondList.length() > 0 ) {
508 out << " <cond_list length=\"" << state->stateCondList.length() << "\">\n";
509 for ( StateCondList::Iter scdi = state->stateCondList; scdi.lte(); scdi++ ) {
511 writeKey( scdi->lowKey );
513 writeKey( scdi->highKey );
515 out << scdi->condSpace->condSpaceId;
518 out << " </cond_list>\n";
522 void XMLCodeGen::writeStateList()
524 /* Write the list of states. */
525 out << " <state_list length=\"" << fsm->stateList.length() << "\">\n";
526 for ( StateList::Iter st = fsm->stateList; st.lte(); st++ ) {
527 out << " <state id=\"" << st->alg.stateNum << "\"";
528 if ( st->isFinState() )
529 out << " final=\"t\"";
532 writeStateActions( st );
534 writeStateConditions( st );
535 writeTransList( st );
537 out << " </state>\n";
542 out << " </state_list>\n";
545 bool XMLCodeGen::writeNameInst( NameInst *nameInst )
547 bool written = false;
548 if ( nameInst->parent != 0 )
549 written = writeNameInst( nameInst->parent );
551 if ( nameInst->name != 0 ) {
554 out << nameInst->name;
561 void XMLCodeGen::writeEntryPoints()
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\"";
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";
577 out << " </entry_points>\n";
581 void XMLCodeGen::writeMachine()
583 /* Open the machine. */
584 out << " <machine>\n";
587 reduceActionTables();
590 writeActionTableList();
594 out << " <start_state>" << fsm->startState->alg.stateNum <<
598 if ( fsm->errState != 0 ) {
599 out << " <error_state>" << fsm->errState->alg.stateNum <<
606 out << " </machine>\n";
610 void XMLCodeGen::writeConditions()
612 if ( condData->condSpaceMap.length() > 0 ) {
613 long nextCondSpaceId = 0;
614 for ( CondSpaceMap::Iter cs = condData->condSpaceMap; cs.lte(); cs++ )
615 cs->condSpaceId = nextCondSpaceId++;
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";
626 out << " </cond_space_list>\n";
630 void XMLCodeGen::writeExports()
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 );
639 out << " </exports>\n";
643 void XMLCodeGen::writeXML()
645 /* Open the definition. */
646 xmlParser.open_ragel_def( fsmName );
647 out << "<ragel_def>\n";
650 out << " <alphtype>" << keyOps->alphType->internalName << "</alphtype>\n";
652 /* Getkey expression. */
653 if ( pd->getKeyExpr != 0 ) {
655 writeInlineList( pd->getKeyExpr );
656 out << "</getkey>\n";
659 /* Access expression. */
660 if ( pd->accessExpr != 0 ) {
662 writeInlineList( pd->accessExpr );
663 out << "</access>\n";
666 /* PrePush expression. */
667 if ( pd->prePushExpr != 0 ) {
669 writeInlineList( pd->prePushExpr );
670 out << "</prepush>\n";
673 /* PostPop expression. */
674 if ( pd->postPopExpr != 0 ) {
676 writeInlineList( pd->postPopExpr );
677 out << "</postpop>\n";
681 * Variable expressions.
684 if ( pd->pExpr != 0 ) {
686 writeInlineList( pd->pExpr );
687 out << "</p_expr>\n";
690 if ( pd->peExpr != 0 ) {
692 writeInlineList( pd->peExpr );
693 out << "</pe_expr>\n";
696 if ( pd->eofExpr != 0 ) {
697 out << " <eof_expr>";
698 writeInlineList( pd->eofExpr );
699 out << "</eof_expr>\n";
702 if ( pd->csExpr != 0 ) {
704 writeInlineList( pd->csExpr );
705 out << "</cs_expr>\n";
708 if ( pd->topExpr != 0 ) {
709 out << " <top_expr>";
710 writeInlineList( pd->topExpr );
711 out << "</top_expr>\n";
714 if ( pd->stackExpr != 0 ) {
715 out << " <stack_expr>";
716 writeInlineList( pd->stackExpr );
717 out << "</stack_expr>\n";
720 if ( pd->actExpr != 0 ) {
721 out << " <act_expr>";
722 writeInlineList( pd->actExpr );
723 out << "</act_expr>\n";
726 if ( pd->tokstartExpr != 0 ) {
727 out << " <tokstart_expr>";
728 writeInlineList( pd->tokstartExpr );
729 out << "</tokstart_expr>\n";
732 if ( pd->tokendExpr != 0 ) {
733 out << " <tokend_expr>";
734 writeInlineList( pd->tokendExpr );
735 out << "</tokend_expr>\n";
738 if ( pd->dataExpr != 0 ) {
739 out << " <data_expr>";
740 writeInlineList( pd->dataExpr );
741 out << "</data_expr>\n";