1 /*
2  *  Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
3  *            2004 Erich Ocean <eric.ocean@ampede.com>
4  *            2005 Alan West <alan@alanz.com>
5  */
6 
7 /*  This file is part of Ragel.
8  *
9  *  Ragel is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2 of the License, or
12  *  (at your option) any later version.
13  *
14  *  Ragel is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with Ragel; if not, write to the Free Software
21  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23 
24 #include "cdcodegen.h"
25 #include "ragel.h"
26 #include "redfsm.h"
27 #include "gendata.h"
28 #include <sstream>
29 #include <string>
30 #include <assert.h>
31 
32 
33 using std::ostream;
34 using std::ostringstream;
35 using std::string;
36 using std::cerr;
37 using std::endl;
38 using std::istream;
39 using std::ifstream;
40 using std::ostream;
41 using std::ios;
42 using std::cin;
43 using std::cout;
44 using std::cerr;
45 using std::endl;
46 
47 
48 extern int numSplitPartitions;
49 extern bool noLineDirectives;
50 
cdLineDirective(ostream & out,const char * fileName,int line)51 void cdLineDirective( ostream &out, const char *fileName, int line )
52 {
53 	if ( noLineDirectives )
54 		out << "/* ";
55 
56 	/* Write the preprocessor line info for to the input file. */
57 	out << "#line " << line  << " \"";
58 	for ( const char *pc = fileName; *pc != 0; pc++ ) {
59 		if ( *pc == '\\' )
60 			out << "\\\\";
61 		else
62 			out << *pc;
63 	}
64 	out << '"';
65 
66 	if ( noLineDirectives )
67 		out << " */";
68 
69 	out << '\n';
70 }
71 
genLineDirective(ostream & out)72 void FsmCodeGen::genLineDirective( ostream &out )
73 {
74 	std::streambuf *sbuf = out.rdbuf();
75 	output_filter *filter = static_cast<output_filter*>(sbuf);
76 	cdLineDirective( out, filter->fileName, filter->line + 1 );
77 }
78 
79 
80 /* Init code gen with in parameters. */
FsmCodeGen(ostream & out)81 FsmCodeGen::FsmCodeGen( ostream &out )
82 :
83 	CodeGenData(out)
84 {
85 }
86 
arrayTypeSize(unsigned long maxVal)87 unsigned int FsmCodeGen::arrayTypeSize( unsigned long maxVal )
88 {
89 	long long maxValLL = (long long) maxVal;
90 	HostType *arrayType = keyOps->typeSubsumes( maxValLL );
91 	assert( arrayType != 0 );
92 	return arrayType->size;
93 }
94 
ARRAY_TYPE(unsigned long maxVal)95 string FsmCodeGen::ARRAY_TYPE( unsigned long maxVal )
96 {
97 	long long maxValLL = (long long) maxVal;
98 	HostType *arrayType = keyOps->typeSubsumes( maxValLL );
99 	assert( arrayType != 0 );
100 
101 	string ret = arrayType->data1;
102 	if ( arrayType->data2 != 0 ) {
103 		ret += " ";
104 		ret += arrayType->data2;
105 	}
106 	return ret;
107 }
108 
109 
110 /* Write out the fsm name. */
FSM_NAME()111 string FsmCodeGen::FSM_NAME()
112 {
113 	return fsmName;
114 }
115 
116 /* Emit the offset of the start state as a decimal integer. */
START_STATE_ID()117 string FsmCodeGen::START_STATE_ID()
118 {
119 	ostringstream ret;
120 	ret << redFsm->startState->id;
121 	return ret.str();
122 };
123 
124 /* Write out the array of actions. */
ACTIONS_ARRAY()125 std::ostream &FsmCodeGen::ACTIONS_ARRAY()
126 {
127 	out << "\t0, ";
128 	int totalActions = 1;
129 	for ( GenActionTableMap::Iter act = redFsm->actionMap; act.lte(); act++ ) {
130 		/* Write out the length, which will never be the last character. */
131 		out << act->key.length() << ", ";
132 		/* Put in a line break every 8 */
133 		if ( totalActions++ % 8 == 7 )
134 			out << "\n\t";
135 
136 		for ( GenActionTable::Iter item = act->key; item.lte(); item++ ) {
137 			out << item->value->actionId;
138 			if ( ! (act.last() && item.last()) )
139 				out << ", ";
140 
141 			/* Put in a line break every 8 */
142 			if ( totalActions++ % 8 == 7 )
143 				out << "\n\t";
144 		}
145 	}
146 	out << "\n";
147 	return out;
148 }
149 
150 
ACCESS()151 string FsmCodeGen::ACCESS()
152 {
153 	ostringstream ret;
154 	if ( accessExpr != 0 )
155 		INLINE_LIST( ret, accessExpr, 0, false, false );
156 	return ret.str();
157 }
158 
159 
P()160 string FsmCodeGen::P()
161 {
162 	ostringstream ret;
163 	if ( pExpr == 0 )
164 		ret << "p";
165 	else {
166 		ret << "(";
167 		INLINE_LIST( ret, pExpr, 0, false, false );
168 		ret << ")";
169 	}
170 	return ret.str();
171 }
172 
PE()173 string FsmCodeGen::PE()
174 {
175 	ostringstream ret;
176 	if ( peExpr == 0 )
177 		ret << "pe";
178 	else {
179 		ret << "(";
180 		INLINE_LIST( ret, peExpr, 0, false, false );
181 		ret << ")";
182 	}
183 	return ret.str();
184 }
185 
vEOF()186 string FsmCodeGen::vEOF()
187 {
188 	ostringstream ret;
189 	if ( eofExpr == 0 )
190 		ret << "eof";
191 	else {
192 		ret << "(";
193 		INLINE_LIST( ret, eofExpr, 0, false, false );
194 		ret << ")";
195 	}
196 	return ret.str();
197 }
198 
vCS()199 string FsmCodeGen::vCS()
200 {
201 	ostringstream ret;
202 	if ( csExpr == 0 )
203 		ret << ACCESS() << "cs";
204 	else {
205 		/* Emit the user supplied method of retrieving the key. */
206 		ret << "(";
207 		INLINE_LIST( ret, csExpr, 0, false, false );
208 		ret << ")";
209 	}
210 	return ret.str();
211 }
212 
TOP()213 string FsmCodeGen::TOP()
214 {
215 	ostringstream ret;
216 	if ( topExpr == 0 )
217 		ret << ACCESS() + "top";
218 	else {
219 		ret << "(";
220 		INLINE_LIST( ret, topExpr, 0, false, false );
221 		ret << ")";
222 	}
223 	return ret.str();
224 }
225 
STACK()226 string FsmCodeGen::STACK()
227 {
228 	ostringstream ret;
229 	if ( stackExpr == 0 )
230 		ret << ACCESS() + "stack";
231 	else {
232 		ret << "(";
233 		INLINE_LIST( ret, stackExpr, 0, false, false );
234 		ret << ")";
235 	}
236 	return ret.str();
237 }
238 
ACT()239 string FsmCodeGen::ACT()
240 {
241 	ostringstream ret;
242 	if ( actExpr == 0 )
243 		ret << ACCESS() + "act";
244 	else {
245 		ret << "(";
246 		INLINE_LIST( ret, actExpr, 0, false, false );
247 		ret << ")";
248 	}
249 	return ret.str();
250 }
251 
TOKSTART()252 string FsmCodeGen::TOKSTART()
253 {
254 	ostringstream ret;
255 	if ( tokstartExpr == 0 )
256 		ret << ACCESS() + "ts";
257 	else {
258 		ret << "(";
259 		INLINE_LIST( ret, tokstartExpr, 0, false, false );
260 		ret << ")";
261 	}
262 	return ret.str();
263 }
264 
TOKEND()265 string FsmCodeGen::TOKEND()
266 {
267 	ostringstream ret;
268 	if ( tokendExpr == 0 )
269 		ret << ACCESS() + "te";
270 	else {
271 		ret << "(";
272 		INLINE_LIST( ret, tokendExpr, 0, false, false );
273 		ret << ")";
274 	}
275 	return ret.str();
276 }
277 
GET_WIDE_KEY()278 string FsmCodeGen::GET_WIDE_KEY()
279 {
280 	if ( redFsm->anyConditions() )
281 		return "_widec";
282 	else
283 		return GET_KEY();
284 }
285 
GET_WIDE_KEY(RedStateAp * state)286 string FsmCodeGen::GET_WIDE_KEY( RedStateAp *state )
287 {
288 	if ( state->stateCondList.length() > 0 )
289 		return "_widec";
290 	else
291 		return GET_KEY();
292 }
293 
GET_KEY()294 string FsmCodeGen::GET_KEY()
295 {
296 	ostringstream ret;
297 	if ( getKeyExpr != 0 ) {
298 		/* Emit the user supplied method of retrieving the key. */
299 		ret << "(";
300 		INLINE_LIST( ret, getKeyExpr, 0, false, false );
301 		ret << ")";
302 	}
303 	else {
304 		/* Expression for retrieving the key, use simple dereference. */
305 		ret << "(*" << P() << ")";
306 	}
307 	return ret.str();
308 }
309 
310 /* Write out level number of tabs. Makes the nested binary search nice
311  * looking. */
TABS(int level)312 string FsmCodeGen::TABS( int level )
313 {
314 	string result;
315 	while ( level-- > 0 )
316 		result += "\t";
317 	return result;
318 }
319 
320 /* Write out a key from the fsm code gen. Depends on wether or not the key is
321  * signed. */
KEY(Key key)322 string FsmCodeGen::KEY( Key key )
323 {
324 	ostringstream ret;
325 	if ( keyOps->isSigned || !hostLang->explicitUnsigned )
326 		ret << key.getVal();
327 	else
328 		ret << (unsigned long) key.getVal() << 'u';
329 	return ret.str();
330 }
331 
isAlphTypeSigned()332 bool FsmCodeGen::isAlphTypeSigned()
333 {
334 	return keyOps->isSigned;
335 }
336 
isWideAlphTypeSigned()337 bool FsmCodeGen::isWideAlphTypeSigned()
338 {
339 	string ret;
340 	if ( redFsm->maxKey <= keyOps->maxKey )
341 		return isAlphTypeSigned();
342 	else {
343 		long long maxKeyVal = redFsm->maxKey.getLongLong();
344 		HostType *wideType = keyOps->typeSubsumes( keyOps->isSigned, maxKeyVal );
345 		return wideType->isSigned;
346 	}
347 }
348 
WIDE_KEY(RedStateAp * state,Key key)349 string FsmCodeGen::WIDE_KEY( RedStateAp *state, Key key )
350 {
351 	if ( state->stateCondList.length() > 0 ) {
352 		ostringstream ret;
353 		if ( isWideAlphTypeSigned() )
354 			ret << key.getVal();
355 		else
356 			ret << (unsigned long) key.getVal() << 'u';
357 		return ret.str();
358 	}
359 	else {
360 		return KEY( key );
361 	}
362 }
363 
EOF_CHECK(ostream & ret)364 void FsmCodeGen::EOF_CHECK( ostream &ret )
365 {
366 	ret <<
367 		"	if ( " << P() << " == " << PE() << " )\n"
368 		"		goto _test_eof;\n";
369 
370 	testEofUsed = true;
371 }
372 
373 
EXEC(ostream & ret,GenInlineItem * item,int targState,int inFinish)374 void FsmCodeGen::EXEC( ostream &ret, GenInlineItem *item, int targState, int inFinish )
375 {
376 	/* The parser gives fexec two children. The double brackets are for D
377 	 * code. If the inline list is a single word it will get interpreted as a
378 	 * C-style cast by the D compiler. */
379 	ret << "{" << P() << " = ((";
380 	INLINE_LIST( ret, item->children, targState, inFinish, false );
381 	ret << "))-1;}";
382 }
383 
LM_SWITCH(ostream & ret,GenInlineItem * item,int targState,int inFinish,bool csForced)384 void FsmCodeGen::LM_SWITCH( ostream &ret, GenInlineItem *item,
385 		int targState, int inFinish, bool csForced )
386 {
387 	ret <<
388 		"	switch( " << ACT() << " ) {\n";
389 
390 	bool haveDefault = false;
391 	for ( GenInlineList::Iter lma = *item->children; lma.lte(); lma++ ) {
392 		/* Write the case label, the action and the case break. */
393 		if ( lma->lmId < 0 ) {
394 			ret << "	default:\n";
395 			haveDefault = true;
396 		}
397 		else
398 			ret << "	case " << lma->lmId << ":\n";
399 
400 		/* Write the block and close it off. */
401 		ret << "	{";
402 		INLINE_LIST( ret, lma->children, targState, inFinish, csForced );
403 		ret << "}\n";
404 
405 		ret << "	break;\n";
406 	}
407 
408 	if ( (hostLang->lang == HostLang::D || hostLang->lang == HostLang::D2) && !haveDefault )
409 		ret << "	default: break;";
410 
411 	ret <<
412 		"	}\n"
413 		"\t";
414 }
415 
SET_ACT(ostream & ret,GenInlineItem * item)416 void FsmCodeGen::SET_ACT( ostream &ret, GenInlineItem *item )
417 {
418 	ret << ACT() << " = " << item->lmId << ";";
419 }
420 
SET_TOKEND(ostream & ret,GenInlineItem * item)421 void FsmCodeGen::SET_TOKEND( ostream &ret, GenInlineItem *item )
422 {
423 	/* The tokend action sets tokend. */
424 	ret << TOKEND() << " = " << P();
425 	if ( item->offset != 0 )
426 		out << "+" << item->offset;
427 	out << ";";
428 }
429 
GET_TOKEND(ostream & ret,GenInlineItem * item)430 void FsmCodeGen::GET_TOKEND( ostream &ret, GenInlineItem *item )
431 {
432 	ret << TOKEND();
433 }
434 
INIT_TOKSTART(ostream & ret,GenInlineItem * item)435 void FsmCodeGen::INIT_TOKSTART( ostream &ret, GenInlineItem *item )
436 {
437 	ret << TOKSTART() << " = " << NULL_ITEM() << ";";
438 }
439 
INIT_ACT(ostream & ret,GenInlineItem * item)440 void FsmCodeGen::INIT_ACT( ostream &ret, GenInlineItem *item )
441 {
442 	ret << ACT() << " = 0;";
443 }
444 
SET_TOKSTART(ostream & ret,GenInlineItem * item)445 void FsmCodeGen::SET_TOKSTART( ostream &ret, GenInlineItem *item )
446 {
447 	ret << TOKSTART() << " = " << P() << ";";
448 }
449 
SUB_ACTION(ostream & ret,GenInlineItem * item,int targState,bool inFinish,bool csForced)450 void FsmCodeGen::SUB_ACTION( ostream &ret, GenInlineItem *item,
451 		int targState, bool inFinish, bool csForced )
452 {
453 	if ( item->children->length() > 0 ) {
454 		/* Write the block and close it off. */
455 		ret << "{";
456 		INLINE_LIST( ret, item->children, targState, inFinish, csForced );
457 		ret << "}";
458 	}
459 }
460 
461 
462 /* Write out an inline tree structure. Walks the list and possibly calls out
463  * to virtual functions than handle language specific items in the tree. */
INLINE_LIST(ostream & ret,GenInlineList * inlineList,int targState,bool inFinish,bool csForced)464 void FsmCodeGen::INLINE_LIST( ostream &ret, GenInlineList *inlineList,
465 		int targState, bool inFinish, bool csForced )
466 {
467 	for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) {
468 		switch ( item->type ) {
469 		case GenInlineItem::Text:
470 			ret << item->data;
471 			break;
472 		case GenInlineItem::Goto:
473 			GOTO( ret, item->targState->id, inFinish );
474 			break;
475 		case GenInlineItem::Call:
476 			CALL( ret, item->targState->id, targState, inFinish );
477 			break;
478 		case GenInlineItem::Next:
479 			NEXT( ret, item->targState->id, inFinish );
480 			break;
481 		case GenInlineItem::Ret:
482 			RET( ret, inFinish );
483 			break;
484 		case GenInlineItem::PChar:
485 			ret << P();
486 			break;
487 		case GenInlineItem::Char:
488 			ret << GET_KEY();
489 			break;
490 		case GenInlineItem::Hold:
491 			ret << P() << "--;";
492 			break;
493 		case GenInlineItem::Exec:
494 			EXEC( ret, item, targState, inFinish );
495 			break;
496 		case GenInlineItem::Curs:
497 			CURS( ret, inFinish );
498 			break;
499 		case GenInlineItem::Targs:
500 			TARGS( ret, inFinish, targState );
501 			break;
502 		case GenInlineItem::Entry:
503 			ret << item->targState->id;
504 			break;
505 		case GenInlineItem::GotoExpr:
506 			GOTO_EXPR( ret, item, inFinish );
507 			break;
508 		case GenInlineItem::CallExpr:
509 			CALL_EXPR( ret, item, targState, inFinish );
510 			break;
511 		case GenInlineItem::NextExpr:
512 			NEXT_EXPR( ret, item, inFinish );
513 			break;
514 		case GenInlineItem::LmSwitch:
515 			LM_SWITCH( ret, item, targState, inFinish, csForced );
516 			break;
517 		case GenInlineItem::LmSetActId:
518 			SET_ACT( ret, item );
519 			break;
520 		case GenInlineItem::LmSetTokEnd:
521 			SET_TOKEND( ret, item );
522 			break;
523 		case GenInlineItem::LmGetTokEnd:
524 			GET_TOKEND( ret, item );
525 			break;
526 		case GenInlineItem::LmInitTokStart:
527 			INIT_TOKSTART( ret, item );
528 			break;
529 		case GenInlineItem::LmInitAct:
530 			INIT_ACT( ret, item );
531 			break;
532 		case GenInlineItem::LmSetTokStart:
533 			SET_TOKSTART( ret, item );
534 			break;
535 		case GenInlineItem::SubAction:
536 			SUB_ACTION( ret, item, targState, inFinish, csForced );
537 			break;
538 		case GenInlineItem::Break:
539 			BREAK( ret, targState, csForced );
540 			break;
541 		}
542 	}
543 }
544 /* Write out paths in line directives. Escapes any special characters. */
LDIR_PATH(char * path)545 string FsmCodeGen::LDIR_PATH( char *path )
546 {
547 	ostringstream ret;
548 	for ( char *pc = path; *pc != 0; pc++ ) {
549 		if ( *pc == '\\' )
550 			ret << "\\\\";
551 		else
552 			ret << *pc;
553 	}
554 	return ret.str();
555 }
556 
ACTION(ostream & ret,GenAction * action,int targState,bool inFinish,bool csForced)557 void FsmCodeGen::ACTION( ostream &ret, GenAction *action, int targState,
558 		bool inFinish, bool csForced )
559 {
560 	/* Write the preprocessor line info for going into the source file. */
561 	cdLineDirective( ret, action->loc.fileName, action->loc.line );
562 
563 	/* Write the block and close it off. */
564 	ret << "\t{";
565 	INLINE_LIST( ret, action->inlineList, targState, inFinish, csForced );
566 	ret << "}\n";
567 }
568 
CONDITION(ostream & ret,GenAction * condition)569 void FsmCodeGen::CONDITION( ostream &ret, GenAction *condition )
570 {
571 	ret << "\n";
572 	cdLineDirective( ret, condition->loc.fileName, condition->loc.line );
573 	INLINE_LIST( ret, condition->inlineList, 0, false, false );
574 }
575 
ERROR_STATE()576 string FsmCodeGen::ERROR_STATE()
577 {
578 	ostringstream ret;
579 	if ( redFsm->errState != 0 )
580 		ret << redFsm->errState->id;
581 	else
582 		ret << "-1";
583 	return ret.str();
584 }
585 
FIRST_FINAL_STATE()586 string FsmCodeGen::FIRST_FINAL_STATE()
587 {
588 	ostringstream ret;
589 	if ( redFsm->firstFinState != 0 )
590 		ret << redFsm->firstFinState->id;
591 	else
592 		ret << redFsm->nextStateId;
593 	return ret.str();
594 }
595 
writeInit()596 void FsmCodeGen::writeInit()
597 {
598 	out << "	{\n";
599 
600 	if ( !noCS )
601 		out << "\t" << vCS() << " = " << START() << ";\n";
602 
603 	/* If there are any calls, then the stack top needs initialization. */
604 	if ( redFsm->anyActionCalls() || redFsm->anyActionRets() )
605 		out << "\t" << TOP() << " = 0;\n";
606 
607 	if ( hasLongestMatch ) {
608 		out <<
609 			"	" << TOKSTART() << " = " << NULL_ITEM() << ";\n"
610 			"	" << TOKEND() << " = " << NULL_ITEM() << ";\n"
611 			"	" << ACT() << " = 0;\n";
612 	}
613 	out << "	}\n";
614 }
615 
DATA_PREFIX()616 string FsmCodeGen::DATA_PREFIX()
617 {
618 	if ( !noPrefix )
619 		return FSM_NAME() + "_";
620 	return "";
621 }
622 
623 /* Emit the alphabet data type. */
ALPH_TYPE()624 string FsmCodeGen::ALPH_TYPE()
625 {
626 	string ret = keyOps->alphType->data1;
627 	if ( keyOps->alphType->data2 != 0 ) {
628 		ret += " ";
629 		ret += + keyOps->alphType->data2;
630 	}
631 	return ret;
632 }
633 
634 /* Emit the alphabet data type. */
WIDE_ALPH_TYPE()635 string FsmCodeGen::WIDE_ALPH_TYPE()
636 {
637 	string ret;
638 	if ( redFsm->maxKey <= keyOps->maxKey )
639 		ret = ALPH_TYPE();
640 	else {
641 		long long maxKeyVal = redFsm->maxKey.getLongLong();
642 		HostType *wideType = keyOps->typeSubsumes( keyOps->isSigned, maxKeyVal );
643 		assert( wideType != 0 );
644 
645 		ret = wideType->data1;
646 		if ( wideType->data2 != 0 ) {
647 			ret += " ";
648 			ret += wideType->data2;
649 		}
650 	}
651 	return ret;
652 }
653 
STATE_IDS()654 void FsmCodeGen::STATE_IDS()
655 {
656 	if ( redFsm->startState != 0 )
657 		STATIC_VAR( "int", START() ) << " = " << START_STATE_ID() << ";\n";
658 
659 	if ( !noFinal )
660 		STATIC_VAR( "int" , FIRST_FINAL() ) << " = " << FIRST_FINAL_STATE() << ";\n";
661 
662 	if ( !noError )
663 		STATIC_VAR( "int", ERROR() ) << " = " << ERROR_STATE() << ";\n";
664 
665 	out << "\n";
666 
667 	if ( !noEntry && entryPointNames.length() > 0 ) {
668 		for ( EntryNameVect::Iter en = entryPointNames; en.lte(); en++ ) {
669 			STATIC_VAR( "int", DATA_PREFIX() + "en_" + *en ) <<
670 					" = " << entryPointIds[en.pos()] << ";\n";
671 		}
672 		out << "\n";
673 	}
674 }
675 
writeStart()676 void FsmCodeGen::writeStart()
677 {
678 	out << START_STATE_ID();
679 }
680 
writeFirstFinal()681 void FsmCodeGen::writeFirstFinal()
682 {
683 	out << FIRST_FINAL_STATE();
684 }
685 
writeError()686 void FsmCodeGen::writeError()
687 {
688 	out << ERROR_STATE();
689 }
690 
691 /*
692  * Language specific, but style independent code generators functions.
693  */
694 
PTR_CONST()695 string CCodeGen::PTR_CONST()
696 {
697 	return "const ";
698 }
699 
PTR_CONST_END()700 string CCodeGen::PTR_CONST_END()
701 {
702 	return "";
703 }
704 
OPEN_ARRAY(string type,string name)705 std::ostream &CCodeGen::OPEN_ARRAY( string type, string name )
706 {
707 	out << "static const " << type << " " << name << "[] = {\n";
708 	return out;
709 }
710 
CLOSE_ARRAY()711 std::ostream &CCodeGen::CLOSE_ARRAY()
712 {
713 	return out << "};\n";
714 }
715 
STATIC_VAR(string type,string name)716 std::ostream &CCodeGen::STATIC_VAR( string type, string name )
717 {
718 	out << "static const " << type << " " << name;
719 	return out;
720 }
721 
UINT()722 string CCodeGen::UINT( )
723 {
724 	return "unsigned int";
725 }
726 
ARR_OFF(string ptr,string offset)727 string CCodeGen::ARR_OFF( string ptr, string offset )
728 {
729 	return ptr + " + " + offset;
730 }
731 
CAST(string type)732 string CCodeGen::CAST( string type )
733 {
734 	return "(" + type + ")";
735 }
736 
NULL_ITEM()737 string CCodeGen::NULL_ITEM()
738 {
739 	return "0";
740 }
741 
POINTER()742 string CCodeGen::POINTER()
743 {
744 	return " *";
745 }
746 
SWITCH_DEFAULT()747 std::ostream &CCodeGen::SWITCH_DEFAULT()
748 {
749 	return out;
750 }
751 
CTRL_FLOW()752 string CCodeGen::CTRL_FLOW()
753 {
754 	return "";
755 }
756 
writeExports()757 void CCodeGen::writeExports()
758 {
759 	if ( exportList.length() > 0 ) {
760 		for ( ExportList::Iter ex = exportList; ex.lte(); ex++ ) {
761 			out << "#define " << DATA_PREFIX() << "ex_" << ex->name << " " <<
762 					KEY(ex->key) << "\n";
763 		}
764 		out << "\n";
765 	}
766 }
767 
768 /*
769  * D Specific
770  */
771 
NULL_ITEM()772 string DCodeGen::NULL_ITEM()
773 {
774 	return "null";
775 }
776 
POINTER()777 string DCodeGen::POINTER()
778 {
779 	// multiple items seperated by commas can also be pointer types.
780 	return "* ";
781 }
782 
PTR_CONST()783 string DCodeGen::PTR_CONST()
784 {
785 	return "";
786 }
787 
PTR_CONST_END()788 string DCodeGen::PTR_CONST_END()
789 {
790 	return "";
791 }
792 
OPEN_ARRAY(string type,string name)793 std::ostream &DCodeGen::OPEN_ARRAY( string type, string name )
794 {
795 	out << "static const " << type << "[] " << name << " = [\n";
796 	return out;
797 }
798 
CLOSE_ARRAY()799 std::ostream &DCodeGen::CLOSE_ARRAY()
800 {
801 	return out << "];\n";
802 }
803 
STATIC_VAR(string type,string name)804 std::ostream &DCodeGen::STATIC_VAR( string type, string name )
805 {
806 	out << "static const " << type << " " << name;
807 	return out;
808 }
809 
ARR_OFF(string ptr,string offset)810 string DCodeGen::ARR_OFF( string ptr, string offset )
811 {
812 	return "&" + ptr + "[" + offset + "]";
813 }
814 
CAST(string type)815 string DCodeGen::CAST( string type )
816 {
817 	return "cast(" + type + ")";
818 }
819 
UINT()820 string DCodeGen::UINT( )
821 {
822 	return "uint";
823 }
824 
SWITCH_DEFAULT()825 std::ostream &DCodeGen::SWITCH_DEFAULT()
826 {
827 	out << "		default: break;\n";
828 	return out;
829 }
830 
CTRL_FLOW()831 string DCodeGen::CTRL_FLOW()
832 {
833 	return "if (true) ";
834 }
835 
writeExports()836 void DCodeGen::writeExports()
837 {
838 	if ( exportList.length() > 0 ) {
839 		for ( ExportList::Iter ex = exportList; ex.lte(); ex++ ) {
840 			out << "static const " << ALPH_TYPE() << " " << DATA_PREFIX() <<
841 					"ex_" << ex->name << " = " << KEY(ex->key) << ";\n";
842 		}
843 		out << "\n";
844 	}
845 }
846 
847 /*
848  * End D-specific code.
849  */
850 
851 /*
852  * D2 Specific
853  */
854 
NULL_ITEM()855 string D2CodeGen::NULL_ITEM()
856 {
857 	return "null";
858 }
859 
POINTER()860 string D2CodeGen::POINTER()
861 {
862 	// multiple items seperated by commas can also be pointer types.
863 	return "* ";
864 }
865 
PTR_CONST()866 string D2CodeGen::PTR_CONST()
867 {
868 	return "const(";
869 }
870 
PTR_CONST_END()871 string D2CodeGen::PTR_CONST_END()
872 {
873 	return ")";
874 }
875 
OPEN_ARRAY(string type,string name)876 std::ostream &D2CodeGen::OPEN_ARRAY( string type, string name )
877 {
878 	out << "enum " << type << "[] " << name << " = [\n";
879 	return out;
880 }
881 
CLOSE_ARRAY()882 std::ostream &D2CodeGen::CLOSE_ARRAY()
883 {
884 	return out << "];\n";
885 }
886 
STATIC_VAR(string type,string name)887 std::ostream &D2CodeGen::STATIC_VAR( string type, string name )
888 {
889 	out << "enum " << type << " " << name;
890 	return out;
891 }
892 
ARR_OFF(string ptr,string offset)893 string D2CodeGen::ARR_OFF( string ptr, string offset )
894 {
895 	return "&" + ptr + "[" + offset + "]";
896 }
897 
CAST(string type)898 string D2CodeGen::CAST( string type )
899 {
900 	return "cast(" + type + ")";
901 }
902 
UINT()903 string D2CodeGen::UINT( )
904 {
905 	return "uint";
906 }
907 
SWITCH_DEFAULT()908 std::ostream &D2CodeGen::SWITCH_DEFAULT()
909 {
910 	out << "		default: break;\n";
911 	return out;
912 }
913 
CTRL_FLOW()914 string D2CodeGen::CTRL_FLOW()
915 {
916 	return "if (true) ";
917 }
918 
writeExports()919 void D2CodeGen::writeExports()
920 {
921 	if ( exportList.length() > 0 ) {
922 		for ( ExportList::Iter ex = exportList; ex.lte(); ex++ ) {
923 			out << "enum " << ALPH_TYPE() << " " << DATA_PREFIX() <<
924 					"ex_" << ex->name << " = " << KEY(ex->key) << ";\n";
925 		}
926 		out << "\n";
927 	}
928 }
929 
SUB_ACTION(ostream & ret,GenInlineItem * item,int targState,bool inFinish,bool csForced)930 void D2CodeGen::SUB_ACTION( ostream &ret, GenInlineItem *item,
931 		int targState, bool inFinish, bool csForced )
932 {
933 	if ( item->children->length() > 0 ) {
934 		/* Write the block and close it off. */
935 		ret << "{{";
936 		INLINE_LIST( ret, item->children, targState, inFinish, csForced );
937 		ret << "}}";
938 	}
939 }
940 
ACTION(ostream & ret,GenAction * action,int targState,bool inFinish,bool csForced)941 void D2CodeGen::ACTION( ostream &ret, GenAction *action, int targState,
942 		bool inFinish, bool csForced )
943 {
944 	/* Write the preprocessor line info for going into the source file. */
945 	cdLineDirective( ret, action->loc.fileName, action->loc.line );
946 
947 	/* Write the block and close it off. */
948 	ret << "\t{{";
949 	INLINE_LIST( ret, action->inlineList, targState, inFinish, csForced );
950 	ret << "}}\n";
951 }
952 
953 /*
954  * End D2-specific code.
955  */
956 
finishRagelDef()957 void FsmCodeGen::finishRagelDef()
958 {
959 	if ( codeStyle == GenGoto || codeStyle == GenFGoto ||
960 			codeStyle == GenIpGoto || codeStyle == GenSplit )
961 	{
962 		/* For directly executable machines there is no required state
963 		 * ordering. Choose a depth-first ordering to increase the
964 		 * potential for fall-throughs. */
965 		redFsm->depthFirstOrdering();
966 	}
967 	else {
968 		/* The frontend will do this for us, but it may be a good idea to
969 		 * force it if the intermediate file is edited. */
970 		redFsm->sortByStateId();
971 	}
972 
973 	/* Choose default transitions and the single transition. */
974 	redFsm->chooseDefaultSpan();
975 
976 	/* Maybe do flat expand, otherwise choose single. */
977 	if ( codeStyle == GenFlat || codeStyle == GenFFlat )
978 		redFsm->makeFlat();
979 	else
980 		redFsm->chooseSingle();
981 
982 	/* If any errors have occured in the input file then don't write anything. */
983 	if ( gblErrorCount > 0 )
984 		return;
985 
986 	if ( codeStyle == GenSplit )
987 		redFsm->partitionFsm( numSplitPartitions );
988 
989 	if ( codeStyle == GenIpGoto || codeStyle == GenSplit )
990 		redFsm->setInTrans();
991 
992 	/* Anlayze Machine will find the final action reference counts, among
993 	 * other things. We will use these in reporting the usage
994 	 * of fsm directives in action code. */
995 	analyzeMachine();
996 
997 	/* Determine if we should use indicies. */
998 	calcIndexSize();
999 }
1000 
source_warning(const InputLoc & loc)1001 ostream &FsmCodeGen::source_warning( const InputLoc &loc )
1002 {
1003 	cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": warning: ";
1004 	return cerr;
1005 }
1006 
source_error(const InputLoc & loc)1007 ostream &FsmCodeGen::source_error( const InputLoc &loc )
1008 {
1009 	gblErrorCount += 1;
1010 	assert( sourceFileName != 0 );
1011 	cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": ";
1012 	return cerr;
1013 }
1014 
1015