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, InputData &inputData )
44 void GenBase::appendTrans( TransListVect &outList, Key lowKey,
45 Key highKey, TransAp *trans )
47 if ( trans->toState != 0 || trans->actionTable.length() > 0 )
48 outList.append( TransEl( lowKey, highKey, trans ) );
51 void GenBase::reduceActionTables()
53 /* Reduce the actions tables to a set. */
54 for ( StateList::Iter st = fsm->stateList; st.lte(); st++ ) {
55 RedActionTable *actionTable = 0;
57 /* Reduce To State Actions. */
58 if ( st->toStateActionTable.length() > 0 ) {
59 if ( actionTableMap.insert( st->toStateActionTable, &actionTable ) )
60 actionTable->id = nextActionTableId++;
63 /* Reduce From State Actions. */
64 if ( st->fromStateActionTable.length() > 0 ) {
65 if ( actionTableMap.insert( st->fromStateActionTable, &actionTable ) )
66 actionTable->id = nextActionTableId++;
69 /* Reduce EOF actions. */
70 if ( st->eofActionTable.length() > 0 ) {
71 if ( actionTableMap.insert( st->eofActionTable, &actionTable ) )
72 actionTable->id = nextActionTableId++;
75 /* Loop the transitions and reduce their actions. */
76 for ( TransList::Iter trans = st->outList; trans.lte(); trans++ ) {
77 if ( trans->actionTable.length() > 0 ) {
78 if ( actionTableMap.insert( trans->actionTable, &actionTable ) )
79 actionTable->id = nextActionTableId++;
85 XMLCodeGen::XMLCodeGen( char *fsmName, ParseData *pd, FsmAp *fsm,
86 std::ostream &out, InputData &inputData )
88 GenBase(fsmName, pd, fsm, inputData),
94 void XMLCodeGen::writeActionList()
96 /* Determine which actions to write. */
98 for ( ActionList::Iter act = pd->actionList; act.lte(); act++ ) {
99 if ( act->numRefs() > 0 || act->numCondRefs > 0 )
100 act->actionId = nextActionId++;
103 /* Write the list. */
104 out << " <action_list length=\"" << nextActionId << "\">\n";
105 for ( ActionList::Iter act = pd->actionList; act.lte(); act++ ) {
106 if ( act->actionId >= 0 )
109 out << " </action_list>\n";
112 void XMLCodeGen::writeActionTableList()
114 /* Must first order the action tables based on their id. */
115 int numTables = nextActionTableId;
116 RedActionTable **tables = new RedActionTable*[numTables];
117 for ( ActionTableMap::Iter at = actionTableMap; at.lte(); at++ )
120 out << " <action_table_list length=\"" << numTables << "\">\n";
121 for ( int t = 0; t < numTables; t++ ) {
122 out << " <action_table id=\"" << t << "\" length=\"" <<
123 tables[t]->key.length() << "\">";
124 for ( ActionTable::Iter atel = tables[t]->key; atel.lte(); atel++ ) {
125 out << atel->value->actionId;
129 out << "</action_table>\n";
131 out << " </action_table_list>\n";
136 void XMLCodeGen::writeKey( Key key )
138 if ( keyOps->isSigned )
141 out << (unsigned long) key.getVal();
144 void XMLCodeGen::writeTrans( Key lowKey, Key highKey, TransAp *trans )
146 /* First reduce the action. */
147 RedActionTable *actionTable = 0;
148 if ( trans->actionTable.length() > 0 )
149 actionTable = actionTableMap.find( trans->actionTable );
151 /* Write the transition. */
157 if ( trans->toState != 0 )
158 out << " " << trans->toState->alg.stateNum;
162 if ( actionTable != 0 )
163 out << " " << actionTable->id;
169 void XMLCodeGen::writeTransList( StateAp *state )
171 TransListVect outList;
173 /* If there is only are no ranges the task is simple. */
174 if ( state->outList.length() > 0 ) {
175 /* Loop each source range. */
176 for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) {
177 /* Reduce the transition. If it reduced to anything then add it. */
178 appendTrans( outList, trans->lowKey, trans->highKey, trans );
182 out << " <trans_list length=\"" << outList.length() << "\">\n";
183 for ( TransListVect::Iter tvi = outList; tvi.lte(); tvi++ )
184 writeTrans( tvi->lowKey, tvi->highKey, tvi->value );
185 out << " </trans_list>\n";
188 void XMLCodeGen::writeEofTrans( StateAp *state )
190 RedActionTable *eofActions = 0;
191 if ( state->eofActionTable.length() > 0 )
192 eofActions = actionTableMap.find( state->eofActionTable );
194 /* The <eof_t> is used when there is an eof target, otherwise the eof
195 * action goes into state actions. */
196 if ( state->eofTarget != 0 ) {
197 out << " <eof_t>" << state->eofTarget->alg.stateNum;
199 if ( eofActions != 0 )
200 out << " " << eofActions->id;
204 out << "</eof_t>" << endl;
208 void XMLCodeGen::writeText( InlineItem *item )
210 if ( item->prev == 0 || item->prev->type != InlineItem::Text )
212 xmlEscapeHost( out, item->data, strlen(item->data) );
213 if ( item->next == 0 || item->next->type != InlineItem::Text )
217 void XMLCodeGen::writeGoto( InlineItem *item )
219 if ( pd->generatingSectionSubset )
220 out << "<goto>-1</goto>";
222 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
223 out << "<goto>" << targ->value->alg.stateNum << "</goto>";
227 void XMLCodeGen::writeCall( InlineItem *item )
229 if ( pd->generatingSectionSubset )
230 out << "<call>-1</call>";
232 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
233 out << "<call>" << targ->value->alg.stateNum << "</call>";
237 void XMLCodeGen::writeNext( InlineItem *item )
239 if ( pd->generatingSectionSubset )
240 out << "<next>-1</next>";
242 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
243 out << "<next>" << targ->value->alg.stateNum << "</next>";
247 void XMLCodeGen::writeGotoExpr( InlineItem *item )
249 out << "<goto_expr>";
250 writeInlineList( item->children );
251 out << "</goto_expr>";
254 void XMLCodeGen::writeCallExpr( InlineItem *item )
256 out << "<call_expr>";
257 writeInlineList( item->children );
258 out << "</call_expr>";
261 void XMLCodeGen::writeNextExpr( InlineItem *item )
263 out << "<next_expr>";
264 writeInlineList( item->children );
265 out << "</next_expr>";
268 void XMLCodeGen::writeEntry( InlineItem *item )
270 if ( pd->generatingSectionSubset )
271 out << "<entry>-1</entry>";
273 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
274 out << "<entry>" << targ->value->alg.stateNum << "</entry>";
278 void XMLCodeGen::writeActionExec( InlineItem *item )
281 writeInlineList( item->children );
285 void XMLCodeGen::writeLmOnLast( InlineItem *item )
287 out << "<set_tokend>1</set_tokend>";
289 if ( item->longestMatchPart->action != 0 ) {
290 out << "<sub_action>";
291 writeInlineList( item->longestMatchPart->action->inlineList );
292 out << "</sub_action>";
296 void XMLCodeGen::writeLmOnNext( InlineItem *item )
298 out << "<set_tokend>0</set_tokend>";
299 out << "<hold></hold>";
301 if ( item->longestMatchPart->action != 0 ) {
302 out << "<sub_action>";
303 writeInlineList( item->longestMatchPart->action->inlineList );
304 out << "</sub_action>";
308 void XMLCodeGen::writeLmOnLagBehind( InlineItem *item )
310 out << "<exec><get_tokend></get_tokend></exec>";
312 if ( item->longestMatchPart->action != 0 ) {
313 out << "<sub_action>";
314 writeInlineList( item->longestMatchPart->action->inlineList );
315 out << "</sub_action>";
319 void XMLCodeGen::writeLmSwitch( InlineItem *item )
321 LongestMatch *longestMatch = item->longestMatch;
322 out << "<lm_switch>\n";
324 /* We can't put the <exec> here because we may need to handle the error
325 * case and in that case p should not be changed. Instead use a default
326 * label in the switch to adjust p when user actions are not set. An id of
327 * -1 indicates the default. */
329 if ( longestMatch->lmSwitchHandlesError ) {
330 /* If the switch handles error then we should have also forced the
332 assert( fsm->errState != 0 );
334 out << " <sub_action id=\"0\">";
335 out << "<goto>" << fsm->errState->alg.stateNum << "</goto>";
336 out << "</sub_action>\n";
339 bool needDefault = false;
340 for ( LmPartList::Iter lmi = *longestMatch->longestMatchList; lmi.lte(); lmi++ ) {
341 if ( lmi->inLmSelect ) {
342 if ( lmi->action == 0 )
345 /* Open the action. Write it with the context that sets up _p
346 * when doing control flow changes from inside the machine. */
347 out << " <sub_action id=\"" << lmi->longestMatchId << "\">";
348 out << "<exec><get_tokend></get_tokend></exec>";
349 writeInlineList( lmi->action->inlineList );
350 out << "</sub_action>\n";
356 out << " <sub_action id=\"-1\"><exec><get_tokend>"
357 "</get_tokend></exec></sub_action>\n";
360 out << " </lm_switch>";
363 void XMLCodeGen::writeInlineList( InlineList *inlineList )
365 for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
366 switch ( item->type ) {
367 case InlineItem::Text:
370 case InlineItem::Goto:
373 case InlineItem::GotoExpr:
374 writeGotoExpr( item );
376 case InlineItem::Call:
379 case InlineItem::CallExpr:
380 writeCallExpr( item );
382 case InlineItem::Next:
385 case InlineItem::NextExpr:
386 writeNextExpr( item );
388 case InlineItem::Break:
389 out << "<break></break>";
391 case InlineItem::Ret:
392 out << "<ret></ret>";
394 case InlineItem::PChar:
395 out << "<pchar></pchar>";
397 case InlineItem::Char:
398 out << "<char></char>";
400 case InlineItem::Curs:
401 out << "<curs></curs>";
403 case InlineItem::Targs:
404 out << "<targs></targs>";
406 case InlineItem::Entry:
410 case InlineItem::Hold:
411 out << "<hold></hold>";
413 case InlineItem::Exec:
414 writeActionExec( item );
417 case InlineItem::LmSetActId:
418 out << "<set_act>" <<
419 item->longestMatchPart->longestMatchId <<
422 case InlineItem::LmSetTokEnd:
423 out << "<set_tokend>1</set_tokend>";
426 case InlineItem::LmOnLast:
427 writeLmOnLast( item );
429 case InlineItem::LmOnNext:
430 writeLmOnNext( item );
432 case InlineItem::LmOnLagBehind:
433 writeLmOnLagBehind( item );
435 case InlineItem::LmSwitch:
436 writeLmSwitch( item );
439 case InlineItem::LmInitAct:
440 out << "<init_act></init_act>";
442 case InlineItem::LmInitTokStart:
443 out << "<init_tokstart></init_tokstart>";
445 case InlineItem::LmSetTokStart:
446 out << "<set_tokstart></set_tokstart>";
452 BackendGen::BackendGen( char *fsmName, ParseData *pd, FsmAp *fsm, InputData &inputData )
454 GenBase(fsmName, pd, fsm, inputData)
459 void BackendGen::makeText( GenInlineList *outList, InlineItem *item )
461 GenInlineItem *inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::Text );
462 inlineItem->data = item->data;
464 outList->append( inlineItem );
467 void BackendGen::makeTargetItem( GenInlineList *outList, long entryId, GenInlineItem::Type type )
470 if ( pd->generatingSectionSubset )
473 EntryMapEl *targ = fsm->entryPoints.find( entryId );
474 targetState = targ->value->alg.stateNum;
478 GenInlineItem *inlineItem = new GenInlineItem( InputLoc(), type );
479 inlineItem->targId = targetState;
480 outList->append( inlineItem );
483 /* Make a sublist item with a given type. */
484 void BackendGen::makeSubList( GenInlineList *outList,
485 InlineList *inlineList, GenInlineItem::Type type )
487 /* Fill the sub list. */
488 GenInlineList *subList = new GenInlineList;
489 makeGenInlineList( subList, inlineList );
492 GenInlineItem *inlineItem = new GenInlineItem( InputLoc(), type );
493 inlineItem->children = subList;
494 outList->append( inlineItem );
497 void BackendGen::makeLmOnLast( GenInlineList *outList, InlineItem *item )
499 makeSetTokend( outList, 1 );
501 if ( item->longestMatchPart->action != 0 ) {
502 makeSubList( outList,
503 item->longestMatchPart->action->inlineList,
504 GenInlineItem::SubAction );
508 void BackendGen::makeLmOnNext( GenInlineList *outList, InlineItem *item )
510 makeSetTokend( outList, 0 );
511 outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Hold ) );
513 if ( item->longestMatchPart->action != 0 ) {
514 makeSubList( outList,
515 item->longestMatchPart->action->inlineList,
516 GenInlineItem::SubAction );
520 void BackendGen::makeExecGetTokend( GenInlineList *outList )
522 /* Make the Exec item. */
523 GenInlineItem *execItem = new GenInlineItem( InputLoc(), GenInlineItem::Exec );
524 execItem->children = new GenInlineList;
526 /* Make the GetTokEnd */
527 GenInlineItem *getTokend = new GenInlineItem( InputLoc(), GenInlineItem::LmGetTokEnd );
528 execItem->children->append( getTokend );
530 outList->append( execItem );
533 void BackendGen::makeLmOnLagBehind( GenInlineList *outList, InlineItem *item )
535 /* Jump to the tokend. */
536 makeExecGetTokend( outList );
538 if ( item->longestMatchPart->action != 0 ) {
539 makeSubList( outList,
540 item->longestMatchPart->action->inlineList,
541 GenInlineItem::SubAction );
545 void BackendGen::makeLmSwitch( GenInlineList *outList, InlineItem *item )
547 GenInlineItem *lmSwitch = new GenInlineItem( InputLoc(), GenInlineItem::LmSwitch );
548 GenInlineList *lmList = lmSwitch->children = new GenInlineList;
549 LongestMatch *longestMatch = item->longestMatch;
551 /* We can't put the <exec> here because we may need to handle the error
552 * case and in that case p should not be changed. Instead use a default
553 * label in the switch to adjust p when user actions are not set. An id of
554 * -1 indicates the default. */
556 if ( longestMatch->lmSwitchHandlesError ) {
557 /* If the switch handles error then we should have also forced the
559 assert( fsm->errState != 0 );
561 GenInlineItem *errCase = new GenInlineItem( InputLoc(), GenInlineItem::SubAction );
563 errCase->children = new GenInlineList;
566 GenInlineItem *gotoItem = new GenInlineItem( InputLoc(), GenInlineItem::Goto );
567 gotoItem->targId = fsm->errState->alg.stateNum;
568 errCase->children->append( gotoItem );
570 lmList->append( errCase );
573 bool needDefault = false;
574 for ( LmPartList::Iter lmi = *longestMatch->longestMatchList; lmi.lte(); lmi++ ) {
575 if ( lmi->inLmSelect ) {
576 if ( lmi->action == 0 )
579 /* Open the action. Write it with the context that sets up _p
580 * when doing control flow changes from inside the machine. */
581 GenInlineItem *lmCase = new GenInlineItem( InputLoc(),
582 GenInlineItem::SubAction );
583 lmCase->lmId = lmi->longestMatchId;
584 lmCase->children = new GenInlineList;
586 makeExecGetTokend( lmCase->children );
587 makeGenInlineList( lmCase->children, lmi->action->inlineList );
589 lmList->append( lmCase );
595 GenInlineItem *defCase = new GenInlineItem( InputLoc(),
596 GenInlineItem::SubAction );
598 defCase->children = new GenInlineList;
600 makeExecGetTokend( defCase->children );
602 lmList->append( defCase );
605 outList->append( lmSwitch );
608 void BackendGen::makeSetTokend( GenInlineList *outList, long offset )
610 GenInlineItem *inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::LmSetTokEnd );
611 inlineItem->offset = offset;
612 outList->append( inlineItem );
615 void BackendGen::makeSetAct( GenInlineList *outList, long lmId )
617 GenInlineItem *inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::LmSetActId );
618 inlineItem->lmId = lmId;
619 outList->append( inlineItem );
622 void BackendGen::makeGenInlineList( GenInlineList *outList, InlineList *inList )
624 for ( InlineList::Iter item = *inList; item.lte(); item++ ) {
625 switch ( item->type ) {
626 case InlineItem::Text:
627 makeText( outList, item );
629 case InlineItem::Goto:
630 makeTargetItem( outList, item->nameTarg->id, GenInlineItem::Goto );
632 case InlineItem::GotoExpr:
633 makeSubList( outList, item->children, GenInlineItem::GotoExpr );
635 case InlineItem::Call:
636 makeTargetItem( outList, item->nameTarg->id, GenInlineItem::Call );
638 case InlineItem::CallExpr:
639 makeSubList( outList, item->children, GenInlineItem::CallExpr );
641 case InlineItem::Next:
642 makeTargetItem( outList, item->nameTarg->id, GenInlineItem::Next );
644 case InlineItem::NextExpr:
645 makeSubList( outList, item->children, GenInlineItem::NextExpr );
647 case InlineItem::Break:
648 outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Break ) );
650 case InlineItem::Ret:
651 outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Ret ) );
653 case InlineItem::PChar:
654 outList->append( new GenInlineItem( InputLoc(), GenInlineItem::PChar ) );
656 case InlineItem::Char:
657 outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Char ) );
659 case InlineItem::Curs:
660 outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Curs ) );
662 case InlineItem::Targs:
663 outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Targs ) );
665 case InlineItem::Entry:
666 makeTargetItem( outList, item->nameTarg->id, GenInlineItem::Entry );
669 case InlineItem::Hold:
670 outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Hold ) );
672 case InlineItem::Exec:
673 makeSubList( outList, item->children, GenInlineItem::Exec );
676 case InlineItem::LmSetActId:
677 makeSetAct( outList, item->longestMatchPart->longestMatchId );
679 case InlineItem::LmSetTokEnd:
680 makeSetTokend( outList, 1 );
683 case InlineItem::LmOnLast:
684 makeLmOnLast( outList, item );
686 case InlineItem::LmOnNext:
687 makeLmOnNext( outList, item );
689 case InlineItem::LmOnLagBehind:
690 makeLmOnLagBehind( outList, item );
692 case InlineItem::LmSwitch:
693 makeLmSwitch( outList, item );
696 case InlineItem::LmInitAct:
697 outList->append( new GenInlineItem( InputLoc(), GenInlineItem::LmInitAct ) );
699 case InlineItem::LmInitTokStart:
700 outList->append( new GenInlineItem( InputLoc(), GenInlineItem::LmInitTokStart ) );
702 case InlineItem::LmSetTokStart:
703 outList->append( new GenInlineItem( InputLoc(), GenInlineItem::LmSetTokStart ) );
704 inputData.cgd->hasLongestMatch = true;
711 void XMLCodeGen::writeAction( Action *action )
713 out << " <action id=\"" << action->actionId << "\"";
714 if ( action->name != 0 )
715 out << " name=\"" << action->name << "\"";
716 out << " line=\"" << action->loc.line << "\" col=\"" << action->loc.col << "\">";
717 writeInlineList( action->inlineList );
718 out << "</action>\n";
721 void xmlEscapeHost( std::ostream &out, char *data, long len )
723 char *end = data + len;
724 while ( data != end ) {
726 case '<': out << "<"; break;
727 case '>': out << ">"; break;
728 case '&': out << "&"; break;
729 default: out << *data; break;
735 void XMLCodeGen::writeStateActions( StateAp *state )
737 RedActionTable *toStateActions = 0;
738 if ( state->toStateActionTable.length() > 0 )
739 toStateActions = actionTableMap.find( state->toStateActionTable );
741 RedActionTable *fromStateActions = 0;
742 if ( state->fromStateActionTable.length() > 0 )
743 fromStateActions = actionTableMap.find( state->fromStateActionTable );
745 /* EOF actions go out here only if the state has no eof target. If it has
746 * an eof target then an eof transition will be used instead. */
747 RedActionTable *eofActions = 0;
748 if ( state->eofTarget == 0 && state->eofActionTable.length() > 0 )
749 eofActions = actionTableMap.find( state->eofActionTable );
751 if ( toStateActions != 0 || fromStateActions != 0 || eofActions != 0 ) {
752 out << " <state_actions>";
753 if ( toStateActions != 0 )
754 out << toStateActions->id;
758 if ( fromStateActions != 0 )
759 out << " " << fromStateActions->id;
763 if ( eofActions != 0 )
764 out << " " << eofActions->id;
768 out << "</state_actions>\n";
772 void XMLCodeGen::writeStateConditions( StateAp *state )
774 if ( state->stateCondList.length() > 0 ) {
775 out << " <cond_list length=\"" << state->stateCondList.length() << "\">\n";
776 for ( StateCondList::Iter scdi = state->stateCondList; scdi.lte(); scdi++ ) {
778 writeKey( scdi->lowKey );
780 writeKey( scdi->highKey );
782 out << scdi->condSpace->condSpaceId;
785 out << " </cond_list>\n";
789 void XMLCodeGen::writeStateList()
791 /* Write the list of states. */
792 out << " <state_list length=\"" << fsm->stateList.length() << "\">\n";
793 for ( StateList::Iter st = fsm->stateList; st.lte(); st++ ) {
794 out << " <state id=\"" << st->alg.stateNum << "\"";
795 if ( st->isFinState() )
796 out << " final=\"t\"";
799 writeStateActions( st );
801 writeStateConditions( st );
802 writeTransList( st );
804 out << " </state>\n";
809 out << " </state_list>\n";
812 bool XMLCodeGen::writeNameInst( NameInst *nameInst )
814 bool written = false;
815 if ( nameInst->parent != 0 )
816 written = writeNameInst( nameInst->parent );
818 if ( nameInst->name != 0 ) {
821 out << nameInst->name;
828 void XMLCodeGen::writeEntryPoints()
830 /* List of entry points other than start state. */
831 if ( fsm->entryPoints.length() > 0 || pd->lmRequiresErrorState ) {
832 out << " <entry_points";
833 if ( pd->lmRequiresErrorState )
834 out << " error=\"t\"";
836 for ( EntryMap::Iter en = fsm->entryPoints; en.lte(); en++ ) {
837 /* Get the name instantiation from nameIndex. */
838 NameInst *nameInst = pd->nameIndex[en->key];
839 StateAp *state = en->value;
840 out << " <entry name=\"";
841 writeNameInst( nameInst );
842 out << "\">" << state->alg.stateNum << "</entry>\n";
844 out << " </entry_points>\n";
848 void XMLCodeGen::writeMachine()
850 /* Open the machine. */
851 out << " <machine>\n";
854 reduceActionTables();
857 writeActionTableList();
861 out << " <start_state>" << fsm->startState->alg.stateNum <<
865 if ( fsm->errState != 0 ) {
866 out << " <error_state>" << fsm->errState->alg.stateNum <<
873 out << " </machine>\n";
877 void XMLCodeGen::writeConditions()
879 if ( condData->condSpaceMap.length() > 0 ) {
880 long nextCondSpaceId = 0;
881 for ( CondSpaceMap::Iter cs = condData->condSpaceMap; cs.lte(); cs++ )
882 cs->condSpaceId = nextCondSpaceId++;
884 out << " <cond_space_list length=\"" << condData->condSpaceMap.length() << "\">\n";
885 for ( CondSpaceMap::Iter cs = condData->condSpaceMap; cs.lte(); cs++ ) {
886 out << " <cond_space id=\"" << cs->condSpaceId <<
887 "\" length=\"" << cs->condSet.length() << "\">";
888 writeKey( cs->baseKey );
889 for ( CondSet::Iter csi = cs->condSet; csi.lte(); csi++ )
890 out << " " << (*csi)->actionId;
891 out << "</cond_space>\n";
893 out << " </cond_space_list>\n";
897 void XMLCodeGen::writeExports()
899 if ( pd->exportList.length() > 0 ) {
900 out << " <exports>\n";
901 for ( ExportList::Iter exp = pd->exportList; exp.lte(); exp++ ) {
902 out << " <ex name=\"" << exp->name << "\">";
903 writeKey( exp->key );
906 out << " </exports>\n";
910 void XMLCodeGen::writeXML()
912 /* Open the definition. */
913 out << "<ragel_def name=\"" << fsmName << "\">\n";
916 out << " <alphtype>" << keyOps->alphType->internalName << "</alphtype>\n";
918 /* Getkey expression. */
919 if ( pd->getKeyExpr != 0 ) {
921 writeInlineList( pd->getKeyExpr );
922 out << "</getkey>\n";
925 /* Access expression. */
926 if ( pd->accessExpr != 0 ) {
928 writeInlineList( pd->accessExpr );
929 out << "</access>\n";
932 /* PrePush expression. */
933 if ( pd->prePushExpr != 0 ) {
935 writeInlineList( pd->prePushExpr );
936 out << "</prepush>\n";
939 /* PostPop expression. */
940 if ( pd->postPopExpr != 0 ) {
942 writeInlineList( pd->postPopExpr );
943 out << "</postpop>\n";
947 * Variable expressions.
950 if ( pd->pExpr != 0 ) {
952 writeInlineList( pd->pExpr );
953 out << "</p_expr>\n";
956 if ( pd->peExpr != 0 ) {
958 writeInlineList( pd->peExpr );
959 out << "</pe_expr>\n";
962 if ( pd->eofExpr != 0 ) {
963 out << " <eof_expr>";
964 writeInlineList( pd->eofExpr );
965 out << "</eof_expr>\n";
968 if ( pd->csExpr != 0 ) {
970 writeInlineList( pd->csExpr );
971 out << "</cs_expr>\n";
974 if ( pd->topExpr != 0 ) {
975 out << " <top_expr>";
976 writeInlineList( pd->topExpr );
977 out << "</top_expr>\n";
980 if ( pd->stackExpr != 0 ) {
981 out << " <stack_expr>";
982 writeInlineList( pd->stackExpr );
983 out << "</stack_expr>\n";
986 if ( pd->actExpr != 0 ) {
987 out << " <act_expr>";
988 writeInlineList( pd->actExpr );
989 out << "</act_expr>\n";
992 if ( pd->tokstartExpr != 0 ) {
993 out << " <tokstart_expr>";
994 writeInlineList( pd->tokstartExpr );
995 out << "</tokstart_expr>\n";
998 if ( pd->tokendExpr != 0 ) {
999 out << " <tokend_expr>";
1000 writeInlineList( pd->tokendExpr );
1001 out << "</tokend_expr>\n";
1004 if ( pd->dataExpr != 0 ) {
1005 out << " <data_expr>";
1006 writeInlineList( pd->dataExpr );
1007 out << "</data_expr>\n";
1018 void BackendGen::makeExports()
1020 for ( ExportList::Iter exp = pd->exportList; exp.lte(); exp++ )
1021 inputData.cgd->exportList.append( new Export( exp->name, exp->key ) );
1024 void BackendGen::makeAction( Action *action )
1026 GenInlineList *genList = new GenInlineList;
1027 makeGenInlineList( genList, action->inlineList );
1029 inputData.cgd->newAction( inputData.curAction++, action->name,
1030 action->loc.line, action->loc.col, genList );
1034 void BackendGen::makeActionList()
1036 /* Determine which actions to write. */
1037 int nextActionId = 0;
1038 for ( ActionList::Iter act = pd->actionList; act.lte(); act++ ) {
1039 if ( act->numRefs() > 0 || act->numCondRefs > 0 )
1040 act->actionId = nextActionId++;
1043 /* Write the list. */
1044 inputData.cgd->initActionList( nextActionId );
1045 inputData.curAction = 0;
1047 for ( ActionList::Iter act = pd->actionList; act.lte(); act++ ) {
1048 if ( act->actionId >= 0 )
1053 void BackendGen::makeActionTableList()
1055 /* Must first order the action tables based on their id. */
1056 int numTables = nextActionTableId;
1057 RedActionTable **tables = new RedActionTable*[numTables];
1058 for ( ActionTableMap::Iter at = actionTableMap; at.lte(); at++ )
1059 tables[at->id] = at;
1061 inputData.cgd->initActionTableList( numTables );
1062 inputData.curActionTable = 0;
1064 for ( int t = 0; t < numTables; t++ ) {
1065 long length = tables[t]->key.length();
1067 /* Collect the action table. */
1068 RedAction *redAct = inputData.cgd->allActionTables + inputData.curActionTable;
1069 redAct->actListId = inputData.curActionTable;
1070 redAct->key.setAsNew( length );
1072 for ( ActionTable::Iter atel = tables[t]->key; atel.lte(); atel++ ) {
1073 redAct->key[atel.pos()].key = 0;
1074 redAct->key[atel.pos()].value = inputData.cgd->allActions +
1075 atel->value->actionId;
1078 /* Insert into the action table map. */
1079 inputData.cgd->redFsm->actionMap.insert( redAct );
1081 inputData.curActionTable += 1;
1087 void BackendGen::makeConditions()
1089 if ( condData->condSpaceMap.length() > 0 ) {
1090 long nextCondSpaceId = 0;
1091 for ( CondSpaceMap::Iter cs = condData->condSpaceMap; cs.lte(); cs++ )
1092 cs->condSpaceId = nextCondSpaceId++;
1094 long listLength = condData->condSpaceMap.length();
1095 inputData.cgd->initCondSpaceList( listLength );
1096 inputData.curCondSpace = 0;
1098 for ( CondSpaceMap::Iter cs = condData->condSpaceMap; cs.lte(); cs++ ) {
1099 long id = cs->condSpaceId;
1100 inputData.cgd->newCondSpace( inputData.curCondSpace, id, cs->baseKey );
1101 for ( CondSet::Iter csi = cs->condSet; csi.lte(); csi++ )
1102 inputData.cgd->condSpaceItem( inputData.curCondSpace, (*csi)->actionId );
1103 inputData.curCondSpace += 1;
1108 bool BackendGen::makeNameInst( std::string &res, NameInst *nameInst )
1110 bool written = false;
1111 if ( nameInst->parent != 0 )
1112 written = makeNameInst( res, nameInst->parent );
1114 if ( nameInst->name != 0 ) {
1117 res += nameInst->name;
1124 void BackendGen::makeEntryPoints()
1126 /* List of entry points other than start state. */
1127 if ( fsm->entryPoints.length() > 0 || pd->lmRequiresErrorState ) {
1128 if ( pd->lmRequiresErrorState )
1129 inputData.cgd->setForcedErrorState();
1131 for ( EntryMap::Iter en = fsm->entryPoints; en.lte(); en++ ) {
1132 /* Get the name instantiation from nameIndex. */
1133 NameInst *nameInst = pd->nameIndex[en->key];
1135 makeNameInst( name, nameInst );
1136 StateAp *state = en->value;
1137 inputData.cgd->addEntryPoint( strdup(name.c_str()), state->alg.stateNum );
1142 void BackendGen::makeStateActions( StateAp *state )
1144 RedActionTable *toStateActions = 0;
1145 if ( state->toStateActionTable.length() > 0 )
1146 toStateActions = actionTableMap.find( state->toStateActionTable );
1148 RedActionTable *fromStateActions = 0;
1149 if ( state->fromStateActionTable.length() > 0 )
1150 fromStateActions = actionTableMap.find( state->fromStateActionTable );
1152 /* EOF actions go out here only if the state has no eof target. If it has
1153 * an eof target then an eof transition will be used instead. */
1154 RedActionTable *eofActions = 0;
1155 if ( state->eofTarget == 0 && state->eofActionTable.length() > 0 )
1156 eofActions = actionTableMap.find( state->eofActionTable );
1158 if ( toStateActions != 0 || fromStateActions != 0 || eofActions != 0 ) {
1160 if ( toStateActions != 0 )
1161 to = toStateActions->id;
1164 if ( fromStateActions != 0 )
1165 from = fromStateActions->id;
1168 if ( eofActions != 0 )
1169 eof = eofActions->id;
1171 inputData.cgd->setStateActions( inputData.curState, to, from, eof );
1175 void BackendGen::makeEofTrans( StateAp *state )
1177 RedActionTable *eofActions = 0;
1178 if ( state->eofActionTable.length() > 0 )
1179 eofActions = actionTableMap.find( state->eofActionTable );
1181 /* The EOF trans is used when there is an eof target, otherwise the eof
1182 * action goes into state actions. */
1183 if ( state->eofTarget != 0 ) {
1184 long targ = state->eofTarget->alg.stateNum;
1186 if ( eofActions != 0 )
1187 action = eofActions->id;
1189 inputData.cgd->setEofTrans( inputData.curState, targ, action );
1193 void BackendGen::makeStateConditions( StateAp *state )
1195 if ( state->stateCondList.length() > 0 ) {
1196 long length = state->stateCondList.length();
1197 inputData.cgd->initStateCondList( inputData.curState, length );
1198 inputData.curStateCond = 0;
1200 for ( StateCondList::Iter scdi = state->stateCondList; scdi.lte(); scdi++ ) {
1201 inputData.cgd->addStateCond( inputData.curState, scdi->lowKey, scdi->highKey,
1202 scdi->condSpace->condSpaceId );
1207 void BackendGen::makeTrans( Key lowKey, Key highKey, TransAp *trans )
1209 /* First reduce the action. */
1210 RedActionTable *actionTable = 0;
1211 if ( trans->actionTable.length() > 0 )
1212 actionTable = actionTableMap.find( trans->actionTable );
1215 if ( trans->toState != 0 )
1216 targ = trans->toState->alg.stateNum;
1219 if ( actionTable != 0 )
1220 action = actionTable->id;
1222 inputData.cgd->newTrans( inputData.curState, inputData.curTrans++, lowKey, highKey, targ, action );
1225 void BackendGen::makeTransList( StateAp *state )
1227 TransListVect outList;
1229 /* If there is only are no ranges the task is simple. */
1230 if ( state->outList.length() > 0 ) {
1231 /* Loop each source range. */
1232 for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) {
1233 /* Reduce the transition. If it reduced to anything then add it. */
1234 appendTrans( outList, trans->lowKey, trans->highKey, trans );
1238 inputData.cgd->initTransList( inputData.curState, outList.length() );
1239 inputData.curTrans = 0;
1241 for ( TransListVect::Iter tvi = outList; tvi.lte(); tvi++ )
1242 makeTrans( tvi->lowKey, tvi->highKey, tvi->value );
1244 inputData.cgd->finishTransList( inputData.curState );
1248 void BackendGen::makeStateList()
1250 /* Write the list of states. */
1251 long length = fsm->stateList.length();
1252 inputData.cgd->initStateList( length );
1253 inputData.curState = 0;
1254 for ( StateList::Iter st = fsm->stateList; st.lte(); st++ ) {
1255 makeStateActions( st );
1257 makeStateConditions( st );
1258 makeTransList( st );
1260 long id = st->alg.stateNum;
1261 inputData.cgd->setId( inputData.curState, id );
1263 if ( st->isFinState() )
1264 inputData.cgd->setFinal( inputData.curState );
1266 inputData.curState += 1;
1271 void BackendGen::makeMachine()
1273 inputData.cgd->createMachine();
1275 /* Action tables. */
1276 reduceActionTables();
1279 makeActionTableList();
1283 inputData.cgd->setStartState( fsm->startState->alg.stateNum );
1286 if ( fsm->errState != 0 )
1287 inputData.cgd->setErrorState( fsm->errState->alg.stateNum );
1292 inputData.cgd->closeMachine();
1295 void BackendGen::open_ragel_def( char *fsmName )
1297 CodeGenMapEl *mapEl = inputData.codeGenMap.find( fsmName );
1299 inputData.cgd = mapEl->value;
1301 inputData.cgd = makeCodeGen( inputData.sourceFileName, fsmName,
1302 *inputData.outStream, inputData.wantComplete );
1303 inputData.codeGenMap.insert( fsmName, inputData.cgd );
1307 void BackendGen::close_ragel_def()
1309 /* Do this before distributing transitions out to singles and defaults
1310 * makes life easier. */
1311 inputData.cgd->redFsm->maxKey = inputData.cgd->findMaxKey();
1313 inputData.cgd->redFsm->assignActionLocs();
1315 /* Find the first final state (The final state with the lowest id). */
1316 inputData.cgd->redFsm->findFirstFinState();
1318 /* Call the user's callback. */
1319 inputData.cgd->finishRagelDef();
1323 void BackendGen::makeBackend()
1325 /* Open the definition. */
1326 open_ragel_def( fsmName );
1328 /* Alphabet type. */
1329 inputData.cgd->setAlphType( keyOps->alphType->internalName );
1331 /* Getkey expression. */
1332 if ( pd->getKeyExpr != 0 ) {
1333 inputData.cgd->getKeyExpr = new GenInlineList;
1334 makeGenInlineList( inputData.cgd->getKeyExpr, pd->getKeyExpr );
1337 /* Access expression. */
1338 if ( pd->accessExpr != 0 ) {
1339 inputData.cgd->accessExpr = new GenInlineList;
1340 makeGenInlineList( inputData.cgd->accessExpr, pd->accessExpr );
1343 /* PrePush expression. */
1344 if ( pd->prePushExpr != 0 ) {
1345 inputData.cgd->prePushExpr = new GenInlineList;
1346 makeGenInlineList( inputData.cgd->prePushExpr, pd->prePushExpr );
1349 /* PostPop expression. */
1350 if ( pd->postPopExpr != 0 ) {
1351 inputData.cgd->postPopExpr = new GenInlineList;
1352 makeGenInlineList( inputData.cgd->postPopExpr, pd->postPopExpr );
1356 * Variable expressions.
1359 if ( pd->pExpr != 0 ) {
1360 inputData.cgd->pExpr = new GenInlineList;
1361 makeGenInlineList( inputData.cgd->pExpr, pd->pExpr );
1364 if ( pd->peExpr != 0 ) {
1365 inputData.cgd->peExpr = new GenInlineList;
1366 makeGenInlineList( inputData.cgd->peExpr, pd->peExpr );
1369 if ( pd->eofExpr != 0 ) {
1370 inputData.cgd->eofExpr = new GenInlineList;
1371 makeGenInlineList( inputData.cgd->eofExpr, pd->eofExpr );
1374 if ( pd->csExpr != 0 ) {
1375 inputData.cgd->csExpr = new GenInlineList;
1376 makeGenInlineList( inputData.cgd->csExpr, pd->csExpr );
1379 if ( pd->topExpr != 0 ) {
1380 inputData.cgd->topExpr = new GenInlineList;
1381 makeGenInlineList( inputData.cgd->topExpr, pd->topExpr );
1384 if ( pd->stackExpr != 0 ) {
1385 inputData.cgd->stackExpr = new GenInlineList;
1386 makeGenInlineList( inputData.cgd->stackExpr, pd->stackExpr );
1389 if ( pd->actExpr != 0 ) {
1390 inputData.cgd->actExpr = new GenInlineList;
1391 makeGenInlineList( inputData.cgd->actExpr, pd->actExpr );
1394 if ( pd->tokstartExpr != 0 ) {
1395 inputData.cgd->tokstartExpr = new GenInlineList;
1396 makeGenInlineList( inputData.cgd->tokstartExpr, pd->tokstartExpr );
1399 if ( pd->tokendExpr != 0 ) {
1400 inputData.cgd->tokendExpr = new GenInlineList;
1401 makeGenInlineList( inputData.cgd->tokendExpr, pd->tokendExpr );
1404 if ( pd->dataExpr != 0 ) {
1405 inputData.cgd->dataExpr = new GenInlineList;
1406 makeGenInlineList( inputData.cgd->dataExpr, pd->dataExpr );