The p varialbe is now set up at the beginning of a scanner action, rather than
[external/ragel.git] / redfsm / gendata.cpp
1 /*
2  *  Copyright 2005-2007 Adrian Thurston <thurston@cs.queensu.ca>
3  */
4
5 /*  This file is part of Ragel.
6  *
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.
11  * 
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.
16  * 
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 
20  */
21
22 #include "gendata.h"
23 #include <iostream>
24
25 using std::cerr;
26 using std::endl;
27
28 /* Total error count. */
29 int gblErrorCount = 0;
30
31 CodeGenData::CodeGenData( ostream &out )
32 :
33         sourceFileName(0),
34         fsmName(0), 
35         out(out),
36         redFsm(0), 
37         allActions(0),
38         allActionTables(0),
39         allConditions(0),
40         allCondSpaces(0),
41         allStates(0),
42         nameIndex(0),
43         startState(-1),
44         errState(-1),
45         getKeyExpr(0),
46         accessExpr(0),
47         pExpr(0),
48         peExpr(0),
49         csExpr(0),
50         topExpr(0),
51         stackExpr(0),
52         actExpr(0),
53         tokstartExpr(0),
54         tokendExpr(0),
55         wantComplete(0),
56         hasLongestMatch(false),
57         hasEnd(true),
58         dataPrefix(true),
59         writeFirstFinal(true),
60         writeErr(true),
61         writeCS(true)
62 {}
63
64
65 void CodeGenData::createMachine()
66 {
67         redFsm = new RedFsmAp();
68 }
69
70 void CodeGenData::initActionList( unsigned long length )
71
72         allActions = new Action[length];
73         for ( unsigned long a = 0; a < length; a++ )
74                 actionList.append( allActions+a );
75 }
76
77 void CodeGenData::newAction( int anum, char *name, int line, 
78                 int col, InlineList *inlineList )
79 {
80         allActions[anum].actionId = anum;
81         allActions[anum].name = name;
82         allActions[anum].loc.line = line;
83         allActions[anum].loc.col = col;
84         allActions[anum].inlineList = inlineList;
85 }
86
87 void CodeGenData::initActionTableList( unsigned long length )
88
89         allActionTables = new RedAction[length];
90 }
91
92 void CodeGenData::initStateList( unsigned long length )
93 {
94         allStates = new RedStateAp[length];
95         for ( unsigned long s = 0; s < length; s++ )
96                 redFsm->stateList.append( allStates+s );
97
98         /* We get the start state as an offset, set the pointer now. */
99         if ( startState >= 0 )
100                 redFsm->startState = allStates + startState;
101         if ( errState >= 0 )
102                 redFsm->errState = allStates + errState;
103         for ( EntryIdVect::Iter en = entryPointIds; en.lte(); en++ )
104                 redFsm->entryPoints.insert( allStates + *en );
105
106         /* The nextStateId is no longer used to assign state ids (they come in set
107          * from the frontend now), however generation code still depends on it.
108          * Should eventually remove this variable. */
109         redFsm->nextStateId = redFsm->stateList.length();
110 }
111
112 void CodeGenData::setStartState( unsigned long startState )
113 {
114         this->startState = startState;
115 }
116
117 void CodeGenData::setErrorState( unsigned long errState )
118 {
119         this->errState = errState;
120 }
121
122 void CodeGenData::addEntryPoint( char *name, unsigned long entryState )
123 {
124         entryPointIds.append( entryState );
125         entryPointNames.append( name );
126 }
127
128 void CodeGenData::initTransList( int snum, unsigned long length )
129 {
130         /* Could preallocate the out range to save time growing it. For now do
131          * nothing. */
132 }
133
134 void CodeGenData::newTrans( int snum, int tnum, Key lowKey, 
135                 Key highKey, long targ, long action )
136 {
137         /* Get the current state and range. */
138         RedStateAp *curState = allStates + snum;
139         RedTransList &destRange = curState->outRange;
140
141         if ( curState == redFsm->errState )
142                 return;
143
144         /* Make the new transitions. */
145         RedStateAp *targState = targ >= 0 ? (allStates + targ) : 
146                         wantComplete ? redFsm->getErrorState() : 0;
147         RedAction *actionTable = action >= 0 ? (allActionTables + action) : 0;
148         RedTransAp *trans = redFsm->allocateTrans( targState, actionTable );
149         RedTransEl transEl( lowKey, highKey, trans );
150
151         if ( wantComplete ) {
152                 /* If the machine is to be complete then we need to fill any gaps with
153                  * the error transitions. */
154                 if ( destRange.length() == 0 ) {
155                         /* Range is currently empty. */
156                         if ( keyOps->minKey < lowKey ) {
157                                 /* The first range doesn't start at the low end. */
158                                 Key fillHighKey = lowKey;
159                                 fillHighKey.decrement();
160
161                                 /* Create the filler with the state's error transition. */
162                                 RedTransEl newTel( keyOps->minKey, fillHighKey, redFsm->getErrorTrans() );
163                                 destRange.append( newTel );
164                         }
165                 }
166                 else {
167                         /* The range list is not empty, get the the last range. */
168                         RedTransEl *last = &destRange[destRange.length()-1];
169                         Key nextKey = last->highKey;
170                         nextKey.increment();
171                         if ( nextKey < lowKey ) {
172                                 /* There is a gap to fill. Make the high key. */
173                                 Key fillHighKey = lowKey;
174                                 fillHighKey.decrement();
175
176                                 /* Create the filler with the state's error transtion. */
177                                 RedTransEl newTel( nextKey, fillHighKey, redFsm->getErrorTrans() );
178                                 destRange.append( newTel );
179                         }
180                 }
181         }
182
183         /* Filler taken care of. Append the range. */
184         destRange.append( RedTransEl( lowKey, highKey, trans ) );
185 }
186
187 void CodeGenData::finishTransList( int snum )
188 {
189         /* Get the current state and range. */
190         RedStateAp *curState = allStates + snum;
191         RedTransList &destRange = curState->outRange;
192
193         if ( curState == redFsm->errState )
194                 return;
195
196         /* If building a complete machine we may need filler on the end. */
197         if ( wantComplete ) {
198                 /* Check if there are any ranges already. */
199                 if ( destRange.length() == 0 ) {
200                         /* Fill with the whole alphabet. */
201                         /* Add the range on the lower and upper bound. */
202                         RedTransEl newTel( keyOps->minKey, keyOps->maxKey, redFsm->getErrorTrans() );
203                         destRange.append( newTel );
204                 }
205                 else {
206                         /* Get the last and check for a gap on the end. */
207                         RedTransEl *last = &destRange[destRange.length()-1];
208                         if ( last->highKey < keyOps->maxKey ) {
209                                 /* Make the high key. */
210                                 Key fillLowKey = last->highKey;
211                                 fillLowKey.increment();
212
213                                 /* Create the new range with the error trans and append it. */
214                                 RedTransEl newTel( fillLowKey, keyOps->maxKey, redFsm->getErrorTrans() );
215                                 destRange.append( newTel );
216                         }
217                 }
218         }
219 }
220
221 void CodeGenData::setId( int snum, int id )
222 {
223         RedStateAp *curState = allStates + snum;
224         curState->id = id;
225 }
226
227 void CodeGenData::setFinal( int snum )
228 {
229         RedStateAp *curState = allStates + snum;
230         curState->isFinal = true;
231 }
232
233
234 void CodeGenData::setStateActions( int snum, long toStateAction, 
235                         long fromStateAction, long eofAction )
236 {
237         RedStateAp *curState = allStates + snum;
238         if ( toStateAction >= 0 )
239                 curState->toStateAction = allActionTables + toStateAction;
240         if ( fromStateAction >= 0 )
241                 curState->fromStateAction = allActionTables + fromStateAction;
242         if ( eofAction >= 0 )
243                 curState->eofAction = allActionTables + eofAction;
244 }
245
246 void CodeGenData::resolveTargetStates( InlineList *inlineList )
247 {
248         for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
249                 switch ( item->type ) {
250                 case InlineItem::Goto: case InlineItem::Call:
251                 case InlineItem::Next: case InlineItem::Entry:
252                         item->targState = allStates + item->targId;
253                         break;
254                 default:
255                         break;
256                 }
257
258                 if ( item->children != 0 )
259                         resolveTargetStates( item->children );
260         }
261 }
262
263 void CodeGenData::closeMachine()
264 {
265         for ( ActionList::Iter a = actionList; a.lte(); a++ )
266                 resolveTargetStates( a->inlineList );
267
268         /* Note that even if we want a complete graph we do not give the error
269          * state a default transition. All machines break out of the processing
270          * loop when in the error state. */
271
272         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
273                 for ( StateCondList::Iter sci = st->stateCondList; sci.lte(); sci++ )
274                         st->stateCondVect.append( sci );
275         }
276 }
277
278
279 bool CodeGenData::setAlphType( char *data )
280 {
281         HostType *alphType = findAlphTypeInternal( data );
282         if ( alphType == 0 )
283                 return false;
284
285         thisKeyOps.setAlphType( alphType );
286         return true;
287 }
288
289 void CodeGenData::initCondSpaceList( ulong length )
290 {
291         allCondSpaces = new CondSpace[length];
292         for ( ulong c = 0; c < length; c++ )
293                 condSpaceList.append( allCondSpaces + c );
294 }
295
296 void CodeGenData::newCondSpace( int cnum, int condSpaceId, Key baseKey )
297 {
298         CondSpace *cond = allCondSpaces + cnum;
299         cond->condSpaceId = condSpaceId;
300         cond->baseKey = baseKey;
301 }
302
303 void CodeGenData::condSpaceItem( int cnum, long condActionId )
304 {
305         CondSpace *cond = allCondSpaces + cnum;
306         cond->condSet.append( allActions + condActionId );
307 }
308
309 void CodeGenData::initStateCondList( int snum, ulong length )
310 {
311         /* Could preallocate these, as we could with transitions. */
312 }
313
314 void CodeGenData::addStateCond( int snum, Key lowKey, Key highKey, long condNum )
315 {
316         RedStateAp *curState = allStates + snum;
317
318         /* Create the new state condition. */
319         StateCond *stateCond = new StateCond;
320         stateCond->lowKey = lowKey;
321         stateCond->highKey = highKey;
322
323         /* Assign it a cond space. */
324         CondSpace *condSpace = allCondSpaces + condNum;
325         stateCond->condSpace = condSpace;
326
327         curState->stateCondList.append( stateCond );
328 }
329
330
331 CondSpace *CodeGenData::findCondSpace( Key lowKey, Key highKey )
332 {
333         for ( CondSpaceList::Iter cs = condSpaceList; cs.lte(); cs++ ) {
334                 Key csHighKey = cs->baseKey;
335                 csHighKey += keyOps->alphSize() * (1 << cs->condSet.length());
336
337                 if ( lowKey >= cs->baseKey && highKey <= csHighKey )
338                         return cs;
339         }
340         return 0;
341 }
342
343 Condition *CodeGenData::findCondition( Key key )
344 {
345         for ( ConditionList::Iter cond = conditionList; cond.lte(); cond++ ) {
346                 Key upperKey = cond->baseKey + (1 << cond->condSet.length());
347                 if ( cond->baseKey <= key && key <= upperKey )
348                         return cond;
349         }
350         return 0;
351 }
352
353 Key CodeGenData::findMaxKey()
354 {
355         Key maxKey = keyOps->maxKey;
356         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
357                 assert( st->outSingle.length() == 0 );
358                 assert( st->defTrans == 0 );
359
360                 long rangeLen = st->outRange.length();
361                 if ( rangeLen > 0 ) {
362                         Key highKey = st->outRange[rangeLen-1].highKey;
363                         if ( highKey > maxKey )
364                                 maxKey = highKey;
365                 }
366         }
367         return maxKey;
368 }
369
370 void CodeGenData::findFinalActionRefs()
371 {
372         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
373                 /* Rerence count out of single transitions. */
374                 for ( RedTransList::Iter rtel = st->outSingle; rtel.lte(); rtel++ ) {
375                         if ( rtel->value->action != 0 ) {
376                                 rtel->value->action->numTransRefs += 1;
377                                 for ( ActionTable::Iter item = rtel->value->action->key; item.lte(); item++ )
378                                         item->value->numTransRefs += 1;
379                         }
380                 }
381
382                 /* Reference count out of range transitions. */
383                 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
384                         if ( rtel->value->action != 0 ) {
385                                 rtel->value->action->numTransRefs += 1;
386                                 for ( ActionTable::Iter item = rtel->value->action->key; item.lte(); item++ )
387                                         item->value->numTransRefs += 1;
388                         }
389                 }
390
391                 /* Reference count default transition. */
392                 if ( st->defTrans != 0 && st->defTrans->action != 0 ) {
393                         st->defTrans->action->numTransRefs += 1;
394                         for ( ActionTable::Iter item = st->defTrans->action->key; item.lte(); item++ )
395                                 item->value->numTransRefs += 1;
396                 }
397
398                 /* Reference count to state actions. */
399                 if ( st->toStateAction != 0 ) {
400                         st->toStateAction->numToStateRefs += 1;
401                         for ( ActionTable::Iter item = st->toStateAction->key; item.lte(); item++ )
402                                 item->value->numToStateRefs += 1;
403                 }
404
405                 /* Reference count from state actions. */
406                 if ( st->fromStateAction != 0 ) {
407                         st->fromStateAction->numFromStateRefs += 1;
408                         for ( ActionTable::Iter item = st->fromStateAction->key; item.lte(); item++ )
409                                 item->value->numFromStateRefs += 1;
410                 }
411
412                 /* Reference count EOF actions. */
413                 if ( st->eofAction != 0 ) {
414                         st->eofAction->numEofRefs += 1;
415                         for ( ActionTable::Iter item = st->eofAction->key; item.lte(); item++ )
416                                 item->value->numEofRefs += 1;
417                 }
418         }
419 }
420
421 void CodeGenData::analyzeAction( Action *act, InlineList *inlineList )
422 {
423         for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
424                 /* Only consider actions that are referenced. */
425                 if ( act->numRefs() > 0 ) {
426                         if ( item->type == InlineItem::Goto || item->type == InlineItem::GotoExpr )
427                                 redFsm->bAnyActionGotos = true;
428                         else if ( item->type == InlineItem::Call || item->type == InlineItem::CallExpr )
429                                 redFsm->bAnyActionCalls = true;
430                         else if ( item->type == InlineItem::Ret )
431                                 redFsm->bAnyActionRets = true;
432                 }
433
434                 /* Check for various things in regular actions. */
435                 if ( act->numTransRefs > 0 || act->numToStateRefs > 0 || act->numFromStateRefs > 0 ) {
436                         /* Any returns in regular actions? */
437                         if ( item->type == InlineItem::Ret )
438                                 redFsm->bAnyRegActionRets = true;
439
440                         /* Any next statements in the regular actions? */
441                         if ( item->type == InlineItem::Next || item->type == InlineItem::NextExpr )
442                                 redFsm->bAnyRegNextStmt = true;
443
444                         /* Any by value control in regular actions? */
445                         if ( item->type == InlineItem::CallExpr || item->type == InlineItem::GotoExpr )
446                                 redFsm->bAnyRegActionByValControl = true;
447
448                         /* Any references to the current state in regular actions? */
449                         if ( item->type == InlineItem::Curs )
450                                 redFsm->bAnyRegCurStateRef = true;
451
452                         if ( item->type == InlineItem::Break )
453                                 redFsm->bAnyRegBreak = true;
454                 }
455
456                 if ( item->children != 0 )
457                         analyzeAction( act, item->children );
458         }
459 }
460
461 void CodeGenData::analyzeActionList( RedAction *redAct, InlineList *inlineList )
462 {
463         for ( InlineList::Iter item = *inlineList; item.lte(); item++ ) {
464                 /* Any next statements in the action table? */
465                 if ( item->type == InlineItem::Next || item->type == InlineItem::NextExpr )
466                         redAct->bAnyNextStmt = true;
467
468                 /* Any references to the current state. */
469                 if ( item->type == InlineItem::Curs )
470                         redAct->bAnyCurStateRef = true;
471
472                 if ( item->type == InlineItem::Break )
473                         redAct->bAnyBreakStmt = true;
474
475                 if ( item->children != 0 )
476                         analyzeActionList( redAct, item->children );
477         }
478 }
479
480 /* Assign ids to referenced actions. */
481 void CodeGenData::assignActionIds()
482 {
483         int nextActionId = 0;
484         for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
485                 /* Only ever interested in referenced actions. */
486                 if ( act->numRefs() > 0 )
487                         act->actionId = nextActionId++;
488         }
489 }
490
491 void CodeGenData::setValueLimits()
492 {
493         redFsm->maxSingleLen = 0;
494         redFsm->maxRangeLen = 0;
495         redFsm->maxKeyOffset = 0;
496         redFsm->maxIndexOffset = 0;
497         redFsm->maxActListId = 0;
498         redFsm->maxActionLoc = 0;
499         redFsm->maxActArrItem = 0;
500         redFsm->maxSpan = 0;
501         redFsm->maxCondSpan = 0;
502         redFsm->maxFlatIndexOffset = 0;
503         redFsm->maxCondOffset = 0;
504         redFsm->maxCondLen = 0;
505         redFsm->maxCondSpaceId = 0;
506         redFsm->maxCondIndexOffset = 0;
507
508         /* In both of these cases the 0 index is reserved for no value, so the max
509          * is one more than it would be if they started at 0. */
510         redFsm->maxIndex = redFsm->transSet.length();
511         redFsm->maxCond = condSpaceList.length(); 
512
513         /* The nextStateId - 1 is the last state id assigned. */
514         redFsm->maxState = redFsm->nextStateId - 1;
515
516         for ( CondSpaceList::Iter csi = condSpaceList; csi.lte(); csi++ ) {
517                 if ( csi->condSpaceId > redFsm->maxCondSpaceId )
518                         redFsm->maxCondSpaceId = csi->condSpaceId;
519         }
520
521         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
522                 /* Maximum cond length. */
523                 if ( st->stateCondList.length() > redFsm->maxCondLen )
524                         redFsm->maxCondLen = st->stateCondList.length();
525
526                 /* Maximum single length. */
527                 if ( st->outSingle.length() > redFsm->maxSingleLen )
528                         redFsm->maxSingleLen = st->outSingle.length();
529
530                 /* Maximum range length. */
531                 if ( st->outRange.length() > redFsm->maxRangeLen )
532                         redFsm->maxRangeLen = st->outRange.length();
533
534                 /* The key offset index offset for the state after last is not used, skip it.. */
535                 if ( ! st.last() ) {
536                         redFsm->maxCondOffset += st->stateCondList.length();
537                         redFsm->maxKeyOffset += st->outSingle.length() + st->outRange.length()*2;
538                         redFsm->maxIndexOffset += st->outSingle.length() + st->outRange.length() + 1;
539                 }
540
541                 /* Max cond span. */
542                 if ( st->condList != 0 ) {
543                         unsigned long long span = keyOps->span( st->condLowKey, st->condHighKey );
544                         if ( span > redFsm->maxCondSpan )
545                                 redFsm->maxCondSpan = span;
546                 }
547
548                 /* Max key span. */
549                 if ( st->transList != 0 ) {
550                         unsigned long long span = keyOps->span( st->lowKey, st->highKey );
551                         if ( span > redFsm->maxSpan )
552                                 redFsm->maxSpan = span;
553                 }
554
555                 /* Max cond index offset. */
556                 if ( ! st.last() ) {
557                         if ( st->condList != 0 )
558                                 redFsm->maxCondIndexOffset += keyOps->span( st->condLowKey, st->condHighKey );
559                 }
560
561                 /* Max flat index offset. */
562                 if ( ! st.last() ) {
563                         if ( st->transList != 0 )
564                                 redFsm->maxFlatIndexOffset += keyOps->span( st->lowKey, st->highKey );
565                         redFsm->maxFlatIndexOffset += 1;
566                 }
567         }
568
569         for ( ActionTableMap::Iter at = redFsm->actionMap; at.lte(); at++ ) {
570                 /* Maximum id of action lists. */
571                 if ( at->actListId+1 > redFsm->maxActListId )
572                         redFsm->maxActListId = at->actListId+1;
573
574                 /* Maximum location of items in action array. */
575                 if ( at->location+1 > redFsm->maxActionLoc )
576                         redFsm->maxActionLoc = at->location+1;
577
578                 /* Maximum values going into the action array. */
579                 if ( at->key.length() > redFsm->maxActArrItem )
580                         redFsm->maxActArrItem = at->key.length();
581                 for ( ActionTable::Iter item = at->key; item.lte(); item++ ) {
582                         if ( item->value->actionId > redFsm->maxActArrItem )
583                                 redFsm->maxActArrItem = item->value->actionId;
584                 }
585         }
586 }
587
588
589
590 /* Gather various info on the machine. */
591 void CodeGenData::analyzeMachine()
592 {
593         /* Find the true count of action references.  */
594         findFinalActionRefs();
595
596         /* Check if there are any calls in action code. */
597         for ( ActionList::Iter act = actionList; act.lte(); act++ ) {
598                 /* Record the occurrence of various kinds of actions. */
599                 if ( act->numToStateRefs > 0 )
600                         redFsm->bAnyToStateActions = true;
601                 if ( act->numFromStateRefs > 0 )
602                         redFsm->bAnyFromStateActions = true;
603                 if ( act->numEofRefs > 0 )
604                         redFsm->bAnyEofActions = true;
605                 if ( act->numTransRefs > 0 )
606                         redFsm->bAnyRegActions = true;
607
608                 /* Recurse through the action's parse tree looking for various things. */
609                 analyzeAction( act, act->inlineList );
610         }
611
612         /* Analyze reduced action lists. */
613         for ( ActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
614                 for ( ActionTable::Iter act = redAct->key; act.lte(); act++ )
615                         analyzeActionList( redAct, act->value->inlineList );
616         }
617
618         /* Find states that have transitions with actions that have next
619          * statements. */
620         for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
621                 /* Check any actions out of outSinge. */
622                 for ( RedTransList::Iter rtel = st->outSingle; rtel.lte(); rtel++ ) {
623                         if ( rtel->value->action != 0 && rtel->value->action->anyCurStateRef() )
624                                 st->bAnyRegCurStateRef = true;
625                 }
626
627                 /* Check any actions out of outRange. */
628                 for ( RedTransList::Iter rtel = st->outRange; rtel.lte(); rtel++ ) {
629                         if ( rtel->value->action != 0 && rtel->value->action->anyCurStateRef() )
630                                 st->bAnyRegCurStateRef = true;
631                 }
632
633                 /* Check any action out of default. */
634                 if ( st->defTrans != 0 && st->defTrans->action != 0 && 
635                                 st->defTrans->action->anyCurStateRef() )
636                         st->bAnyRegCurStateRef = true;
637                 
638                 if ( st->stateCondList.length() > 0 )
639                         redFsm->bAnyConditions = true;
640         }
641
642         /* Assign ids to actions that are referenced. */
643         assignActionIds();
644
645         /* Set the maximums of various values used for deciding types. */
646         setValueLimits();
647 }
648
649 void CodeGenData::writeStatement( InputLoc &loc, int nargs, char **args )
650 {
651         /* FIXME: This should be moved to the virtual functions in the code
652          * generators.
653          *
654          * Force a newline. */
655         out << "\n";
656         genLineDirective( out );
657
658         if ( strcmp( args[0], "data" ) == 0 ) {
659                 for ( int i = 1; i < nargs; i++ ) {
660                         if ( strcmp( args[i], "noerror" ) == 0 )
661                                 writeErr = false;
662                         else if ( strcmp( args[i], "noprefix" ) == 0 )
663                                 dataPrefix = false;
664                         else if ( strcmp( args[i], "nofinal" ) == 0 )
665                                 writeFirstFinal = false;
666                         else {
667                                 source_warning(loc) << "unrecognized write option \"" << 
668                                                 args[i] << "\"" << endl;
669                         }
670                 }
671                 writeData();
672         }
673         else if ( strcmp( args[0], "init" ) == 0 ) {
674                 for ( int i = 1; i < nargs; i++ ) {
675                         if ( strcmp( args[i], "nocs" ) == 0 )
676                                 writeCS = false;
677                         else {
678                                 source_warning(loc) << "unrecognized write option \"" << 
679                                                 args[i] << "\"" << endl;
680                         }
681                 }
682                 writeInit();
683         }
684         else if ( strcmp( args[0], "exec" ) == 0 ) {
685                 for ( int i = 1; i < nargs; i++ ) {
686                         if ( strcmp( args[i], "noend" ) == 0 )
687                                 hasEnd = false;
688                         else {
689                                 source_warning(loc) << "unrecognized write option \"" << 
690                                                 args[i] << "\"" << endl;
691                         }
692                 }
693                 writeExec();
694         }
695         else if ( strcmp( args[0], "eof" ) == 0 ) {
696                 for ( int i = 1; i < nargs; i++ ) {
697                         source_warning(loc) << "unrecognized write option \"" << 
698                                         args[i] << "\"" << endl;
699                 }
700                 writeEOF();
701         }
702         else if ( strcmp( args[0], "exports" ) == 0 ) {
703                 for ( int i = 1; i < nargs; i++ ) {
704                         source_warning(loc) << "unrecognized write option \"" << 
705                                         args[i] << "\"" << endl;
706                 }
707                 writeExports();
708         }
709         else {
710                 /* EMIT An error here. */
711                 source_error(loc) << "unrecognized write command \"" << 
712                                 args[0] << "\"" << endl;
713         }
714 }
715
716 ostream &CodeGenData::source_warning( const InputLoc &loc )
717 {
718         cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": warning: ";
719         return cerr;
720 }
721
722 ostream &CodeGenData::source_error( const InputLoc &loc )
723 {
724         gblErrorCount += 1;
725         assert( sourceFileName != 0 );
726         cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": ";
727         return cerr;
728 }
729
730