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"
29 #include "inputdata.h"
34 GenBase::GenBase( char *fsmName, ParseData *pd, FsmAp *fsm )
43 void GenBase::appendTrans( TransListVect &outList, Key lowKey,
44 Key highKey, TransAp *trans )
46 if ( trans->toState != 0 || trans->actionTable.length() > 0 )
47 outList.append( TransEl( lowKey, highKey, trans ) );
50 void GenBase::reduceActionTables()
52 /* Reduce the actions tables to a set. */
53 for ( StateList::Iter st = fsm->stateList; st.lte(); st++ ) {
54 RedActionTable *actionTable = 0;
56 /* Reduce To State Actions. */
57 if ( st->toStateActionTable.length() > 0 ) {
58 if ( actionTableMap.insert( st->toStateActionTable, &actionTable ) )
59 actionTable->id = nextActionTableId++;
62 /* Reduce From State Actions. */
63 if ( st->fromStateActionTable.length() > 0 ) {
64 if ( actionTableMap.insert( st->fromStateActionTable, &actionTable ) )
65 actionTable->id = nextActionTableId++;
68 /* Reduce EOF actions. */
69 if ( st->eofActionTable.length() > 0 ) {
70 if ( actionTableMap.insert( st->eofActionTable, &actionTable ) )
71 actionTable->id = nextActionTableId++;
74 /* Loop the transitions and reduce their actions. */
75 for ( TransList::Iter trans = st->outList; trans.lte(); trans++ ) {
76 if ( trans->actionTable.length() > 0 ) {
77 if ( actionTableMap.insert( trans->actionTable, &actionTable ) )
78 actionTable->id = nextActionTableId++;
84 XMLCodeGen::XMLCodeGen( char *fsmName, ParseData *pd, FsmAp *fsm, std::ostream &out )
86 GenBase(fsmName, pd, fsm),
92 void XMLCodeGen::writeActionList()
94 /* Determine which actions to write. */
96 for ( ActionList::Iter act = pd->actionList; act.lte(); act++ ) {
97 if ( act->numRefs() > 0 || act->numCondRefs > 0 )
98 act->actionId = nextActionId++;
101 /* Write the list. */
102 out << " <action_list length=\"" << nextActionId << "\">\n";
103 for ( ActionList::Iter act = pd->actionList; act.lte(); act++ ) {
104 if ( act->actionId >= 0 )
107 out << " </action_list>\n";
110 void XMLCodeGen::writeActionTableList()
112 /* Must first order the action tables based on their id. */
113 int numTables = nextActionTableId;
114 RedActionTable **tables = new RedActionTable*[numTables];
115 for ( ActionTableMap::Iter at = actionTableMap; at.lte(); at++ )
118 out << " <action_table_list length=\"" << numTables << "\">\n";
119 for ( int t = 0; t < numTables; t++ ) {
120 out << " <action_table id=\"" << t << "\" length=\"" <<
121 tables[t]->key.length() << "\">";
122 for ( ActionTable::Iter atel = tables[t]->key; atel.lte(); atel++ ) {
123 out << atel->value->actionId;
127 out << "</action_table>\n";
129 out << " </action_table_list>\n";
134 void XMLCodeGen::writeKey( Key key )
136 if ( keyOps->isSigned )
139 out << (unsigned long) key.getVal();
142 void XMLCodeGen::writeTrans( Key lowKey, Key highKey, TransAp *trans )
144 /* First reduce the action. */
145 RedActionTable *actionTable = 0;
146 if ( trans->actionTable.length() > 0 )
147 actionTable = actionTableMap.find( trans->actionTable );
149 /* Write the transition. */
155 if ( trans->toState != 0 )
156 out << " " << trans->toState->alg.stateNum;
160 if ( actionTable != 0 )
161 out << " " << actionTable->id;
167 void XMLCodeGen::writeTransList( StateAp *state )
169 TransListVect outList;
171 /* If there is only are no ranges the task is simple. */
172 if ( state->outList.length() > 0 ) {
173 /* Loop each source range. */
174 for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) {
175 /* Reduce the transition. If it reduced to anything then add it. */
176 appendTrans( outList, trans->lowKey, trans->highKey, trans );
180 out << " <trans_list length=\"" << outList.length() << "\">\n";
181 for ( TransListVect::Iter tvi = outList; tvi.lte(); tvi++ )
182 writeTrans( tvi->lowKey, tvi->highKey, tvi->value );
183 out << " </trans_list>\n";
186 void XMLCodeGen::writeEofTrans( StateAp *state )
188 RedActionTable *eofActions = 0;
189 if ( state->eofActionTable.length() > 0 )
190 eofActions = actionTableMap.find( state->eofActionTable );
192 /* The <eof_t> is used when there is an eof target, otherwise the eof
193 * action goes into state actions. */
194 if ( state->eofTarget != 0 ) {
195 out << " <eof_t>" << state->eofTarget->alg.stateNum;
197 if ( eofActions != 0 )
198 out << " " << eofActions->id;
202 out << "</eof_t>" << endl;
206 void XMLCodeGen::writeText( InlineItem *item )
208 if ( item->prev == 0 || item->prev->type != InlineItem::Text )
210 xmlEscapeHost( out, item->data, strlen(item->data) );
211 if ( item->next == 0 || item->next->type != InlineItem::Text )
215 void XMLCodeGen::writeGoto( InlineItem *item )
217 if ( pd->generatingSectionSubset )
218 out << "<goto>-1</goto>";
220 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
221 out << "<goto>" << targ->value->alg.stateNum << "</goto>";
225 void XMLCodeGen::writeCall( InlineItem *item )
227 if ( pd->generatingSectionSubset )
228 out << "<call>-1</call>";
230 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
231 out << "<call>" << targ->value->alg.stateNum << "</call>";
235 void XMLCodeGen::writeNext( InlineItem *item )
237 if ( pd->generatingSectionSubset )
238 out << "<next>-1</next>";
240 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
241 out << "<next>" << targ->value->alg.stateNum << "</next>";
245 void XMLCodeGen::writeGotoExpr( InlineItem *item )
247 out << "<goto_expr>";
248 writeInlineList( item->children );
249 out << "</goto_expr>";
252 void XMLCodeGen::writeCallExpr( InlineItem *item )
254 out << "<call_expr>";
255 writeInlineList( item->children );
256 out << "</call_expr>";
259 void XMLCodeGen::writeNextExpr( InlineItem *item )
261 out << "<next_expr>";
262 writeInlineList( item->children );
263 out << "</next_expr>";
266 void XMLCodeGen::writeEntry( InlineItem *item )
268 if ( pd->generatingSectionSubset )
269 out << "<entry>-1</entry>";
271 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
272 out << "<entry>" << targ->value->alg.stateNum << "</entry>";
276 void XMLCodeGen::writeActionExec( InlineItem *item )
279 writeInlineList( item->children );
283 void XMLCodeGen::writeLmOnLast( InlineItem *item )
285 out << "<set_tokend>1</set_tokend>";
287 if ( item->longestMatchPart->action != 0 ) {
288 out << "<sub_action>";
289 writeInlineList( item->longestMatchPart->action->inlineList );
290 out << "</sub_action>";
294 void XMLCodeGen::writeLmOnNext( InlineItem *item )
296 out << "<set_tokend>0</set_tokend>";
297 out << "<hold></hold>";
299 if ( item->longestMatchPart->action != 0 ) {
300 out << "<sub_action>";
301 writeInlineList( item->longestMatchPart->action->inlineList );
302 out << "</sub_action>";
306 void XMLCodeGen::writeLmOnLagBehind( InlineItem *item )
308 out << "<exec><get_tokend></get_tokend></exec>";
310 if ( item->longestMatchPart->action != 0 ) {
311 out << "<sub_action>";
312 writeInlineList( item->longestMatchPart->action->inlineList );
313 out << "</sub_action>";
317 void XMLCodeGen::writeLmSwitch( InlineItem *item )
319 LongestMatch *longestMatch = item->longestMatch;
320 out << "<lm_switch>\n";
322 /* We can't put the <exec> here because we may need to handle the error
323 * case and in that case p should not be changed. Instead use a default
324 * label in the switch to adjust p when user actions are not set. An id of
325 * -1 indicates the default. */
327 if ( longestMatch->lmSwitchHandlesError ) {
328 /* If the switch handles error then we should have also forced the
330 assert( fsm->errState != 0 );
332 out << " <sub_action id=\"0\">";
333 out << "<goto>" << fsm->errState->alg.stateNum << "</goto>";
334 out << "</sub_action>\n";
337 bool needDefault = false;
338 for ( LmPartList::Iter lmi = *longestMatch->longestMatchList; lmi.lte(); lmi++ ) {
339 if ( lmi->inLmSelect ) {
340 if ( lmi->action == 0 )
343 /* Open the action. Write it with the context that sets up _p
344 * when doing control flow changes from inside the machine. */
345 out << " <sub_action id=\"" << lmi->longestMatchId << "\">";
346 out << "<exec><get_tokend></get_tokend></exec>";
347 writeInlineList( lmi->action->inlineList );
348 out << "</sub_action>\n";
354 out << " <sub_action id=\"-1\"><exec><get_tokend>"
355 "</get_tokend></exec></sub_action>\n";
358 out << " </lm_switch>";
361 void XMLCodeGen::writeInlineList( InlineList *inlineList )
363 for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
364 switch ( item->type ) {
365 case InlineItem::Text:
368 case InlineItem::Goto:
371 case InlineItem::GotoExpr:
372 writeGotoExpr( item );
374 case InlineItem::Call:
377 case InlineItem::CallExpr:
378 writeCallExpr( item );
380 case InlineItem::Next:
383 case InlineItem::NextExpr:
384 writeNextExpr( item );
386 case InlineItem::Break:
387 out << "<break></break>";
389 case InlineItem::Ret:
390 out << "<ret></ret>";
392 case InlineItem::PChar:
393 out << "<pchar></pchar>";
395 case InlineItem::Char:
396 out << "<char></char>";
398 case InlineItem::Curs:
399 out << "<curs></curs>";
401 case InlineItem::Targs:
402 out << "<targs></targs>";
404 case InlineItem::Entry:
408 case InlineItem::Hold:
409 out << "<hold></hold>";
411 case InlineItem::Exec:
412 writeActionExec( item );
415 case InlineItem::LmSetActId:
416 out << "<set_act>" <<
417 item->longestMatchPart->longestMatchId <<
420 case InlineItem::LmSetTokEnd:
421 out << "<set_tokend>1</set_tokend>";
424 case InlineItem::LmOnLast:
425 writeLmOnLast( item );
427 case InlineItem::LmOnNext:
428 writeLmOnNext( item );
430 case InlineItem::LmOnLagBehind:
431 writeLmOnLagBehind( item );
433 case InlineItem::LmSwitch:
434 writeLmSwitch( item );
437 case InlineItem::LmInitAct:
438 out << "<init_act></init_act>";
440 case InlineItem::LmInitTokStart:
441 out << "<init_tokstart></init_tokstart>";
443 case InlineItem::LmSetTokStart:
444 out << "<set_tokstart></set_tokstart>";
450 BackendGen::BackendGen( char *fsmName, ParseData *pd, FsmAp *fsm, CodeGenData *cgd )
452 GenBase(fsmName, pd, fsm),
458 void BackendGen::makeText( GenInlineList *outList, InlineItem *item )
460 GenInlineItem *inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::Text );
461 inlineItem->data = item->data;
463 outList->append( inlineItem );
466 void BackendGen::makeTargetItem( GenInlineList *outList, long entryId, GenInlineItem::Type type )
469 if ( pd->generatingSectionSubset )
472 EntryMapEl *targ = fsm->entryPoints.find( entryId );
473 targetState = targ->value->alg.stateNum;
477 GenInlineItem *inlineItem = new GenInlineItem( InputLoc(), type );
478 inlineItem->targId = targetState;
479 outList->append( inlineItem );
482 /* Make a sublist item with a given type. */
483 void BackendGen::makeSubList( GenInlineList *outList,
484 InlineList *inlineList, GenInlineItem::Type type )
486 /* Fill the sub list. */
487 GenInlineList *subList = new GenInlineList;
488 makeGenInlineList( subList, inlineList );
491 GenInlineItem *inlineItem = new GenInlineItem( InputLoc(), type );
492 inlineItem->children = subList;
493 outList->append( inlineItem );
496 void BackendGen::makeLmOnLast( GenInlineList *outList, InlineItem *item )
498 makeSetTokend( outList, 1 );
500 if ( item->longestMatchPart->action != 0 ) {
501 makeSubList( outList,
502 item->longestMatchPart->action->inlineList,
503 GenInlineItem::SubAction );
507 void BackendGen::makeLmOnNext( GenInlineList *outList, InlineItem *item )
509 makeSetTokend( outList, 0 );
510 outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Hold ) );
512 if ( item->longestMatchPart->action != 0 ) {
513 makeSubList( outList,
514 item->longestMatchPart->action->inlineList,
515 GenInlineItem::SubAction );
519 void BackendGen::makeExecGetTokend( GenInlineList *outList )
521 /* Make the Exec item. */
522 GenInlineItem *execItem = new GenInlineItem( InputLoc(), GenInlineItem::Exec );
523 execItem->children = new GenInlineList;
525 /* Make the GetTokEnd */
526 GenInlineItem *getTokend = new GenInlineItem( InputLoc(), GenInlineItem::LmGetTokEnd );
527 execItem->children->append( getTokend );
529 outList->append( execItem );
532 void BackendGen::makeLmOnLagBehind( GenInlineList *outList, InlineItem *item )
534 /* Jump to the tokend. */
535 makeExecGetTokend( outList );
537 if ( item->longestMatchPart->action != 0 ) {
538 makeSubList( outList,
539 item->longestMatchPart->action->inlineList,
540 GenInlineItem::SubAction );
544 void BackendGen::makeLmSwitch( GenInlineList *outList, InlineItem *item )
546 GenInlineItem *lmSwitch = new GenInlineItem( InputLoc(), GenInlineItem::LmSwitch );
547 GenInlineList *lmList = lmSwitch->children = new GenInlineList;
548 LongestMatch *longestMatch = item->longestMatch;
550 /* We can't put the <exec> here because we may need to handle the error
551 * case and in that case p should not be changed. Instead use a default
552 * label in the switch to adjust p when user actions are not set. An id of
553 * -1 indicates the default. */
555 if ( longestMatch->lmSwitchHandlesError ) {
556 /* If the switch handles error then we should have also forced the
558 assert( fsm->errState != 0 );
560 GenInlineItem *errCase = new GenInlineItem( InputLoc(), GenInlineItem::SubAction );
562 errCase->children = new GenInlineList;
565 GenInlineItem *gotoItem = new GenInlineItem( InputLoc(), GenInlineItem::Goto );
566 gotoItem->targId = fsm->errState->alg.stateNum;
567 errCase->children->append( gotoItem );
569 lmList->append( errCase );
572 bool needDefault = false;
573 for ( LmPartList::Iter lmi = *longestMatch->longestMatchList; lmi.lte(); lmi++ ) {
574 if ( lmi->inLmSelect ) {
575 if ( lmi->action == 0 )
578 /* Open the action. Write it with the context that sets up _p
579 * when doing control flow changes from inside the machine. */
580 GenInlineItem *lmCase = new GenInlineItem( InputLoc(),
581 GenInlineItem::SubAction );
582 lmCase->lmId = lmi->longestMatchId;
583 lmCase->children = new GenInlineList;
585 makeExecGetTokend( lmCase->children );
586 makeGenInlineList( lmCase->children, lmi->action->inlineList );
588 lmList->append( lmCase );
594 GenInlineItem *defCase = new GenInlineItem( InputLoc(),
595 GenInlineItem::SubAction );
597 defCase->children = new GenInlineList;
599 makeExecGetTokend( defCase->children );
601 lmList->append( defCase );
604 outList->append( lmSwitch );
607 void BackendGen::makeSetTokend( GenInlineList *outList, long offset )
609 GenInlineItem *inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::LmSetTokEnd );
610 inlineItem->offset = offset;
611 outList->append( inlineItem );
614 void BackendGen::makeSetAct( GenInlineList *outList, long lmId )
616 GenInlineItem *inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::LmSetActId );
617 inlineItem->lmId = lmId;
618 outList->append( inlineItem );
621 void BackendGen::makeGenInlineList( GenInlineList *outList, InlineList *inList )
623 for ( InlineList::Iter item = *inList; item.lte(); item++ ) {
624 switch ( item->type ) {
625 case InlineItem::Text:
626 makeText( outList, item );
628 case InlineItem::Goto:
629 makeTargetItem( outList, item->nameTarg->id, GenInlineItem::Goto );
631 case InlineItem::GotoExpr:
632 makeSubList( outList, item->children, GenInlineItem::GotoExpr );
634 case InlineItem::Call:
635 makeTargetItem( outList, item->nameTarg->id, GenInlineItem::Call );
637 case InlineItem::CallExpr:
638 makeSubList( outList, item->children, GenInlineItem::CallExpr );
640 case InlineItem::Next:
641 makeTargetItem( outList, item->nameTarg->id, GenInlineItem::Next );
643 case InlineItem::NextExpr:
644 makeSubList( outList, item->children, GenInlineItem::NextExpr );
646 case InlineItem::Break:
647 outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Break ) );
649 case InlineItem::Ret:
650 outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Ret ) );
652 case InlineItem::PChar:
653 outList->append( new GenInlineItem( InputLoc(), GenInlineItem::PChar ) );
655 case InlineItem::Char:
656 outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Char ) );
658 case InlineItem::Curs:
659 outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Curs ) );
661 case InlineItem::Targs:
662 outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Targs ) );
664 case InlineItem::Entry:
665 makeTargetItem( outList, item->nameTarg->id, GenInlineItem::Entry );
668 case InlineItem::Hold:
669 outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Hold ) );
671 case InlineItem::Exec:
672 makeSubList( outList, item->children, GenInlineItem::Exec );
675 case InlineItem::LmSetActId:
676 makeSetAct( outList, item->longestMatchPart->longestMatchId );
678 case InlineItem::LmSetTokEnd:
679 makeSetTokend( outList, 1 );
682 case InlineItem::LmOnLast:
683 makeLmOnLast( outList, item );
685 case InlineItem::LmOnNext:
686 makeLmOnNext( outList, item );
688 case InlineItem::LmOnLagBehind:
689 makeLmOnLagBehind( outList, item );
691 case InlineItem::LmSwitch:
692 makeLmSwitch( outList, item );
695 case InlineItem::LmInitAct:
696 outList->append( new GenInlineItem( InputLoc(), GenInlineItem::LmInitAct ) );
698 case InlineItem::LmInitTokStart:
699 outList->append( new GenInlineItem( InputLoc(), GenInlineItem::LmInitTokStart ) );
701 case InlineItem::LmSetTokStart:
702 outList->append( new GenInlineItem( InputLoc(), GenInlineItem::LmSetTokStart ) );
703 cgd->hasLongestMatch = true;
710 void XMLCodeGen::writeAction( Action *action )
712 out << " <action id=\"" << action->actionId << "\"";
713 if ( action->name != 0 )
714 out << " name=\"" << action->name << "\"";
715 out << " line=\"" << action->loc.line << "\" col=\"" << action->loc.col << "\">";
716 writeInlineList( action->inlineList );
717 out << "</action>\n";
720 void xmlEscapeHost( std::ostream &out, char *data, long len )
722 char *end = data + len;
723 while ( data != end ) {
725 case '<': out << "<"; break;
726 case '>': out << ">"; break;
727 case '&': out << "&"; break;
728 default: out << *data; break;
734 void XMLCodeGen::writeStateActions( StateAp *state )
736 RedActionTable *toStateActions = 0;
737 if ( state->toStateActionTable.length() > 0 )
738 toStateActions = actionTableMap.find( state->toStateActionTable );
740 RedActionTable *fromStateActions = 0;
741 if ( state->fromStateActionTable.length() > 0 )
742 fromStateActions = actionTableMap.find( state->fromStateActionTable );
744 /* EOF actions go out here only if the state has no eof target. If it has
745 * an eof target then an eof transition will be used instead. */
746 RedActionTable *eofActions = 0;
747 if ( state->eofTarget == 0 && state->eofActionTable.length() > 0 )
748 eofActions = actionTableMap.find( state->eofActionTable );
750 if ( toStateActions != 0 || fromStateActions != 0 || eofActions != 0 ) {
751 out << " <state_actions>";
752 if ( toStateActions != 0 )
753 out << toStateActions->id;
757 if ( fromStateActions != 0 )
758 out << " " << fromStateActions->id;
762 if ( eofActions != 0 )
763 out << " " << eofActions->id;
767 out << "</state_actions>\n";
771 void XMLCodeGen::writeStateConditions( StateAp *state )
773 if ( state->stateCondList.length() > 0 ) {
774 out << " <cond_list length=\"" << state->stateCondList.length() << "\">\n";
775 for ( StateCondList::Iter scdi = state->stateCondList; scdi.lte(); scdi++ ) {
777 writeKey( scdi->lowKey );
779 writeKey( scdi->highKey );
781 out << scdi->condSpace->condSpaceId;
784 out << " </cond_list>\n";
788 void XMLCodeGen::writeStateList()
790 /* Write the list of states. */
791 out << " <state_list length=\"" << fsm->stateList.length() << "\">\n";
792 for ( StateList::Iter st = fsm->stateList; st.lte(); st++ ) {
793 out << " <state id=\"" << st->alg.stateNum << "\"";
794 if ( st->isFinState() )
795 out << " final=\"t\"";
798 writeStateActions( st );
800 writeStateConditions( st );
801 writeTransList( st );
803 out << " </state>\n";
808 out << " </state_list>\n";
811 bool XMLCodeGen::writeNameInst( NameInst *nameInst )
813 bool written = false;
814 if ( nameInst->parent != 0 )
815 written = writeNameInst( nameInst->parent );
817 if ( nameInst->name != 0 ) {
820 out << nameInst->name;
827 void XMLCodeGen::writeEntryPoints()
829 /* List of entry points other than start state. */
830 if ( fsm->entryPoints.length() > 0 || pd->lmRequiresErrorState ) {
831 out << " <entry_points";
832 if ( pd->lmRequiresErrorState )
833 out << " error=\"t\"";
835 for ( EntryMap::Iter en = fsm->entryPoints; en.lte(); en++ ) {
836 /* Get the name instantiation from nameIndex. */
837 NameInst *nameInst = pd->nameIndex[en->key];
838 StateAp *state = en->value;
839 out << " <entry name=\"";
840 writeNameInst( nameInst );
841 out << "\">" << state->alg.stateNum << "</entry>\n";
843 out << " </entry_points>\n";
847 void XMLCodeGen::writeMachine()
849 /* Open the machine. */
850 out << " <machine>\n";
853 reduceActionTables();
856 writeActionTableList();
860 out << " <start_state>" << fsm->startState->alg.stateNum <<
864 if ( fsm->errState != 0 ) {
865 out << " <error_state>" << fsm->errState->alg.stateNum <<
872 out << " </machine>\n";
876 void XMLCodeGen::writeConditions()
878 if ( condData->condSpaceMap.length() > 0 ) {
879 long nextCondSpaceId = 0;
880 for ( CondSpaceMap::Iter cs = condData->condSpaceMap; cs.lte(); cs++ )
881 cs->condSpaceId = nextCondSpaceId++;
883 out << " <cond_space_list length=\"" << condData->condSpaceMap.length() << "\">\n";
884 for ( CondSpaceMap::Iter cs = condData->condSpaceMap; cs.lte(); cs++ ) {
885 out << " <cond_space id=\"" << cs->condSpaceId <<
886 "\" length=\"" << cs->condSet.length() << "\">";
887 writeKey( cs->baseKey );
888 for ( CondSet::Iter csi = cs->condSet; csi.lte(); csi++ )
889 out << " " << (*csi)->actionId;
890 out << "</cond_space>\n";
892 out << " </cond_space_list>\n";
896 void XMLCodeGen::writeExports()
898 if ( pd->exportList.length() > 0 ) {
899 out << " <exports>\n";
900 for ( ExportList::Iter exp = pd->exportList; exp.lte(); exp++ ) {
901 out << " <ex name=\"" << exp->name << "\">";
902 writeKey( exp->key );
905 out << " </exports>\n";
909 void XMLCodeGen::writeXML()
911 /* Open the definition. */
912 out << "<ragel_def name=\"" << fsmName << "\">\n";
915 out << " <alphtype>" << keyOps->alphType->internalName << "</alphtype>\n";
917 /* Getkey expression. */
918 if ( pd->getKeyExpr != 0 ) {
920 writeInlineList( pd->getKeyExpr );
921 out << "</getkey>\n";
924 /* Access expression. */
925 if ( pd->accessExpr != 0 ) {
927 writeInlineList( pd->accessExpr );
928 out << "</access>\n";
931 /* PrePush expression. */
932 if ( pd->prePushExpr != 0 ) {
934 writeInlineList( pd->prePushExpr );
935 out << "</prepush>\n";
938 /* PostPop expression. */
939 if ( pd->postPopExpr != 0 ) {
941 writeInlineList( pd->postPopExpr );
942 out << "</postpop>\n";
946 * Variable expressions.
949 if ( pd->pExpr != 0 ) {
951 writeInlineList( pd->pExpr );
952 out << "</p_expr>\n";
955 if ( pd->peExpr != 0 ) {
957 writeInlineList( pd->peExpr );
958 out << "</pe_expr>\n";
961 if ( pd->eofExpr != 0 ) {
962 out << " <eof_expr>";
963 writeInlineList( pd->eofExpr );
964 out << "</eof_expr>\n";
967 if ( pd->csExpr != 0 ) {
969 writeInlineList( pd->csExpr );
970 out << "</cs_expr>\n";
973 if ( pd->topExpr != 0 ) {
974 out << " <top_expr>";
975 writeInlineList( pd->topExpr );
976 out << "</top_expr>\n";
979 if ( pd->stackExpr != 0 ) {
980 out << " <stack_expr>";
981 writeInlineList( pd->stackExpr );
982 out << "</stack_expr>\n";
985 if ( pd->actExpr != 0 ) {
986 out << " <act_expr>";
987 writeInlineList( pd->actExpr );
988 out << "</act_expr>\n";
991 if ( pd->tokstartExpr != 0 ) {
992 out << " <tokstart_expr>";
993 writeInlineList( pd->tokstartExpr );
994 out << "</tokstart_expr>\n";
997 if ( pd->tokendExpr != 0 ) {
998 out << " <tokend_expr>";
999 writeInlineList( pd->tokendExpr );
1000 out << "</tokend_expr>\n";
1003 if ( pd->dataExpr != 0 ) {
1004 out << " <data_expr>";
1005 writeInlineList( pd->dataExpr );
1006 out << "</data_expr>\n";
1017 void BackendGen::makeExports()
1019 for ( ExportList::Iter exp = pd->exportList; exp.lte(); exp++ )
1020 cgd->exportList.append( new Export( exp->name, exp->key ) );
1023 void BackendGen::makeAction( Action *action )
1025 GenInlineList *genList = new GenInlineList;
1026 makeGenInlineList( genList, action->inlineList );
1028 cgd->newAction( curAction++, action->name,
1029 action->loc.line, action->loc.col, genList );
1033 void BackendGen::makeActionList()
1035 /* Determine which actions to write. */
1036 int nextActionId = 0;
1037 for ( ActionList::Iter act = pd->actionList; act.lte(); act++ ) {
1038 if ( act->numRefs() > 0 || act->numCondRefs > 0 )
1039 act->actionId = nextActionId++;
1042 /* Write the list. */
1043 cgd->initActionList( nextActionId );
1046 for ( ActionList::Iter act = pd->actionList; act.lte(); act++ ) {
1047 if ( act->actionId >= 0 )
1052 void BackendGen::makeActionTableList()
1054 /* Must first order the action tables based on their id. */
1055 int numTables = nextActionTableId;
1056 RedActionTable **tables = new RedActionTable*[numTables];
1057 for ( ActionTableMap::Iter at = actionTableMap; at.lte(); at++ )
1058 tables[at->id] = at;
1060 cgd->initActionTableList( numTables );
1063 for ( int t = 0; t < numTables; t++ ) {
1064 long length = tables[t]->key.length();
1066 /* Collect the action table. */
1067 RedAction *redAct = cgd->allActionTables + curActionTable;
1068 redAct->actListId = curActionTable;
1069 redAct->key.setAsNew( length );
1071 for ( ActionTable::Iter atel = tables[t]->key; atel.lte(); atel++ ) {
1072 redAct->key[atel.pos()].key = 0;
1073 redAct->key[atel.pos()].value = cgd->allActions +
1074 atel->value->actionId;
1077 /* Insert into the action table map. */
1078 cgd->redFsm->actionMap.insert( redAct );
1080 curActionTable += 1;
1086 void BackendGen::makeConditions()
1088 if ( condData->condSpaceMap.length() > 0 ) {
1089 long nextCondSpaceId = 0;
1090 for ( CondSpaceMap::Iter cs = condData->condSpaceMap; cs.lte(); cs++ )
1091 cs->condSpaceId = nextCondSpaceId++;
1093 long listLength = condData->condSpaceMap.length();
1094 cgd->initCondSpaceList( listLength );
1097 for ( CondSpaceMap::Iter cs = condData->condSpaceMap; cs.lte(); cs++ ) {
1098 long id = cs->condSpaceId;
1099 cgd->newCondSpace( curCondSpace, id, cs->baseKey );
1100 for ( CondSet::Iter csi = cs->condSet; csi.lte(); csi++ )
1101 cgd->condSpaceItem( curCondSpace, (*csi)->actionId );
1107 bool BackendGen::makeNameInst( std::string &res, NameInst *nameInst )
1109 bool written = false;
1110 if ( nameInst->parent != 0 )
1111 written = makeNameInst( res, nameInst->parent );
1113 if ( nameInst->name != 0 ) {
1116 res += nameInst->name;
1123 void BackendGen::makeEntryPoints()
1125 /* List of entry points other than start state. */
1126 if ( fsm->entryPoints.length() > 0 || pd->lmRequiresErrorState ) {
1127 if ( pd->lmRequiresErrorState )
1128 cgd->setForcedErrorState();
1130 for ( EntryMap::Iter en = fsm->entryPoints; en.lte(); en++ ) {
1131 /* Get the name instantiation from nameIndex. */
1132 NameInst *nameInst = pd->nameIndex[en->key];
1134 makeNameInst( name, nameInst );
1135 StateAp *state = en->value;
1136 cgd->addEntryPoint( strdup(name.c_str()), state->alg.stateNum );
1141 void BackendGen::makeStateActions( StateAp *state )
1143 RedActionTable *toStateActions = 0;
1144 if ( state->toStateActionTable.length() > 0 )
1145 toStateActions = actionTableMap.find( state->toStateActionTable );
1147 RedActionTable *fromStateActions = 0;
1148 if ( state->fromStateActionTable.length() > 0 )
1149 fromStateActions = actionTableMap.find( state->fromStateActionTable );
1151 /* EOF actions go out here only if the state has no eof target. If it has
1152 * an eof target then an eof transition will be used instead. */
1153 RedActionTable *eofActions = 0;
1154 if ( state->eofTarget == 0 && state->eofActionTable.length() > 0 )
1155 eofActions = actionTableMap.find( state->eofActionTable );
1157 if ( toStateActions != 0 || fromStateActions != 0 || eofActions != 0 ) {
1159 if ( toStateActions != 0 )
1160 to = toStateActions->id;
1163 if ( fromStateActions != 0 )
1164 from = fromStateActions->id;
1167 if ( eofActions != 0 )
1168 eof = eofActions->id;
1170 cgd->setStateActions( curState, to, from, eof );
1174 void BackendGen::makeEofTrans( StateAp *state )
1176 RedActionTable *eofActions = 0;
1177 if ( state->eofActionTable.length() > 0 )
1178 eofActions = actionTableMap.find( state->eofActionTable );
1180 /* The EOF trans is used when there is an eof target, otherwise the eof
1181 * action goes into state actions. */
1182 if ( state->eofTarget != 0 ) {
1183 long targ = state->eofTarget->alg.stateNum;
1185 if ( eofActions != 0 )
1186 action = eofActions->id;
1188 cgd->setEofTrans( curState, targ, action );
1192 void BackendGen::makeStateConditions( StateAp *state )
1194 if ( state->stateCondList.length() > 0 ) {
1195 long length = state->stateCondList.length();
1196 cgd->initStateCondList( curState, length );
1199 for ( StateCondList::Iter scdi = state->stateCondList; scdi.lte(); scdi++ ) {
1200 cgd->addStateCond( curState, scdi->lowKey, scdi->highKey,
1201 scdi->condSpace->condSpaceId );
1206 void BackendGen::makeTrans( Key lowKey, Key highKey, TransAp *trans )
1208 /* First reduce the action. */
1209 RedActionTable *actionTable = 0;
1210 if ( trans->actionTable.length() > 0 )
1211 actionTable = actionTableMap.find( trans->actionTable );
1214 if ( trans->toState != 0 )
1215 targ = trans->toState->alg.stateNum;
1218 if ( actionTable != 0 )
1219 action = actionTable->id;
1221 cgd->newTrans( curState, curTrans++, lowKey, highKey, targ, action );
1224 void BackendGen::makeTransList( StateAp *state )
1226 TransListVect outList;
1228 /* If there is only are no ranges the task is simple. */
1229 if ( state->outList.length() > 0 ) {
1230 /* Loop each source range. */
1231 for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) {
1232 /* Reduce the transition. If it reduced to anything then add it. */
1233 appendTrans( outList, trans->lowKey, trans->highKey, trans );
1237 cgd->initTransList( curState, outList.length() );
1240 for ( TransListVect::Iter tvi = outList; tvi.lte(); tvi++ )
1241 makeTrans( tvi->lowKey, tvi->highKey, tvi->value );
1243 cgd->finishTransList( curState );
1247 void BackendGen::makeStateList()
1249 /* Write the list of states. */
1250 long length = fsm->stateList.length();
1251 cgd->initStateList( length );
1253 for ( StateList::Iter st = fsm->stateList; st.lte(); st++ ) {
1254 makeStateActions( st );
1256 makeStateConditions( st );
1257 makeTransList( st );
1259 long id = st->alg.stateNum;
1260 cgd->setId( curState, id );
1262 if ( st->isFinState() )
1263 cgd->setFinal( curState );
1270 void BackendGen::makeMachine()
1272 cgd->createMachine();
1274 /* Action tables. */
1275 reduceActionTables();
1278 makeActionTableList();
1282 cgd->setStartState( fsm->startState->alg.stateNum );
1285 if ( fsm->errState != 0 )
1286 cgd->setErrorState( fsm->errState->alg.stateNum );
1291 cgd->closeMachine();
1294 void BackendGen::close_ragel_def()
1296 /* Do this before distributing transitions out to singles and defaults
1297 * makes life easier. */
1298 cgd->redFsm->maxKey = cgd->findMaxKey();
1300 cgd->redFsm->assignActionLocs();
1302 /* Find the first final state (The final state with the lowest id). */
1303 cgd->redFsm->findFirstFinState();
1305 /* Call the user's callback. */
1306 cgd->finishRagelDef();
1310 void BackendGen::makeBackend()
1312 /* Alphabet type. */
1313 cgd->setAlphType( keyOps->alphType->internalName );
1315 /* Getkey expression. */
1316 if ( pd->getKeyExpr != 0 ) {
1317 cgd->getKeyExpr = new GenInlineList;
1318 makeGenInlineList( cgd->getKeyExpr, pd->getKeyExpr );
1321 /* Access expression. */
1322 if ( pd->accessExpr != 0 ) {
1323 cgd->accessExpr = new GenInlineList;
1324 makeGenInlineList( cgd->accessExpr, pd->accessExpr );
1327 /* PrePush expression. */
1328 if ( pd->prePushExpr != 0 ) {
1329 cgd->prePushExpr = new GenInlineList;
1330 makeGenInlineList( cgd->prePushExpr, pd->prePushExpr );
1333 /* PostPop expression. */
1334 if ( pd->postPopExpr != 0 ) {
1335 cgd->postPopExpr = new GenInlineList;
1336 makeGenInlineList( cgd->postPopExpr, pd->postPopExpr );
1340 * Variable expressions.
1343 if ( pd->pExpr != 0 ) {
1344 cgd->pExpr = new GenInlineList;
1345 makeGenInlineList( cgd->pExpr, pd->pExpr );
1348 if ( pd->peExpr != 0 ) {
1349 cgd->peExpr = new GenInlineList;
1350 makeGenInlineList( cgd->peExpr, pd->peExpr );
1353 if ( pd->eofExpr != 0 ) {
1354 cgd->eofExpr = new GenInlineList;
1355 makeGenInlineList( cgd->eofExpr, pd->eofExpr );
1358 if ( pd->csExpr != 0 ) {
1359 cgd->csExpr = new GenInlineList;
1360 makeGenInlineList( cgd->csExpr, pd->csExpr );
1363 if ( pd->topExpr != 0 ) {
1364 cgd->topExpr = new GenInlineList;
1365 makeGenInlineList( cgd->topExpr, pd->topExpr );
1368 if ( pd->stackExpr != 0 ) {
1369 cgd->stackExpr = new GenInlineList;
1370 makeGenInlineList( cgd->stackExpr, pd->stackExpr );
1373 if ( pd->actExpr != 0 ) {
1374 cgd->actExpr = new GenInlineList;
1375 makeGenInlineList( cgd->actExpr, pd->actExpr );
1378 if ( pd->tokstartExpr != 0 ) {
1379 cgd->tokstartExpr = new GenInlineList;
1380 makeGenInlineList( cgd->tokstartExpr, pd->tokstartExpr );
1383 if ( pd->tokendExpr != 0 ) {
1384 cgd->tokendExpr = new GenInlineList;
1385 makeGenInlineList( cgd->tokendExpr, pd->tokendExpr );
1388 if ( pd->dataExpr != 0 ) {
1389 cgd->dataExpr = new GenInlineList;
1390 makeGenInlineList( cgd->dataExpr, pd->dataExpr );