2 * Copyright 2005-2006 Adrian Thurston <thurston@cs.queensu.ca>
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 /* Code Generators. */
26 #include "tabcodegen.h"
27 #include "ftabcodegen.h"
28 #include "flatcodegen.h"
29 #include "fflatcodegen.h"
30 #include "gotocodegen.h"
31 #include "fgotocodegen.h"
32 #include "ipgotocodegen.h"
33 #include "splitcodegen.h"
34 #include "javacodegen.h"
43 void CodeGenData::createMachine()
45 redFsm = new RedFsmAp();
48 void CodeGenData::initActionList( unsigned long length )
50 allActions = new Action[length];
51 for ( unsigned long a = 0; a < length; a++ )
52 actionList.append( allActions+a );
55 void CodeGenData::newAction( int anum, char *name, int line,
56 int col, InlineList *inlineList )
58 allActions[anum].actionId = anum;
59 allActions[anum].name = name;
60 allActions[anum].loc.line = line;
61 allActions[anum].loc.col = col;
62 allActions[anum].inlineList = inlineList;
65 void CodeGenData::initActionTableList( unsigned long length )
67 allActionTables = new RedAction[length];
70 void CodeGenData::initStateList( unsigned long length )
72 allStates = new RedStateAp[length];
73 for ( unsigned long s = 0; s < length; s++ )
74 redFsm->stateList.append( allStates+s );
77 void CodeGenData::setStartState( unsigned long startState )
79 this->startState = startState;
82 void CodeGenData::addEntryPoint( char *name, unsigned long entryState )
84 entryPointIds.append( entryState );
85 entryPointNames.append( name );
88 void CodeGenData::initTransList( int snum, unsigned long length )
90 /* Could preallocate the out range to save time growing it. For now do
94 void CodeGenData::newTrans( int snum, int tnum, Key lowKey,
95 Key highKey, long targ, long action )
97 /* Get the current state and range. */
98 RedStateAp *curState = allStates + snum;
99 RedTransList &destRange = curState->outRange;
101 /* Make the new transitions. */
102 RedStateAp *targState = targ >= 0 ? (allStates + targ) :
103 wantComplete ? redFsm->getErrorState() : 0;
104 RedAction *actionTable = action >= 0 ? (allActionTables + action) : 0;
105 RedTransAp *trans = redFsm->allocateTrans( targState, actionTable );
106 RedTransEl transEl( lowKey, highKey, trans );
108 if ( wantComplete ) {
109 /* If the machine is to be complete then we need to fill any gaps with
110 * the error transitions. */
111 if ( destRange.length() == 0 ) {
112 /* Range is currently empty. */
113 if ( keyOps->minKey < lowKey ) {
114 /* The first range doesn't start at the low end. */
115 Key fillHighKey = lowKey;
116 fillHighKey.decrement();
118 /* Create the filler with the state's error transition. */
119 RedTransEl newTel( keyOps->minKey, fillHighKey, redFsm->getErrorTrans() );
120 destRange.append( newTel );
124 /* The range list is not empty, get the the last range. */
125 RedTransEl *last = &destRange[destRange.length()-1];
126 Key nextKey = last->highKey;
128 if ( nextKey < lowKey ) {
129 /* There is a gap to fill. Make the high key. */
130 Key fillHighKey = lowKey;
131 fillHighKey.decrement();
133 /* Create the filler with the state's error transtion. */
134 RedTransEl newTel( nextKey, fillHighKey, redFsm->getErrorTrans() );
135 destRange.append( newTel );
140 /* Filler taken care of. Append the range. */
141 destRange.append( RedTransEl( lowKey, highKey, trans ) );
144 void CodeGenData::finishTransList( int snum )
146 /* Get the current state and range. */
147 RedStateAp *curState = allStates + snum;
148 RedTransList &destRange = curState->outRange;
150 /* If building a complete machine we may need filler on the end. */
151 if ( wantComplete ) {
152 /* Check if there are any ranges already. */
153 if ( destRange.length() == 0 ) {
154 /* Fill with the whole alphabet. */
155 /* Add the range on the lower and upper bound. */
156 RedTransEl newTel( keyOps->minKey, keyOps->maxKey, redFsm->getErrorTrans() );
157 destRange.append( newTel );
160 /* Get the last and check for a gap on the end. */
161 RedTransEl *last = &destRange[destRange.length()-1];
162 if ( last->highKey < keyOps->maxKey ) {
163 /* Make the high key. */
164 Key fillLowKey = last->highKey;
165 fillLowKey.increment();
167 /* Create the new range with the error trans and append it. */
168 RedTransEl newTel( fillLowKey, keyOps->maxKey, redFsm->getErrorTrans() );
169 destRange.append( newTel );
175 void CodeGenData::setFinal( int snum )
177 RedStateAp *curState = allStates + snum;
178 curState->isFinal = true;
182 void CodeGenData::setStateActions( int snum, long toStateAction,
183 long fromStateAction, long eofAction )
185 RedStateAp *curState = allStates + snum;
186 if ( toStateAction >= 0 )
187 curState->toStateAction = allActionTables + toStateAction;
188 if ( fromStateAction >= 0 )
189 curState->fromStateAction = allActionTables + fromStateAction;
190 if ( eofAction >= 0 )
191 curState->eofAction = allActionTables + eofAction;
194 void CodeGenData::resolveTargetStates( InlineList *inlineList )
196 for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
197 switch ( item->type ) {
198 case InlineItem::Goto: case InlineItem::Call:
199 case InlineItem::Next: case InlineItem::Entry:
200 item->targState = allStates + item->targId;
206 if ( item->children != 0 )
207 resolveTargetStates( item->children );
212 void CodeGenData::finishMachine()
214 if ( redFsm->forcedErrorState )
215 redFsm->getErrorState();
217 /* We get the start state as an offset, set the pointer now. */
218 redFsm->startState = allStates + startState;
219 for ( EntryIdVect::Iter en = entryPointIds; en.lte(); en++ )
220 redFsm->entryPoints.insert( allStates + *en );
222 for ( ActionList::Iter a = actionList; a.lte(); a++ )
223 resolveTargetStates( a->inlineList );
225 /* Note that even if we want a complete graph we do not give the error
226 * state a default transition. All machines break out of the processing
227 * loop when in the error state. */
229 if ( codeStyle == GenGoto || codeStyle == GenFGoto || codeStyle == GenIpGoto ) {
230 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
231 for ( StateCondList::Iter sci = st->stateCondList; sci.lte(); sci++ )
232 st->stateCondVect.append( sci );
238 bool CodeGenData::setAlphType( char *data )
240 /* FIXME: This should validate the alphabet type selection. */
241 HostType *alphType = hostLang->hostTypes + atoi(data);
242 thisKeyOps.setAlphType( alphType );
246 void CodeGenData::initCondSpaceList( ulong length )
248 allCondSpaces = new CondSpace[length];
249 for ( ulong c = 0; c < length; c++ )
250 condSpaceList.append( allCondSpaces + c );
253 void CodeGenData::newCondSpace( int cnum, int condSpaceId, Key baseKey )
255 CondSpace *cond = allCondSpaces + cnum;
256 cond->condSpaceId = condSpaceId;
257 cond->baseKey = baseKey;
260 void CodeGenData::condSpaceItem( int cnum, long condActionId )
262 CondSpace *cond = allCondSpaces + cnum;
263 cond->condSet.append( allActions + condActionId );
266 void CodeGenData::initStateCondList( int snum, ulong length )
268 /* Could preallocate these, as we could with transitions. */
271 void CodeGenData::addStateCond( int snum, Key lowKey, Key highKey, long condNum )
273 RedStateAp *curState = allStates + snum;
275 /* Create the new state condition. */
276 StateCond *stateCond = new StateCond;
277 stateCond->lowKey = lowKey;
278 stateCond->highKey = highKey;
280 /* Assign it a cond space. */
281 CondSpace *condSpace = allCondSpaces + condNum;
282 stateCond->condSpace = condSpace;
284 curState->stateCondList.append( stateCond );
288 /* Generate the codegen depending on the command line options given. */
289 void CodeGenData::makeCodeGen()
291 switch ( hostLangType ) {
293 switch ( codeStyle ) {
295 codeGen = new CTabCodeGen(out);
298 codeGen = new CFTabCodeGen(out);
301 codeGen = new CFlatCodeGen(out);
304 codeGen = new CFFlatCodeGen(out);
307 codeGen = new CGotoCodeGen(out);
310 codeGen = new CFGotoCodeGen(out);
313 codeGen = new CIpGotoCodeGen(out);
316 codeGen = new CSplitCodeGen(out);
322 switch ( codeStyle ) {
324 codeGen = new DTabCodeGen(out);
327 codeGen = new DFTabCodeGen(out);
330 codeGen = new DFlatCodeGen(out);
333 codeGen = new DFFlatCodeGen(out);
336 codeGen = new DGotoCodeGen(out);
339 codeGen = new DFGotoCodeGen(out);
342 codeGen = new DIpGotoCodeGen(out);
345 codeGen = new DSplitCodeGen(out);
351 switch ( codeStyle ) {
353 codeGen = new JavaTabCodeGen(out);
365 CondSpace *CodeGenData::findCondSpace( Key lowKey, Key highKey )
367 for ( CondSpaceList::Iter cs = condSpaceList; cs.lte(); cs++ ) {
368 Key csHighKey = cs->baseKey;
369 csHighKey += keyOps->alphSize() * (1 << cs->condSet.length());
371 if ( lowKey >= cs->baseKey && highKey <= csHighKey )
377 Condition *CodeGenData::findCondition( Key key )
379 for ( ConditionList::Iter cond = conditionList; cond.lte(); cond++ ) {
380 Key upperKey = cond->baseKey + (1 << cond->condSet.length());
381 if ( cond->baseKey <= key && key <= upperKey )
387 Key CodeGenData::findMaxKey()
389 Key maxKey = keyOps->maxKey;
390 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
391 assert( st->outSingle.length() == 0 );
392 assert( st->defTrans == 0 );
394 long rangeLen = st->outRange.length();
395 if ( rangeLen > 0 ) {
396 Key highKey = st->outRange[rangeLen-1].highKey;
397 if ( highKey > maxKey )
404 void CodeGenData::findFinalActionRefs()
406 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
407 /* Rerence count out of single transitions. */
408 for ( RedTransList::Iter rtel = st->outSingle; rtel.lte(); rtel++ ) {
409 if ( rtel->value->action != 0 ) {
410 rtel->value->action->numTransRefs += 1;
411 for ( ActionTable::Iter item = rtel->value->action->key; item.lte(); item++ )
412 item->value->numTransRefs += 1;
416 /* Reference count out of range transitions. */
417 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
418 if ( rtel->value->action != 0 ) {
419 rtel->value->action->numTransRefs += 1;
420 for ( ActionTable::Iter item = rtel->value->action->key; item.lte(); item++ )
421 item->value->numTransRefs += 1;
425 /* Reference count default transition. */
426 if ( st->defTrans != 0 && st->defTrans->action != 0 ) {
427 st->defTrans->action->numTransRefs += 1;
428 for ( ActionTable::Iter item = st->defTrans->action->key; item.lte(); item++ )
429 item->value->numTransRefs += 1;
432 /* Reference count to state actions. */
433 if ( st->toStateAction != 0 ) {
434 st->toStateAction->numToStateRefs += 1;
435 for ( ActionTable::Iter item = st->toStateAction->key; item.lte(); item++ )
436 item->value->numToStateRefs += 1;
439 /* Reference count from state actions. */
440 if ( st->fromStateAction != 0 ) {
441 st->fromStateAction->numFromStateRefs += 1;
442 for ( ActionTable::Iter item = st->fromStateAction->key; item.lte(); item++ )
443 item->value->numFromStateRefs += 1;
446 /* Reference count EOF actions. */
447 if ( st->eofAction != 0 ) {
448 st->eofAction->numEofRefs += 1;
449 for ( ActionTable::Iter item = st->eofAction->key; item.lte(); item++ )
450 item->value->numEofRefs += 1;
455 void CodeGenData::analyzeAction( Action *act, InlineList *inlineList )
457 for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
458 /* Only consider actions that are referenced. */
459 if ( act->numRefs() > 0 ) {
460 if ( item->type == InlineItem::Goto || item->type == InlineItem::GotoExpr )
461 codeGen->bAnyActionGotos = true;
462 else if ( item->type == InlineItem::Call || item->type == InlineItem::CallExpr )
463 codeGen->bAnyActionCalls = true;
464 else if ( item->type == InlineItem::Ret )
465 codeGen->bAnyActionRets = true;
468 /* Check for various things in regular actions. */
469 if ( act->numTransRefs > 0 || act->numToStateRefs > 0 || act->numFromStateRefs > 0 ) {
470 /* Any returns in regular actions? */
471 if ( item->type == InlineItem::Ret )
472 codeGen->bAnyRegActionRets = true;
474 /* Any next statements in the regular actions? */
475 if ( item->type == InlineItem::Next || item->type == InlineItem::NextExpr )
476 codeGen->bAnyRegNextStmt = true;
478 /* Any by value control in regular actions? */
479 if ( item->type == InlineItem::CallExpr || item->type == InlineItem::GotoExpr )
480 codeGen->bAnyRegActionByValControl = true;
482 /* Any references to the current state in regular actions? */
483 if ( item->type == InlineItem::Curs )
484 codeGen->bAnyRegCurStateRef = true;
486 if ( item->type == InlineItem::Break )
487 codeGen->bAnyRegBreak = true;
489 if ( item->type == InlineItem::LmSwitch && item->handlesError )
490 codeGen->bAnyLmSwitchError = true;
493 if ( item->children != 0 )
494 analyzeAction( act, item->children );
498 void CodeGenData::analyzeActionList( RedAction *redAct, InlineList *inlineList )
500 for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
501 /* Any next statements in the action table? */
502 if ( item->type == InlineItem::Next || item->type == InlineItem::NextExpr )
503 redAct->bAnyNextStmt = true;
505 /* Any references to the current state. */
506 if ( item->type == InlineItem::Curs )
507 redAct->bAnyCurStateRef = true;
509 if ( item->type == InlineItem::Break )
510 redAct->bAnyBreakStmt = true;
512 if ( item->children != 0 )
513 analyzeActionList( redAct, item->children );
517 /* Assign ids to referenced actions. */
518 void CodeGenData::assignActionIds()
520 int nextActionId = 0;
521 for ( ActionList::Iter act = cgd->actionList; act.lte(); act++ ) {
522 /* Only ever interested in referenced actions. */
523 if ( act->numRefs() > 0 )
524 act->actionId = nextActionId++;
528 void CodeGenData::setValueLimits()
530 codeGen->maxSingleLen = 0;
531 codeGen->maxRangeLen = 0;
532 codeGen->maxKeyOffset = 0;
533 codeGen->maxIndexOffset = 0;
534 codeGen->maxActListId = 0;
535 codeGen->maxActionLoc = 0;
536 codeGen->maxActArrItem = 0;
537 codeGen->maxSpan = 0;
538 codeGen->maxCondSpan = 0;
539 codeGen->maxFlatIndexOffset = 0;
540 codeGen->maxCondOffset = 0;
541 codeGen->maxCondLen = 0;
542 codeGen->maxCondSpaceId = 0;
543 codeGen->maxCondIndexOffset = 0;
545 /* In both of these cases the 0 index is reserved for no value, so the max
546 * is one more than it would be if they started at 0. */
547 codeGen->maxIndex = redFsm->transSet.length();
548 codeGen->maxCond = cgd->condSpaceList.length();
550 /* The nextStateId - 1 is the last state id assigned. */
551 codeGen->maxState = redFsm->nextStateId - 1;
553 for ( CondSpaceList::Iter csi = cgd->condSpaceList; csi.lte(); csi++ ) {
554 if ( csi->condSpaceId > codeGen->maxCondSpaceId )
555 codeGen->maxCondSpaceId = csi->condSpaceId;
558 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
559 /* Maximum cond length. */
560 if ( st->stateCondList.length() > codeGen->maxCondLen )
561 codeGen->maxCondLen = st->stateCondList.length();
563 /* Maximum single length. */
564 if ( st->outSingle.length() > codeGen->maxSingleLen )
565 codeGen->maxSingleLen = st->outSingle.length();
567 /* Maximum range length. */
568 if ( st->outRange.length() > codeGen->maxRangeLen )
569 codeGen->maxRangeLen = st->outRange.length();
571 /* The key offset index offset for the state after last is not used, skip it.. */
573 codeGen->maxCondOffset += st->stateCondList.length();
574 codeGen->maxKeyOffset += st->outSingle.length() + st->outRange.length()*2;
575 codeGen->maxIndexOffset += st->outSingle.length() + st->outRange.length() + 1;
579 if ( st->condList != 0 ) {
580 unsigned long long span = keyOps->span( st->condLowKey, st->condHighKey );
581 if ( span > codeGen->maxCondSpan )
582 codeGen->maxCondSpan = span;
586 if ( st->transList != 0 ) {
587 unsigned long long span = keyOps->span( st->lowKey, st->highKey );
588 if ( span > codeGen->maxSpan )
589 codeGen->maxSpan = span;
592 /* Max cond index offset. */
594 if ( st->condList != 0 )
595 codeGen->maxCondIndexOffset += keyOps->span( st->condLowKey, st->condHighKey );
598 /* Max flat index offset. */
600 if ( st->transList != 0 )
601 codeGen->maxFlatIndexOffset += keyOps->span( st->lowKey, st->highKey );
602 codeGen->maxFlatIndexOffset += 1;
606 for ( ActionTableMap::Iter at = redFsm->actionMap; at.lte(); at++ ) {
607 /* Maximum id of action lists. */
608 if ( at->actListId+1 > codeGen->maxActListId )
609 codeGen->maxActListId = at->actListId+1;
611 /* Maximum location of items in action array. */
612 if ( at->location+1 > codeGen->maxActionLoc )
613 codeGen->maxActionLoc = at->location+1;
615 /* Maximum values going into the action array. */
616 if ( at->key.length() > codeGen->maxActArrItem )
617 codeGen->maxActArrItem = at->key.length();
618 for ( ActionTable::Iter item = at->key; item.lte(); item++ ) {
619 if ( item->value->actionId > codeGen->maxActArrItem )
620 codeGen->maxActArrItem = item->value->actionId;
627 /* Gather various info on the machine. */
628 void CodeGenData::analyzeMachine()
630 /* Find the true count of action references. */
631 findFinalActionRefs();
633 /* Check if there are any calls in action code. */
634 for ( ActionList::Iter act = cgd->actionList; act.lte(); act++ ) {
635 /* Record the occurrence of various kinds of actions. */
636 if ( act->numToStateRefs > 0 )
637 codeGen->bAnyToStateActions = true;
638 if ( act->numFromStateRefs > 0 )
639 codeGen->bAnyFromStateActions = true;
640 if ( act->numEofRefs > 0 )
641 codeGen->bAnyEofActions = true;
642 if ( act->numTransRefs > 0 )
643 codeGen->bAnyRegActions = true;
645 /* Recurse through the action's parse tree looking for various things. */
646 analyzeAction( act, act->inlineList );
649 /* Analyze reduced action lists. */
650 for ( ActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
651 for ( ActionTable::Iter act = redAct->key; act.lte(); act++ )
652 analyzeActionList( redAct, act->value->inlineList );
655 /* Find states that have transitions with actions that have next
657 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
658 /* Check any actions out of outSinge. */
659 for ( RedTransList::Iter rtel = st->outSingle; rtel.lte(); rtel++ ) {
660 if ( rtel->value->action != 0 && rtel->value->action->anyCurStateRef() )
661 st->bAnyRegCurStateRef = true;
664 /* Check any actions out of outRange. */
665 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
666 if ( rtel->value->action != 0 && rtel->value->action->anyCurStateRef() )
667 st->bAnyRegCurStateRef = true;
670 /* Check any action out of default. */
671 if ( st->defTrans != 0 && st->defTrans->action != 0 &&
672 st->defTrans->action->anyCurStateRef() )
673 st->bAnyRegCurStateRef = true;
675 if ( st->stateCondList.length() > 0 )
676 codeGen->bAnyConditions = true;
679 /* Assign ids to actions that are referenced. */
682 /* Set the maximums of various values used for deciding types. */
685 /* Determine if we should use indicies. */
686 codeGen->calcIndexSize();
689 /* Generate the code for an fsm. Assumes parseData is set up properly. Called
691 void CodeGenData::prepareMachine()
693 if ( hasBeenPrepared )
695 hasBeenPrepared = true;
697 /* Do this before distributing transitions out to singles and defaults
698 * makes life easier. */
699 Key maxKey = findMaxKey();
701 redFsm->assignActionLocs();
703 /* Order the states. */
704 redFsm->depthFirstOrdering();
706 if ( codeStyle == GenGoto || codeStyle == GenFGoto ||
707 codeStyle == GenIpGoto || codeStyle == GenSplit )
709 /* For goto driven machines we can keep the original depth
710 * first ordering because it's ok if the state ids are not
711 * sequential. Split the the ids by final state status. */
712 redFsm->sortStateIdsByFinal();
715 /* For table driven machines the location of the state is used to
716 * identify it so the states must be sorted by their final ids.
717 * Though having a deterministic ordering is important,
718 * specifically preserving the depth first ordering is not because
719 * states are stored in tables. */
720 redFsm->sortStatesByFinal();
721 redFsm->sequentialStateIds();
724 /* Find the first final state. This is the final state with the lowest
726 redFsm->findFirstFinState();
728 /* Choose default transitions and the single transition. */
729 redFsm->chooseDefaultSpan();
731 /* Maybe do flat expand, otherwise choose single. */
732 if ( codeStyle == GenFlat || codeStyle == GenFFlat )
735 redFsm->chooseSingle();
737 /* If any errors have occured in the input file then don't write anything. */
738 if ( gblErrorCount > 0 )
741 if ( codeStyle == GenSplit )
742 redFsm->partitionFsm( numSplitPartitions );
744 if ( codeStyle == GenIpGoto || codeStyle == GenSplit )
745 redFsm->setInTrans();
747 /* Make a code generator that will output the header/code. */
750 codeGen->redFsm = redFsm;
752 /* Anlayze Machine will find the final action reference counts, among
753 * other things. We will use these in reporting the usage
754 * of fsm directives in action code. */
756 codeGen->maxKey = maxKey;
759 void CodeGenData::generateGraphviz()
761 /* Do ordering and choose state ids. */
762 redFsm->depthFirstOrdering();
763 redFsm->sequentialStateIds();
765 /* For dot file generation we want to pick default transitions. */
766 redFsm->chooseDefaultSpan();
768 /* Make the generator. */
769 GraphvizDotGen dotGen( fsmName, this, redFsm, out );
771 /* Write out with it. */
772 dotGen.writeDotFile();
775 void CodeGenData::generateCode()
777 if ( writeOps & WO_NOEND )
780 if ( writeOps & WO_NOERROR )
783 if ( writeOps & WO_NOPREFIX )
786 if ( writeOps & WO_NOFF )
787 writeFirstFinal = false;
789 if ( writeData || writeInit || writeExec || writeEOF ) {
792 /* Force a newline. */
794 genLineDirective( out );
799 /* Must set labels immediately before writing because we may depend
800 * on the noend write option. */
801 codeGen->setLabelsNeeded();
805 codeGen->writeOutData();
808 codeGen->writeOutInit();
811 codeGen->writeOutExec();
814 codeGen->writeOutEOF();
817 void CodeGenData::generate()
820 if ( outputFormat == OutCode )
822 else if ( outputFormat == OutGraphvizDot && !graphvizDone ) {
829 void lineDirective( ostream &out, char *fileName, int line )
831 if ( hostLangType != JavaCode ) {
832 /* Write the preprocessor line info for to the input file. */
833 out << "#line " << line << " \"";
834 for ( char *pc = fileName; *pc != 0; pc++ ) {
844 void genLineDirective( ostream &out )
846 assert( outputFormat == OutCode );
847 std::streambuf *sbuf = out.rdbuf();
848 output_filter *filter = static_cast<output_filter*>(sbuf);
849 lineDirective( out, filter->fileName, filter->line + 1 );