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"
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::writeEofTrans( StateAp *state )
180 RedActionTable *eofActions = 0;
181 if ( state->eofActionTable.length() > 0 )
182 eofActions = actionTableMap.find( state->eofActionTable );
184 /* The <eof_t> is used when there is an eof target, otherwise the eof
185 * action goes into state actions. */
186 if ( state->eofTarget != 0 ) {
187 out << " <eof_t>" << state->eofTarget->alg.stateNum;
189 if ( eofActions != 0 )
190 out << " " << eofActions->id;
194 out << "</eof_t>" << endl;
198 void XMLCodeGen::writeText( InlineItem *item )
200 if ( item->prev == 0 || item->prev->type != InlineItem::Text )
202 xmlEscapeHost( out, item->data, strlen(item->data) );
203 if ( item->next == 0 || item->next->type != InlineItem::Text )
207 void XMLCodeGen::writeGoto( InlineItem *item )
209 if ( pd->generatingSectionSubset )
210 out << "<goto>-1</goto>";
212 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
213 out << "<goto>" << targ->value->alg.stateNum << "</goto>";
217 void XMLCodeGen::writeCall( InlineItem *item )
219 if ( pd->generatingSectionSubset )
220 out << "<call>-1</call>";
222 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
223 out << "<call>" << targ->value->alg.stateNum << "</call>";
227 void XMLCodeGen::writeNext( InlineItem *item )
229 if ( pd->generatingSectionSubset )
230 out << "<next>-1</next>";
232 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
233 out << "<next>" << targ->value->alg.stateNum << "</next>";
237 void XMLCodeGen::writeGotoExpr( InlineItem *item )
239 out << "<goto_expr>";
240 writeInlineList( item->children );
241 out << "</goto_expr>";
244 void XMLCodeGen::writeCallExpr( InlineItem *item )
246 out << "<call_expr>";
247 writeInlineList( item->children );
248 out << "</call_expr>";
251 void XMLCodeGen::writeNextExpr( InlineItem *item )
253 out << "<next_expr>";
254 writeInlineList( item->children );
255 out << "</next_expr>";
258 void XMLCodeGen::writeEntry( InlineItem *item )
260 if ( pd->generatingSectionSubset )
261 out << "<entry>-1</entry>";
263 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
264 out << "<entry>" << targ->value->alg.stateNum << "</entry>";
268 void XMLCodeGen::writeActionExec( InlineItem *item )
271 writeInlineList( item->children );
275 void XMLCodeGen::writeLmOnLast( InlineItem *item )
277 out << "<set_tokend>1</set_tokend>";
279 if ( item->longestMatchPart->action != 0 ) {
280 out << "<sub_action>";
281 writeInlineList( item->longestMatchPart->action->inlineList );
282 out << "</sub_action>";
286 void XMLCodeGen::writeLmOnNext( InlineItem *item )
288 out << "<set_tokend>0</set_tokend>";
289 out << "<hold></hold>";
291 if ( item->longestMatchPart->action != 0 ) {
292 out << "<sub_action>";
293 writeInlineList( item->longestMatchPart->action->inlineList );
294 out << "</sub_action>";
298 void XMLCodeGen::writeLmOnLagBehind( InlineItem *item )
300 out << "<exec><get_tokend></get_tokend></exec>";
302 if ( item->longestMatchPart->action != 0 ) {
303 out << "<sub_action>";
304 writeInlineList( item->longestMatchPart->action->inlineList );
305 out << "</sub_action>";
309 void XMLCodeGen::writeLmSwitch( InlineItem *item )
311 LongestMatch *longestMatch = item->longestMatch;
312 out << "<lm_switch>\n";
314 /* We can't put the <exec> here because we may need to handle the error
315 * case and in that case p should not be changed. Instead use a default
316 * label in the switch to adjust p when user actions are not set. An id of
317 * -1 indicates the default. */
319 if ( longestMatch->lmSwitchHandlesError ) {
320 /* If the switch handles error then we should have also forced the
322 assert( fsm->errState != 0 );
324 out << " <sub_action id=\"0\">";
325 out << "<goto>" << fsm->errState->alg.stateNum << "</goto>";
326 out << "</sub_action>\n";
329 bool needDefault = false;
330 for ( LmPartList::Iter lmi = *longestMatch->longestMatchList; lmi.lte(); lmi++ ) {
331 if ( lmi->inLmSelect ) {
332 if ( lmi->action == 0 )
335 /* Open the action. Write it with the context that sets up _p
336 * when doing control flow changes from inside the machine. */
337 out << " <sub_action id=\"" << lmi->longestMatchId << "\">";
338 out << "<exec><get_tokend></get_tokend></exec>";
339 writeInlineList( lmi->action->inlineList );
340 out << "</sub_action>\n";
346 out << " <sub_action id=\"-1\"><exec><get_tokend>"
347 "</get_tokend></exec></sub_action>\n";
350 out << " </lm_switch>";
353 void XMLCodeGen::writeInlineList( InlineList *inlineList )
355 for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
356 switch ( item->type ) {
357 case InlineItem::Text:
360 case InlineItem::Goto:
363 case InlineItem::GotoExpr:
364 writeGotoExpr( item );
366 case InlineItem::Call:
369 case InlineItem::CallExpr:
370 writeCallExpr( item );
372 case InlineItem::Next:
375 case InlineItem::NextExpr:
376 writeNextExpr( item );
378 case InlineItem::Break:
379 out << "<break></break>";
381 case InlineItem::Ret:
382 out << "<ret></ret>";
384 case InlineItem::PChar:
385 out << "<pchar></pchar>";
387 case InlineItem::Char:
388 out << "<char></char>";
390 case InlineItem::Curs:
391 out << "<curs></curs>";
393 case InlineItem::Targs:
394 out << "<targs></targs>";
396 case InlineItem::Entry:
400 case InlineItem::Hold:
401 out << "<hold></hold>";
403 case InlineItem::Exec:
404 writeActionExec( item );
407 case InlineItem::LmSetActId:
408 out << "<set_act>" <<
409 item->longestMatchPart->longestMatchId <<
412 case InlineItem::LmSetTokEnd:
413 out << "<set_tokend>1</set_tokend>";
416 case InlineItem::LmOnLast:
417 writeLmOnLast( item );
419 case InlineItem::LmOnNext:
420 writeLmOnNext( item );
422 case InlineItem::LmOnLagBehind:
423 writeLmOnLagBehind( item );
425 case InlineItem::LmSwitch:
426 writeLmSwitch( item );
429 case InlineItem::LmInitAct:
430 out << "<init_act></init_act>";
432 case InlineItem::LmInitTokStart:
433 out << "<init_tokstart></init_tokstart>";
435 case InlineItem::LmSetTokStart:
436 out << "<set_tokstart></set_tokstart>";
442 void XMLCodeGen::writeAction( Action *action )
444 out << " <action id=\"" << action->actionId << "\"";
445 if ( action->name != 0 )
446 out << " name=\"" << action->name << "\"";
447 out << " line=\"" << action->loc.line << "\" col=\"" << action->loc.col << "\">";
448 writeInlineList( action->inlineList );
449 out << "</action>\n";
452 void xmlEscapeHost( std::ostream &out, char *data, long len )
454 char *end = data + len;
455 while ( data != end ) {
457 case '<': out << "<"; break;
458 case '>': out << ">"; break;
459 case '&': out << "&"; break;
460 default: out << *data; break;
466 void XMLCodeGen::writeStateActions( StateAp *state )
468 RedActionTable *toStateActions = 0;
469 if ( state->toStateActionTable.length() > 0 )
470 toStateActions = actionTableMap.find( state->toStateActionTable );
472 RedActionTable *fromStateActions = 0;
473 if ( state->fromStateActionTable.length() > 0 )
474 fromStateActions = actionTableMap.find( state->fromStateActionTable );
476 /* EOF actions go out here only if the state has no eof target. If it has
477 * an eof target then an eof transition will be used instead. */
478 RedActionTable *eofActions = 0;
479 if ( state->eofTarget == 0 && state->eofActionTable.length() > 0 )
480 eofActions = actionTableMap.find( state->eofActionTable );
482 if ( toStateActions != 0 || fromStateActions != 0 || eofActions != 0 ) {
483 out << " <state_actions>";
484 if ( toStateActions != 0 )
485 out << toStateActions->id;
489 if ( fromStateActions != 0 )
490 out << " " << fromStateActions->id;
494 if ( eofActions != 0 )
495 out << " " << eofActions->id;
499 out << "</state_actions>\n";
503 void XMLCodeGen::writeStateConditions( StateAp *state )
505 if ( state->stateCondList.length() > 0 ) {
506 out << " <cond_list length=\"" << state->stateCondList.length() << "\">\n";
507 for ( StateCondList::Iter scdi = state->stateCondList; scdi.lte(); scdi++ ) {
509 writeKey( scdi->lowKey );
511 writeKey( scdi->highKey );
513 out << scdi->condSpace->condSpaceId;
516 out << " </cond_list>\n";
520 void XMLCodeGen::writeStateList()
522 /* Write the list of states. */
523 out << " <state_list length=\"" << fsm->stateList.length() << "\">\n";
524 for ( StateList::Iter st = fsm->stateList; st.lte(); st++ ) {
525 out << " <state id=\"" << st->alg.stateNum << "\"";
526 if ( st->isFinState() )
527 out << " final=\"t\"";
530 writeStateActions( st );
532 writeStateConditions( st );
533 writeTransList( st );
535 out << " </state>\n";
540 out << " </state_list>\n";
543 bool XMLCodeGen::writeNameInst( NameInst *nameInst )
545 bool written = false;
546 if ( nameInst->parent != 0 )
547 written = writeNameInst( nameInst->parent );
549 if ( nameInst->name != 0 ) {
552 out << nameInst->name;
559 void XMLCodeGen::writeEntryPoints()
561 /* List of entry points other than start state. */
562 if ( fsm->entryPoints.length() > 0 || pd->lmRequiresErrorState ) {
563 out << " <entry_points";
564 if ( pd->lmRequiresErrorState )
565 out << " error=\"t\"";
567 for ( EntryMap::Iter en = fsm->entryPoints; en.lte(); en++ ) {
568 /* Get the name instantiation from nameIndex. */
569 NameInst *nameInst = pd->nameIndex[en->key];
570 StateAp *state = en->value;
571 out << " <entry name=\"";
572 writeNameInst( nameInst );
573 out << "\">" << state->alg.stateNum << "</entry>\n";
575 out << " </entry_points>\n";
579 void XMLCodeGen::writeMachine()
581 /* Open the machine. */
582 out << " <machine>\n";
585 reduceActionTables();
588 writeActionTableList();
592 out << " <start_state>" << fsm->startState->alg.stateNum <<
596 if ( fsm->errState != 0 ) {
597 out << " <error_state>" << fsm->errState->alg.stateNum <<
604 out << " </machine>\n";
608 void XMLCodeGen::writeConditions()
610 if ( condData->condSpaceMap.length() > 0 ) {
611 long nextCondSpaceId = 0;
612 for ( CondSpaceMap::Iter cs = condData->condSpaceMap; cs.lte(); cs++ )
613 cs->condSpaceId = nextCondSpaceId++;
615 out << " <cond_space_list length=\"" << condData->condSpaceMap.length() << "\">\n";
616 for ( CondSpaceMap::Iter cs = condData->condSpaceMap; cs.lte(); cs++ ) {
617 out << " <cond_space id=\"" << cs->condSpaceId <<
618 "\" length=\"" << cs->condSet.length() << "\">";
619 writeKey( cs->baseKey );
620 for ( CondSet::Iter csi = cs->condSet; csi.lte(); csi++ )
621 out << " " << (*csi)->actionId;
622 out << "</cond_space>\n";
624 out << " </cond_space_list>\n";
628 void XMLCodeGen::writeExports()
630 if ( pd->exportList.length() > 0 ) {
631 out << " <exports>\n";
632 for ( ExportList::Iter exp = pd->exportList; exp.lte(); exp++ ) {
633 out << " <ex name=\"" << exp->name << "\">";
634 writeKey( exp->key );
637 out << " </exports>\n";
641 void XMLCodeGen::writeXML()
643 /* Open the definition. */
644 out << "<ragel_def name=\"" << fsmName << "\">\n";
647 out << " <alphtype>" << keyOps->alphType->internalName << "</alphtype>\n";
649 /* Getkey expression. */
650 if ( pd->getKeyExpr != 0 ) {
652 writeInlineList( pd->getKeyExpr );
653 out << "</getkey>\n";
656 /* Access expression. */
657 if ( pd->accessExpr != 0 ) {
659 writeInlineList( pd->accessExpr );
660 out << "</access>\n";
663 /* PrePush expression. */
664 if ( pd->prePushExpr != 0 ) {
666 writeInlineList( pd->prePushExpr );
667 out << "</prepush>\n";
670 /* PostPop expression. */
671 if ( pd->postPopExpr != 0 ) {
673 writeInlineList( pd->postPopExpr );
674 out << "</postpop>\n";
678 * Variable expressions.
681 if ( pd->pExpr != 0 ) {
683 writeInlineList( pd->pExpr );
684 out << "</p_expr>\n";
687 if ( pd->peExpr != 0 ) {
689 writeInlineList( pd->peExpr );
690 out << "</pe_expr>\n";
693 if ( pd->eofExpr != 0 ) {
694 out << " <eof_expr>";
695 writeInlineList( pd->eofExpr );
696 out << "</eof_expr>\n";
699 if ( pd->csExpr != 0 ) {
701 writeInlineList( pd->csExpr );
702 out << "</cs_expr>\n";
705 if ( pd->topExpr != 0 ) {
706 out << " <top_expr>";
707 writeInlineList( pd->topExpr );
708 out << "</top_expr>\n";
711 if ( pd->stackExpr != 0 ) {
712 out << " <stack_expr>";
713 writeInlineList( pd->stackExpr );
714 out << "</stack_expr>\n";
717 if ( pd->actExpr != 0 ) {
718 out << " <act_expr>";
719 writeInlineList( pd->actExpr );
720 out << "</act_expr>\n";
723 if ( pd->tokstartExpr != 0 ) {
724 out << " <tokstart_expr>";
725 writeInlineList( pd->tokstartExpr );
726 out << "</tokstart_expr>\n";
729 if ( pd->tokendExpr != 0 ) {
730 out << " <tokend_expr>";
731 writeInlineList( pd->tokendExpr );
732 out << "</tokend_expr>\n";
735 if ( pd->dataExpr != 0 ) {
736 out << " <data_expr>";
737 writeInlineList( pd->dataExpr );
738 out << "</data_expr>\n";