Use portable types in the C/C++ code generator
[ragel-jkt.git] / ragel / xmlcodegen.cpp
blobe4b14bc82b2c485d8d86da8d6a759b5e820ef6d4
1 /*
2 * Copyright 2005-2007 Adrian Thurston <thurston@complang.org>
3 */
5 /* This file is part of Ragel.
7 * Ragel is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * Ragel is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Ragel; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "ragel.h"
24 #include "xmlcodegen.h"
25 #include "parsedata.h"
26 #include "fsmgraph.h"
27 #include "gendata.h"
28 #include "inputdata.h"
29 #include <string.h>
30 #include "rlparse.h"
31 #include "version.h"
33 using namespace std;
35 GenBase::GenBase( char *fsmName, ParseData *pd, FsmAp *fsm )
37 fsmName(fsmName),
38 pd(pd),
39 fsm(fsm),
40 nextActionTableId(0)
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, std::ostream &out )
87 GenBase(fsmName, pd, fsm),
88 out(out)
93 void XMLCodeGen::writeActionList()
95 /* Determine which actions to write. */
96 int nextActionId = 0;
97 for ( ActionList::Iter act = pd->actionList; act.lte(); act++ ) {
98 if ( act->numRefs() > 0 || act->numCondRefs > 0 )
99 act->actionId = nextActionId++;
102 /* Write the list. */
103 out << " <action_list length=\"" << nextActionId << "\">\n";
104 for ( ActionList::Iter act = pd->actionList; act.lte(); act++ ) {
105 if ( act->actionId >= 0 )
106 writeAction( act );
108 out << " </action_list>\n";
111 void XMLCodeGen::writeActionTableList()
113 /* Must first order the action tables based on their id. */
114 int numTables = nextActionTableId;
115 RedActionTable **tables = new RedActionTable*[numTables];
116 for ( ActionTableMap::Iter at = actionTableMap; at.lte(); at++ )
117 tables[at->id] = at;
119 out << " <action_table_list length=\"" << numTables << "\">\n";
120 for ( int t = 0; t < numTables; t++ ) {
121 out << " <action_table id=\"" << t << "\" length=\"" <<
122 tables[t]->key.length() << "\">";
123 for ( ActionTable::Iter atel = tables[t]->key; atel.lte(); atel++ ) {
124 out << atel->value->actionId;
125 if ( ! atel.last() )
126 out << " ";
128 out << "</action_table>\n";
130 out << " </action_table_list>\n";
132 delete[] tables;
135 void XMLCodeGen::writeKey( Key key )
137 if ( keyOps->isSigned )
138 out << key.getVal();
139 else
140 out << (unsigned long) key.getVal();
143 void XMLCodeGen::writeTrans( Key lowKey, Key highKey, TransAp *trans )
145 /* First reduce the action. */
146 RedActionTable *actionTable = 0;
147 if ( trans->actionTable.length() > 0 )
148 actionTable = actionTableMap.find( trans->actionTable );
150 /* Write the transition. */
151 out << " <t>";
152 writeKey( lowKey );
153 out << " ";
154 writeKey( highKey );
156 if ( trans->toState != 0 )
157 out << " " << trans->toState->alg.stateNum;
158 else
159 out << " x";
161 if ( actionTable != 0 )
162 out << " " << actionTable->id;
163 else
164 out << " x";
165 out << "</t>\n";
168 void XMLCodeGen::writeTransList( StateAp *state )
170 TransListVect outList;
172 /* If there is only are no ranges the task is simple. */
173 if ( state->outList.length() > 0 ) {
174 /* Loop each source range. */
175 for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) {
176 /* Reduce the transition. If it reduced to anything then add it. */
177 appendTrans( outList, trans->lowKey, trans->highKey, trans );
181 out << " <trans_list length=\"" << outList.length() << "\">\n";
182 for ( TransListVect::Iter tvi = outList; tvi.lte(); tvi++ )
183 writeTrans( tvi->lowKey, tvi->highKey, tvi->value );
184 out << " </trans_list>\n";
187 void XMLCodeGen::writeEofTrans( StateAp *state )
189 RedActionTable *eofActions = 0;
190 if ( state->eofActionTable.length() > 0 )
191 eofActions = actionTableMap.find( state->eofActionTable );
193 /* The <eof_t> is used when there is an eof target, otherwise the eof
194 * action goes into state actions. */
195 if ( state->eofTarget != 0 ) {
196 out << " <eof_t>" << state->eofTarget->alg.stateNum;
198 if ( eofActions != 0 )
199 out << " " << eofActions->id;
200 else
201 out << " x";
203 out << "</eof_t>" << endl;
207 void XMLCodeGen::writeText( InlineItem *item )
209 if ( item->prev == 0 || item->prev->type != InlineItem::Text )
210 out << "<text>";
211 xmlEscapeHost( out, item->data, strlen(item->data) );
212 if ( item->next == 0 || item->next->type != InlineItem::Text )
213 out << "</text>";
216 void XMLCodeGen::writeGoto( InlineItem *item )
218 if ( pd->generatingSectionSubset )
219 out << "<goto>-1</goto>";
220 else {
221 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
222 out << "<goto>" << targ->value->alg.stateNum << "</goto>";
226 void XMLCodeGen::writeCall( InlineItem *item )
228 if ( pd->generatingSectionSubset )
229 out << "<call>-1</call>";
230 else {
231 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
232 out << "<call>" << targ->value->alg.stateNum << "</call>";
236 void XMLCodeGen::writeNext( InlineItem *item )
238 if ( pd->generatingSectionSubset )
239 out << "<next>-1</next>";
240 else {
241 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
242 out << "<next>" << targ->value->alg.stateNum << "</next>";
246 void XMLCodeGen::writeGotoExpr( InlineItem *item )
248 out << "<goto_expr>";
249 writeInlineList( item->children );
250 out << "</goto_expr>";
253 void XMLCodeGen::writeCallExpr( InlineItem *item )
255 out << "<call_expr>";
256 writeInlineList( item->children );
257 out << "</call_expr>";
260 void XMLCodeGen::writeNextExpr( InlineItem *item )
262 out << "<next_expr>";
263 writeInlineList( item->children );
264 out << "</next_expr>";
267 void XMLCodeGen::writeEntry( InlineItem *item )
269 if ( pd->generatingSectionSubset )
270 out << "<entry>-1</entry>";
271 else {
272 EntryMapEl *targ = fsm->entryPoints.find( item->nameTarg->id );
273 out << "<entry>" << targ->value->alg.stateNum << "</entry>";
277 void XMLCodeGen::writeActionExec( InlineItem *item )
279 out << "<exec>";
280 writeInlineList( item->children );
281 out << "</exec>";
284 void XMLCodeGen::writeLmOnLast( InlineItem *item )
286 out << "<set_tokend>1</set_tokend>";
288 if ( item->longestMatchPart->action != 0 ) {
289 out << "<sub_action>";
290 writeInlineList( item->longestMatchPart->action->inlineList );
291 out << "</sub_action>";
295 void XMLCodeGen::writeLmOnNext( InlineItem *item )
297 out << "<set_tokend>0</set_tokend>";
298 out << "<hold></hold>";
300 if ( item->longestMatchPart->action != 0 ) {
301 out << "<sub_action>";
302 writeInlineList( item->longestMatchPart->action->inlineList );
303 out << "</sub_action>";
307 void XMLCodeGen::writeLmOnLagBehind( InlineItem *item )
309 out << "<exec><get_tokend></get_tokend></exec>";
311 if ( item->longestMatchPart->action != 0 ) {
312 out << "<sub_action>";
313 writeInlineList( item->longestMatchPart->action->inlineList );
314 out << "</sub_action>";
318 void XMLCodeGen::writeLmSwitch( InlineItem *item )
320 LongestMatch *longestMatch = item->longestMatch;
321 out << "<lm_switch>\n";
323 /* We can't put the <exec> here because we may need to handle the error
324 * case and in that case p should not be changed. Instead use a default
325 * label in the switch to adjust p when user actions are not set. An id of
326 * -1 indicates the default. */
328 if ( longestMatch->lmSwitchHandlesError ) {
329 /* If the switch handles error then we should have also forced the
330 * error state. */
331 assert( fsm->errState != 0 );
333 out << " <sub_action id=\"0\">";
334 out << "<goto>" << fsm->errState->alg.stateNum << "</goto>";
335 out << "</sub_action>\n";
338 bool needDefault = false;
339 for ( LmPartList::Iter lmi = *longestMatch->longestMatchList; lmi.lte(); lmi++ ) {
340 if ( lmi->inLmSelect ) {
341 if ( lmi->action == 0 )
342 needDefault = true;
343 else {
344 /* Open the action. Write it with the context that sets up _p
345 * when doing control flow changes from inside the machine. */
346 out << " <sub_action id=\"" << lmi->longestMatchId << "\">";
347 out << "<exec><get_tokend></get_tokend></exec>";
348 writeInlineList( lmi->action->inlineList );
349 out << "</sub_action>\n";
354 if ( needDefault ) {
355 out << " <sub_action id=\"-1\"><exec><get_tokend>"
356 "</get_tokend></exec></sub_action>\n";
359 out << " </lm_switch>";
362 void XMLCodeGen::writeInlineList( InlineList *inlineList )
364 for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
365 switch ( item->type ) {
366 case InlineItem::Text:
367 writeText( item );
368 break;
369 case InlineItem::Goto:
370 writeGoto( item );
371 break;
372 case InlineItem::GotoExpr:
373 writeGotoExpr( item );
374 break;
375 case InlineItem::Call:
376 writeCall( item );
377 break;
378 case InlineItem::CallExpr:
379 writeCallExpr( item );
380 break;
381 case InlineItem::Next:
382 writeNext( item );
383 break;
384 case InlineItem::NextExpr:
385 writeNextExpr( item );
386 break;
387 case InlineItem::Break:
388 out << "<break></break>";
389 break;
390 case InlineItem::Ret:
391 out << "<ret></ret>";
392 break;
393 case InlineItem::PChar:
394 out << "<pchar></pchar>";
395 break;
396 case InlineItem::Char:
397 out << "<char></char>";
398 break;
399 case InlineItem::Curs:
400 out << "<curs></curs>";
401 break;
402 case InlineItem::Targs:
403 out << "<targs></targs>";
404 break;
405 case InlineItem::Entry:
406 writeEntry( item );
407 break;
409 case InlineItem::Hold:
410 out << "<hold></hold>";
411 break;
412 case InlineItem::Exec:
413 writeActionExec( item );
414 break;
416 case InlineItem::LmSetActId:
417 out << "<set_act>" <<
418 item->longestMatchPart->longestMatchId <<
419 "</set_act>";
420 break;
421 case InlineItem::LmSetTokEnd:
422 out << "<set_tokend>1</set_tokend>";
423 break;
425 case InlineItem::LmOnLast:
426 writeLmOnLast( item );
427 break;
428 case InlineItem::LmOnNext:
429 writeLmOnNext( item );
430 break;
431 case InlineItem::LmOnLagBehind:
432 writeLmOnLagBehind( item );
433 break;
434 case InlineItem::LmSwitch:
435 writeLmSwitch( item );
436 break;
438 case InlineItem::LmInitAct:
439 out << "<init_act></init_act>";
440 break;
441 case InlineItem::LmInitTokStart:
442 out << "<init_tokstart></init_tokstart>";
443 break;
444 case InlineItem::LmSetTokStart:
445 out << "<set_tokstart></set_tokstart>";
446 break;
451 BackendGen::BackendGen( char *fsmName, ParseData *pd, FsmAp *fsm, CodeGenData *cgd )
453 GenBase(fsmName, pd, fsm),
454 cgd(cgd)
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, NameInst *nameTarg,
468 GenInlineItem::Type type )
470 long targetState;
471 if ( pd->generatingSectionSubset )
472 targetState = -1;
473 else {
474 EntryMapEl *targ = fsm->entryPoints.find( nameTarg->id );
475 targetState = targ->value->alg.stateNum;
478 /* Make the item. */
479 GenInlineItem *inlineItem = new GenInlineItem( InputLoc(), type );
480 inlineItem->targId = targetState;
481 outList->append( inlineItem );
484 /* Make a sublist item with a given type. */
485 void BackendGen::makeSubList( GenInlineList *outList,
486 InlineList *inlineList, GenInlineItem::Type type )
488 /* Fill the sub list. */
489 GenInlineList *subList = new GenInlineList;
490 makeGenInlineList( subList, inlineList );
492 /* Make the item. */
493 GenInlineItem *inlineItem = new GenInlineItem( InputLoc(), type );
494 inlineItem->children = subList;
495 outList->append( inlineItem );
498 void BackendGen::makeLmOnLast( GenInlineList *outList, InlineItem *item )
500 makeSetTokend( outList, 1 );
502 if ( item->longestMatchPart->action != 0 ) {
503 makeSubList( outList,
504 item->longestMatchPart->action->inlineList,
505 GenInlineItem::SubAction );
509 void BackendGen::makeLmOnNext( GenInlineList *outList, InlineItem *item )
511 makeSetTokend( outList, 0 );
512 outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Hold ) );
514 if ( item->longestMatchPart->action != 0 ) {
515 makeSubList( outList,
516 item->longestMatchPart->action->inlineList,
517 GenInlineItem::SubAction );
521 void BackendGen::makeExecGetTokend( GenInlineList *outList )
523 /* Make the Exec item. */
524 GenInlineItem *execItem = new GenInlineItem( InputLoc(), GenInlineItem::Exec );
525 execItem->children = new GenInlineList;
527 /* Make the GetTokEnd */
528 GenInlineItem *getTokend = new GenInlineItem( InputLoc(), GenInlineItem::LmGetTokEnd );
529 execItem->children->append( getTokend );
531 outList->append( execItem );
534 void BackendGen::makeLmOnLagBehind( GenInlineList *outList, InlineItem *item )
536 /* Jump to the tokend. */
537 makeExecGetTokend( outList );
539 if ( item->longestMatchPart->action != 0 ) {
540 makeSubList( outList,
541 item->longestMatchPart->action->inlineList,
542 GenInlineItem::SubAction );
546 void BackendGen::makeLmSwitch( GenInlineList *outList, InlineItem *item )
548 GenInlineItem *lmSwitch = new GenInlineItem( InputLoc(), GenInlineItem::LmSwitch );
549 GenInlineList *lmList = lmSwitch->children = new GenInlineList;
550 LongestMatch *longestMatch = item->longestMatch;
552 /* We can't put the <exec> here because we may need to handle the error
553 * case and in that case p should not be changed. Instead use a default
554 * label in the switch to adjust p when user actions are not set. An id of
555 * -1 indicates the default. */
557 if ( longestMatch->lmSwitchHandlesError ) {
558 /* If the switch handles error then we should have also forced the
559 * error state. */
560 assert( fsm->errState != 0 );
562 GenInlineItem *errCase = new GenInlineItem( InputLoc(), GenInlineItem::SubAction );
563 errCase->lmId = 0;
564 errCase->children = new GenInlineList;
566 /* Make the item. */
567 GenInlineItem *gotoItem = new GenInlineItem( InputLoc(), GenInlineItem::Goto );
568 gotoItem->targId = fsm->errState->alg.stateNum;
569 errCase->children->append( gotoItem );
571 lmList->append( errCase );
574 bool needDefault = false;
575 for ( LmPartList::Iter lmi = *longestMatch->longestMatchList; lmi.lte(); lmi++ ) {
576 if ( lmi->inLmSelect ) {
577 if ( lmi->action == 0 )
578 needDefault = true;
579 else {
580 /* Open the action. Write it with the context that sets up _p
581 * when doing control flow changes from inside the machine. */
582 GenInlineItem *lmCase = new GenInlineItem( InputLoc(),
583 GenInlineItem::SubAction );
584 lmCase->lmId = lmi->longestMatchId;
585 lmCase->children = new GenInlineList;
587 makeExecGetTokend( lmCase->children );
588 makeGenInlineList( lmCase->children, lmi->action->inlineList );
590 lmList->append( lmCase );
595 if ( needDefault ) {
596 GenInlineItem *defCase = new GenInlineItem( InputLoc(),
597 GenInlineItem::SubAction );
598 defCase->lmId = -1;
599 defCase->children = new GenInlineList;
601 makeExecGetTokend( defCase->children );
603 lmList->append( defCase );
606 outList->append( lmSwitch );
609 void BackendGen::makeSetTokend( GenInlineList *outList, long offset )
611 GenInlineItem *inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::LmSetTokEnd );
612 inlineItem->offset = offset;
613 outList->append( inlineItem );
616 void BackendGen::makeSetAct( GenInlineList *outList, long lmId )
618 GenInlineItem *inlineItem = new GenInlineItem( InputLoc(), GenInlineItem::LmSetActId );
619 inlineItem->lmId = lmId;
620 outList->append( inlineItem );
623 void BackendGen::makeGenInlineList( GenInlineList *outList, InlineList *inList )
625 for ( InlineList::Iter item = *inList; item.lte(); item++ ) {
626 switch ( item->type ) {
627 case InlineItem::Text:
628 makeText( outList, item );
629 break;
630 case InlineItem::Goto:
631 makeTargetItem( outList, item->nameTarg, GenInlineItem::Goto );
632 break;
633 case InlineItem::GotoExpr:
634 makeSubList( outList, item->children, GenInlineItem::GotoExpr );
635 break;
636 case InlineItem::Call:
637 makeTargetItem( outList, item->nameTarg, GenInlineItem::Call );
638 break;
639 case InlineItem::CallExpr:
640 makeSubList( outList, item->children, GenInlineItem::CallExpr );
641 break;
642 case InlineItem::Next:
643 makeTargetItem( outList, item->nameTarg, GenInlineItem::Next );
644 break;
645 case InlineItem::NextExpr:
646 makeSubList( outList, item->children, GenInlineItem::NextExpr );
647 break;
648 case InlineItem::Break:
649 outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Break ) );
650 break;
651 case InlineItem::Ret:
652 outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Ret ) );
653 break;
654 case InlineItem::PChar:
655 outList->append( new GenInlineItem( InputLoc(), GenInlineItem::PChar ) );
656 break;
657 case InlineItem::Char:
658 outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Char ) );
659 break;
660 case InlineItem::Curs:
661 outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Curs ) );
662 break;
663 case InlineItem::Targs:
664 outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Targs ) );
665 break;
666 case InlineItem::Entry:
667 makeTargetItem( outList, item->nameTarg, GenInlineItem::Entry );
668 break;
670 case InlineItem::Hold:
671 outList->append( new GenInlineItem( InputLoc(), GenInlineItem::Hold ) );
672 break;
673 case InlineItem::Exec:
674 makeSubList( outList, item->children, GenInlineItem::Exec );
675 break;
677 case InlineItem::LmSetActId:
678 makeSetAct( outList, item->longestMatchPart->longestMatchId );
679 break;
680 case InlineItem::LmSetTokEnd:
681 makeSetTokend( outList, 1 );
682 break;
684 case InlineItem::LmOnLast:
685 makeLmOnLast( outList, item );
686 break;
687 case InlineItem::LmOnNext:
688 makeLmOnNext( outList, item );
689 break;
690 case InlineItem::LmOnLagBehind:
691 makeLmOnLagBehind( outList, item );
692 break;
693 case InlineItem::LmSwitch:
694 makeLmSwitch( outList, item );
695 break;
697 case InlineItem::LmInitAct:
698 outList->append( new GenInlineItem( InputLoc(), GenInlineItem::LmInitAct ) );
699 break;
700 case InlineItem::LmInitTokStart:
701 outList->append( new GenInlineItem( InputLoc(), GenInlineItem::LmInitTokStart ) );
702 break;
703 case InlineItem::LmSetTokStart:
704 outList->append( new GenInlineItem( InputLoc(), GenInlineItem::LmSetTokStart ) );
705 cgd->hasLongestMatch = true;
706 break;
712 void XMLCodeGen::writeAction( Action *action )
714 out << " <action id=\"" << action->actionId << "\"";
715 if ( action->name != 0 )
716 out << " name=\"" << action->name << "\"";
717 out << " line=\"" << action->loc.line << "\" col=\"" << action->loc.col << "\">";
718 writeInlineList( action->inlineList );
719 out << "</action>\n";
722 void xmlEscapeHost( std::ostream &out, char *data, long len )
724 char *end = data + len;
725 while ( data != end ) {
726 switch ( *data ) {
727 case '<': out << "&lt;"; break;
728 case '>': out << "&gt;"; break;
729 case '&': out << "&amp;"; break;
730 default: out << *data; break;
732 data += 1;
736 void XMLCodeGen::writeStateActions( StateAp *state )
738 RedActionTable *toStateActions = 0;
739 if ( state->toStateActionTable.length() > 0 )
740 toStateActions = actionTableMap.find( state->toStateActionTable );
742 RedActionTable *fromStateActions = 0;
743 if ( state->fromStateActionTable.length() > 0 )
744 fromStateActions = actionTableMap.find( state->fromStateActionTable );
746 /* EOF actions go out here only if the state has no eof target. If it has
747 * an eof target then an eof transition will be used instead. */
748 RedActionTable *eofActions = 0;
749 if ( state->eofTarget == 0 && state->eofActionTable.length() > 0 )
750 eofActions = actionTableMap.find( state->eofActionTable );
752 if ( toStateActions != 0 || fromStateActions != 0 || eofActions != 0 ) {
753 out << " <state_actions>";
754 if ( toStateActions != 0 )
755 out << toStateActions->id;
756 else
757 out << "x";
759 if ( fromStateActions != 0 )
760 out << " " << fromStateActions->id;
761 else
762 out << " x";
764 if ( eofActions != 0 )
765 out << " " << eofActions->id;
766 else
767 out << " x";
769 out << "</state_actions>\n";
773 void XMLCodeGen::writeStateConditions( StateAp *state )
775 if ( state->stateCondList.length() > 0 ) {
776 out << " <cond_list length=\"" << state->stateCondList.length() << "\">\n";
777 for ( StateCondList::Iter scdi = state->stateCondList; scdi.lte(); scdi++ ) {
778 out << " <c>";
779 writeKey( scdi->lowKey );
780 out << " ";
781 writeKey( scdi->highKey );
782 out << " ";
783 out << scdi->condSpace->condSpaceId;
784 out << "</c>\n";
786 out << " </cond_list>\n";
790 void XMLCodeGen::writeStateList()
792 /* Write the list of states. */
793 out << " <state_list length=\"" << fsm->stateList.length() << "\">\n";
794 for ( StateList::Iter st = fsm->stateList; st.lte(); st++ ) {
795 out << " <state id=\"" << st->alg.stateNum << "\"";
796 if ( st->isFinState() )
797 out << " final=\"t\"";
798 out << ">\n";
800 writeStateActions( st );
801 writeEofTrans( st );
802 writeStateConditions( st );
803 writeTransList( st );
805 out << " </state>\n";
807 if ( !st.last() )
808 out << "\n";
810 out << " </state_list>\n";
813 bool XMLCodeGen::writeNameInst( NameInst *nameInst )
815 bool written = false;
816 if ( nameInst->parent != 0 )
817 written = writeNameInst( nameInst->parent );
819 if ( nameInst->name != 0 ) {
820 if ( written )
821 out << '_';
822 out << nameInst->name;
823 written = true;
826 return written;
829 void XMLCodeGen::writeEntryPoints()
831 /* List of entry points other than start state. */
832 if ( fsm->entryPoints.length() > 0 || pd->lmRequiresErrorState ) {
833 out << " <entry_points";
834 if ( pd->lmRequiresErrorState )
835 out << " error=\"t\"";
836 out << ">\n";
837 for ( EntryMap::Iter en = fsm->entryPoints; en.lte(); en++ ) {
838 /* Get the name instantiation from nameIndex. */
839 NameInst *nameInst = pd->nameIndex[en->key];
840 StateAp *state = en->value;
841 out << " <entry name=\"";
842 writeNameInst( nameInst );
843 out << "\">" << state->alg.stateNum << "</entry>\n";
845 out << " </entry_points>\n";
849 void XMLCodeGen::writeMachine()
851 /* Open the machine. */
852 out << " <machine>\n";
854 /* Action tables. */
855 reduceActionTables();
857 writeActionList();
858 writeActionTableList();
859 writeConditions();
861 /* Start state. */
862 out << " <start_state>" << fsm->startState->alg.stateNum <<
863 "</start_state>\n";
865 /* Error state. */
866 if ( fsm->errState != 0 ) {
867 out << " <error_state>" << fsm->errState->alg.stateNum <<
868 "</error_state>\n";
871 writeEntryPoints();
872 writeStateList();
874 out << " </machine>\n";
878 void XMLCodeGen::writeConditions()
880 if ( condData->condSpaceMap.length() > 0 ) {
881 long nextCondSpaceId = 0;
882 for ( CondSpaceMap::Iter cs = condData->condSpaceMap; cs.lte(); cs++ )
883 cs->condSpaceId = nextCondSpaceId++;
885 out << " <cond_space_list length=\"" << condData->condSpaceMap.length() << "\">\n";
886 for ( CondSpaceMap::Iter cs = condData->condSpaceMap; cs.lte(); cs++ ) {
887 out << " <cond_space id=\"" << cs->condSpaceId <<
888 "\" length=\"" << cs->condSet.length() << "\">";
889 writeKey( cs->baseKey );
890 for ( CondSet::Iter csi = cs->condSet; csi.lte(); csi++ )
891 out << " " << (*csi)->actionId;
892 out << "</cond_space>\n";
894 out << " </cond_space_list>\n";
898 void XMLCodeGen::writeExports()
900 if ( pd->exportList.length() > 0 ) {
901 out << " <exports>\n";
902 for ( ExportList::Iter exp = pd->exportList; exp.lte(); exp++ ) {
903 out << " <ex name=\"" << exp->name << "\">";
904 writeKey( exp->key );
905 out << "</ex>\n";
907 out << " </exports>\n";
911 void XMLCodeGen::writeXML()
913 /* Open the definition. */
914 out << "<ragel_def name=\"" << fsmName << "\">\n";
916 /* Alphabet type. */
917 out << " <alphtype>" << keyOps->alphType->internalName << "</alphtype>\n";
919 /* Getkey expression. */
920 if ( pd->getKeyExpr != 0 ) {
921 out << " <getkey>";
922 writeInlineList( pd->getKeyExpr );
923 out << "</getkey>\n";
926 /* Access expression. */
927 if ( pd->accessExpr != 0 ) {
928 out << " <access>";
929 writeInlineList( pd->accessExpr );
930 out << "</access>\n";
933 /* PrePush expression. */
934 if ( pd->prePushExpr != 0 ) {
935 out << " <prepush>";
936 writeInlineList( pd->prePushExpr );
937 out << "</prepush>\n";
940 /* PostPop expression. */
941 if ( pd->postPopExpr != 0 ) {
942 out << " <postpop>";
943 writeInlineList( pd->postPopExpr );
944 out << "</postpop>\n";
948 * Variable expressions.
951 if ( pd->pExpr != 0 ) {
952 out << " <p_expr>";
953 writeInlineList( pd->pExpr );
954 out << "</p_expr>\n";
957 if ( pd->peExpr != 0 ) {
958 out << " <pe_expr>";
959 writeInlineList( pd->peExpr );
960 out << "</pe_expr>\n";
963 if ( pd->eofExpr != 0 ) {
964 out << " <eof_expr>";
965 writeInlineList( pd->eofExpr );
966 out << "</eof_expr>\n";
969 if ( pd->csExpr != 0 ) {
970 out << " <cs_expr>";
971 writeInlineList( pd->csExpr );
972 out << "</cs_expr>\n";
975 if ( pd->topExpr != 0 ) {
976 out << " <top_expr>";
977 writeInlineList( pd->topExpr );
978 out << "</top_expr>\n";
981 if ( pd->stackExpr != 0 ) {
982 out << " <stack_expr>";
983 writeInlineList( pd->stackExpr );
984 out << "</stack_expr>\n";
987 if ( pd->actExpr != 0 ) {
988 out << " <act_expr>";
989 writeInlineList( pd->actExpr );
990 out << "</act_expr>\n";
993 if ( pd->tokstartExpr != 0 ) {
994 out << " <tokstart_expr>";
995 writeInlineList( pd->tokstartExpr );
996 out << "</tokstart_expr>\n";
999 if ( pd->tokendExpr != 0 ) {
1000 out << " <tokend_expr>";
1001 writeInlineList( pd->tokendExpr );
1002 out << "</tokend_expr>\n";
1005 if ( pd->dataExpr != 0 ) {
1006 out << " <data_expr>";
1007 writeInlineList( pd->dataExpr );
1008 out << "</data_expr>\n";
1011 writeExports();
1013 writeMachine();
1015 out <<
1016 "</ragel_def>\n";
1019 void BackendGen::makeExports()
1021 for ( ExportList::Iter exp = pd->exportList; exp.lte(); exp++ )
1022 cgd->exportList.append( new Export( exp->name, exp->key ) );
1025 void BackendGen::makeAction( Action *action )
1027 GenInlineList *genList = new GenInlineList;
1028 makeGenInlineList( genList, action->inlineList );
1030 cgd->newAction( curAction++, action->name, action->loc, 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 cgd->initActionList( nextActionId );
1045 curAction = 0;
1047 for ( ActionList::Iter act = pd->actionList; act.lte(); act++ ) {
1048 if ( act->actionId >= 0 )
1049 makeAction( act );
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 cgd->initActionTableList( numTables );
1062 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 = cgd->allActionTables + curActionTable;
1069 redAct->actListId = 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 = cgd->allActions +
1075 atel->value->actionId;
1078 /* Insert into the action table map. */
1079 cgd->redFsm->actionMap.insert( redAct );
1081 curActionTable += 1;
1084 delete[] tables;
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 cgd->initCondSpaceList( listLength );
1096 curCondSpace = 0;
1098 for ( CondSpaceMap::Iter cs = condData->condSpaceMap; cs.lte(); cs++ ) {
1099 long id = cs->condSpaceId;
1100 cgd->newCondSpace( curCondSpace, id, cs->baseKey );
1101 for ( CondSet::Iter csi = cs->condSet; csi.lte(); csi++ )
1102 cgd->condSpaceItem( curCondSpace, (*csi)->actionId );
1103 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 ) {
1115 if ( written )
1116 res += '_';
1117 res += nameInst->name;
1118 written = true;
1121 return written;
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 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];
1134 std::string name;
1135 makeNameInst( name, nameInst );
1136 StateAp *state = en->value;
1137 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 ) {
1159 long to = -1;
1160 if ( toStateActions != 0 )
1161 to = toStateActions->id;
1163 long from = -1;
1164 if ( fromStateActions != 0 )
1165 from = fromStateActions->id;
1167 long eof = -1;
1168 if ( eofActions != 0 )
1169 eof = eofActions->id;
1171 cgd->setStateActions( 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;
1185 long action = -1;
1186 if ( eofActions != 0 )
1187 action = eofActions->id;
1189 cgd->setEofTrans( curState, targ, action );
1193 void BackendGen::makeStateConditions( StateAp *state )
1195 if ( state->stateCondList.length() > 0 ) {
1196 long length = state->stateCondList.length();
1197 cgd->initStateCondList( curState, length );
1198 curStateCond = 0;
1200 for ( StateCondList::Iter scdi = state->stateCondList; scdi.lte(); scdi++ ) {
1201 cgd->addStateCond( 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 );
1214 long targ = -1;
1215 if ( trans->toState != 0 )
1216 targ = trans->toState->alg.stateNum;
1218 long action = -1;
1219 if ( actionTable != 0 )
1220 action = actionTable->id;
1222 cgd->newTrans( curState, 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 cgd->initTransList( curState, outList.length() );
1239 curTrans = 0;
1241 for ( TransListVect::Iter tvi = outList; tvi.lte(); tvi++ )
1242 makeTrans( tvi->lowKey, tvi->highKey, tvi->value );
1244 cgd->finishTransList( curState );
1248 void BackendGen::makeStateList()
1250 /* Write the list of states. */
1251 long length = fsm->stateList.length();
1252 cgd->initStateList( length );
1253 curState = 0;
1254 for ( StateList::Iter st = fsm->stateList; st.lte(); st++ ) {
1255 makeStateActions( st );
1256 makeEofTrans( st );
1257 makeStateConditions( st );
1258 makeTransList( st );
1260 long id = st->alg.stateNum;
1261 cgd->setId( curState, id );
1263 if ( st->isFinState() )
1264 cgd->setFinal( curState );
1266 curState += 1;
1271 void BackendGen::makeMachine()
1273 cgd->createMachine();
1275 /* Action tables. */
1276 reduceActionTables();
1278 makeActionList();
1279 makeActionTableList();
1280 makeConditions();
1282 /* Start State. */
1283 cgd->setStartState( fsm->startState->alg.stateNum );
1285 /* Error state. */
1286 if ( fsm->errState != 0 )
1287 cgd->setErrorState( fsm->errState->alg.stateNum );
1289 makeEntryPoints();
1290 makeStateList();
1292 cgd->closeMachine();
1295 void BackendGen::close_ragel_def()
1297 /* Do this before distributing transitions out to singles and defaults
1298 * makes life easier. */
1299 cgd->redFsm->maxKey = cgd->findMaxKey();
1301 cgd->redFsm->assignActionLocs();
1303 /* Find the first final state (The final state with the lowest id). */
1304 cgd->redFsm->findFirstFinState();
1306 /* Call the user's callback. */
1307 cgd->finishRagelDef();
1311 void BackendGen::makeBackend()
1313 /* Alphabet type. */
1314 cgd->setAlphType( keyOps->alphType->internalName );
1316 /* Getkey expression. */
1317 if ( pd->getKeyExpr != 0 ) {
1318 cgd->getKeyExpr = new GenInlineList;
1319 makeGenInlineList( cgd->getKeyExpr, pd->getKeyExpr );
1322 /* Access expression. */
1323 if ( pd->accessExpr != 0 ) {
1324 cgd->accessExpr = new GenInlineList;
1325 makeGenInlineList( cgd->accessExpr, pd->accessExpr );
1328 /* PrePush expression. */
1329 if ( pd->prePushExpr != 0 ) {
1330 cgd->prePushExpr = new GenInlineList;
1331 makeGenInlineList( cgd->prePushExpr, pd->prePushExpr );
1334 /* PostPop expression. */
1335 if ( pd->postPopExpr != 0 ) {
1336 cgd->postPopExpr = new GenInlineList;
1337 makeGenInlineList( cgd->postPopExpr, pd->postPopExpr );
1341 * Variable expressions.
1344 if ( pd->pExpr != 0 ) {
1345 cgd->pExpr = new GenInlineList;
1346 makeGenInlineList( cgd->pExpr, pd->pExpr );
1349 if ( pd->peExpr != 0 ) {
1350 cgd->peExpr = new GenInlineList;
1351 makeGenInlineList( cgd->peExpr, pd->peExpr );
1354 if ( pd->eofExpr != 0 ) {
1355 cgd->eofExpr = new GenInlineList;
1356 makeGenInlineList( cgd->eofExpr, pd->eofExpr );
1359 if ( pd->csExpr != 0 ) {
1360 cgd->csExpr = new GenInlineList;
1361 makeGenInlineList( cgd->csExpr, pd->csExpr );
1364 if ( pd->topExpr != 0 ) {
1365 cgd->topExpr = new GenInlineList;
1366 makeGenInlineList( cgd->topExpr, pd->topExpr );
1369 if ( pd->stackExpr != 0 ) {
1370 cgd->stackExpr = new GenInlineList;
1371 makeGenInlineList( cgd->stackExpr, pd->stackExpr );
1374 if ( pd->actExpr != 0 ) {
1375 cgd->actExpr = new GenInlineList;
1376 makeGenInlineList( cgd->actExpr, pd->actExpr );
1379 if ( pd->tokstartExpr != 0 ) {
1380 cgd->tokstartExpr = new GenInlineList;
1381 makeGenInlineList( cgd->tokstartExpr, pd->tokstartExpr );
1384 if ( pd->tokendExpr != 0 ) {
1385 cgd->tokendExpr = new GenInlineList;
1386 makeGenInlineList( cgd->tokendExpr, pd->tokendExpr );
1389 if ( pd->dataExpr != 0 ) {
1390 cgd->dataExpr = new GenInlineList;
1391 makeGenInlineList( cgd->dataExpr, pd->dataExpr );
1394 makeExports();
1395 makeMachine();
1397 close_ragel_def();
1400 void InputData::writeLanguage( std::ostream &out )
1402 out << " lang=\"";
1403 switch ( hostLang->lang ) {
1404 case HostLang::C: out << "C"; break;
1405 case HostLang::D: out << "D"; break;
1406 case HostLang::D2: out << "D2"; break;
1407 case HostLang::Go: out << "Go"; break;
1408 case HostLang::Java: out << "Java"; break;
1409 case HostLang::Ruby: out << "Ruby"; break;
1410 case HostLang::CSharp: out << "C#"; break;
1411 case HostLang::OCaml: out << "OCaml"; break;
1413 out << "\"";
1416 void InputData::writeXML( std::ostream &out )
1418 out << "<ragel version=\"" VERSION "\" filename=\"" << inputFileName << "\"";
1419 writeLanguage( out );
1420 out << ">\n";
1422 for ( ParserDict::Iter parser = parserDict; parser.lte(); parser++ ) {
1423 ParseData *pd = parser->value->pd;
1424 if ( pd->instanceList.length() > 0 )
1425 pd->generateXML( *outStream );
1428 out << "</ragel>\n";