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 "ragel.h"
25 #include "mlcodegen.h"
26 #include "redfsm.h"
27 #include "gendata.h"
28 #include <sstream>
29 #include <iomanip>
30 #include <string>
31 #include <assert.h>
32 
33 using std::ostream;
34 using std::ostringstream;
35 using std::string;
36 using std::cerr;
37 using std::endl;
38 
39 using std::istream;
40 using std::ifstream;
41 using std::ostream;
42 using std::ios;
43 using std::cin;
44 using std::cout;
45 using std::cerr;
46 using std::endl;
47 
ocamlLineDirective(ostream & out,const char * fileName,int line)48 void ocamlLineDirective( ostream &out, const char *fileName, int line )
49 {
50 	if ( noLineDirectives )
51 		return;
52 
53 	/* Write the line info for to the input file. */
54 	out << "# " << line << " \"";
55 	for ( const char *pc = fileName; *pc != 0; pc++ ) {
56 		if ( *pc == '\\' || *pc == '"' )
57 			out << "\\";
58   	out << *pc;
59 	}
60 	out << "\"\n";
61 }
62 
genLineDirective(ostream & out)63 void OCamlCodeGen::genLineDirective( ostream &out )
64 {
65 	std::streambuf *sbuf = out.rdbuf();
66 	output_filter *filter = static_cast<output_filter*>(sbuf);
67 	ocamlLineDirective( out, filter->fileName, filter->line + 1 );
68 }
69 
70 
71 /* Init code gen with in parameters. */
OCamlCodeGen(ostream & out)72 OCamlCodeGen::OCamlCodeGen( ostream &out )
73 :
74 	CodeGenData(out)
75 {
76 }
77 
arrayTypeSize(unsigned long maxVal)78 unsigned int OCamlCodeGen::arrayTypeSize( unsigned long maxVal )
79 {
80 	long long maxValLL = (long long) maxVal;
81 	HostType *arrayType = keyOps->typeSubsumes( maxValLL );
82 	assert( arrayType != 0 );
83 	return arrayType->size;
84 }
85 
ARRAY_TYPE(unsigned long maxVal)86 string OCamlCodeGen::ARRAY_TYPE( unsigned long maxVal )
87 {
88 	return ARRAY_TYPE( maxVal, false );
89 }
90 
ARRAY_TYPE(unsigned long maxVal,bool forceSigned)91 string OCamlCodeGen::ARRAY_TYPE( unsigned long maxVal, bool forceSigned )
92 {
93 	long long maxValLL = (long long) maxVal;
94 	HostType *arrayType;
95 	if (forceSigned)
96 		arrayType = keyOps->typeSubsumes(true, maxValLL);
97 	else
98 		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 /* Write out the fsm name. */
FSM_NAME()110 string OCamlCodeGen::FSM_NAME()
111 {
112 	return fsmName;
113 }
114 
115 /* Emit the offset of the start state as a decimal integer. */
START_STATE_ID()116 string OCamlCodeGen::START_STATE_ID()
117 {
118 	ostringstream ret;
119 	ret << redFsm->startState->id;
120 	return ret.str();
121 };
122 
123 /* Write out the array of actions. */
ACTIONS_ARRAY()124 std::ostream &OCamlCodeGen::ACTIONS_ARRAY()
125 {
126 	out << "\t0; ";
127 	int totalActions = 1;
128 	for ( GenActionTableMap::Iter act = redFsm->actionMap; act.lte(); act++ ) {
129 		/* Write out the length, which will never be the last character. */
130 		out << act->key.length() << ARR_SEP();
131 		/* Put in a line break every 8 */
132 		if ( totalActions++ % 8 == 7 )
133 			out << "\n\t";
134 
135 		for ( GenActionTable::Iter item = act->key; item.lte(); item++ ) {
136 			out << item->value->actionId;
137 			if ( ! (act.last() && item.last()) )
138 				out << ARR_SEP();
139 
140 			/* Put in a line break every 8 */
141 			if ( totalActions++ % 8 == 7 )
142 				out << "\n\t";
143 		}
144 	}
145 	out << "\n";
146 	return out;
147 }
148 
149 
150 /*
151 string OCamlCodeGen::ACCESS()
152 {
153 	ostringstream ret;
154 	if ( accessExpr != 0 )
155 		INLINE_LIST( ret, accessExpr, 0, false );
156 	return ret.str();
157 }
158 */
159 
make_access(char const * name,GenInlineList * x,bool prefix=true)160 string OCamlCodeGen::make_access(char const* name, GenInlineList* x, bool prefix = true)
161 {
162 	ostringstream ret;
163 	if ( x == 0 )
164   {
165     if (prefix && accessExpr != 0)
166     {
167       INLINE_LIST( ret, accessExpr, 0, false);
168       ret << name;
169     }
170     else
171       ret << name << ".contents"; // ref cell
172   }
173 	else {
174 		ret << "(";
175 		INLINE_LIST( ret, x, 0, false );
176 		ret << ")";
177 	}
178 	return ret.str();
179 }
180 
P()181 string OCamlCodeGen::P() { return make_access("p", pExpr, false); }
PE()182 string OCamlCodeGen::PE() { return make_access("pe", peExpr, false); }
vEOF()183 string OCamlCodeGen::vEOF() { return make_access("eof", eofExpr, false); }
vCS()184 string OCamlCodeGen::vCS() { return make_access("cs", csExpr); }
TOP()185 string OCamlCodeGen::TOP() { return make_access("top", topExpr); }
STACK()186 string OCamlCodeGen::STACK() { return make_access("stack", stackExpr); }
ACT()187 string OCamlCodeGen::ACT() { return make_access("act", actExpr); }
TOKSTART()188 string OCamlCodeGen::TOKSTART() { return make_access("ts", tokstartExpr); }
TOKEND()189 string OCamlCodeGen::TOKEND() { return make_access("te", tokendExpr); }
190 
GET_WIDE_KEY()191 string OCamlCodeGen::GET_WIDE_KEY()
192 {
193 	if ( redFsm->anyConditions() )
194 		return "_widec";
195 	else
196     { ostringstream ret; ret << "Char.code " << GET_KEY(); return ret.str(); }
197 }
198 
GET_WIDE_KEY(RedStateAp * state)199 string OCamlCodeGen::GET_WIDE_KEY( RedStateAp *state )
200 {
201 	if ( state->stateCondList.length() > 0 )
202 		return "_widec";
203 	else
204     { ostringstream ret; ret << "Char.code " << GET_KEY(); return ret.str(); }
205 }
206 
207 /* Write out level number of tabs. Makes the nested binary search nice
208  * looking. */
TABS(int level)209 string OCamlCodeGen::TABS( int level )
210 {
211 	string result;
212 	while ( level-- > 0 )
213 		result += "\t";
214 	return result;
215 }
216 
217 /* Write out a key from the fsm code gen. Depends on wether or not the key is
218  * signed. */
KEY(Key key)219 string OCamlCodeGen::KEY( Key key )
220 {
221 	ostringstream ret;
222 	if ( keyOps->isSigned || !hostLang->explicitUnsigned )
223 		ret << key.getVal();
224 	else
225 		ret << (unsigned long) key.getVal() << 'u';
226 	return ret.str();
227 }
228 
ALPHA_KEY(Key key)229 string OCamlCodeGen::ALPHA_KEY( Key key )
230 {
231 	ostringstream ret;
232   ret << key.getVal();
233   /*
234 	if (key.getVal() > 0xFFFF) {
235 		ret << key.getVal();
236 	} else {
237 		ret << "'\\u" << std::hex << std::setw(4) << std::setfill('0') <<
238 			key.getVal() << "'";
239 	}
240   */
241 	//ret << "(char) " << key.getVal();
242 	return ret.str();
243 }
244 
EXEC(ostream & ret,GenInlineItem * item,int targState,int inFinish)245 void OCamlCodeGen::EXEC( ostream &ret, GenInlineItem *item, int targState, int inFinish )
246 {
247 // The parser gives fexec two children.
248 	ret << "begin " << P() << " <- ";
249 	INLINE_LIST( ret, item->children, targState, inFinish );
250 	ret << " - 1 end; ";
251 }
252 
LM_SWITCH(ostream & ret,GenInlineItem * item,int targState,int inFinish)253 void OCamlCodeGen::LM_SWITCH( ostream &ret, GenInlineItem *item,
254 		int targState, int inFinish )
255 {
256 	bool catch_all = false;
257 	ret <<
258 		"	begin match " << ACT() << " with\n";
259 
260 	for ( GenInlineList::Iter lma = *item->children; lma.lte(); lma++ ) {
261 		/* Write the case label, the action and the case break. */
262 		if ( lma->lmId < 0 )
263 		{
264 			catch_all = true;
265 			ret << "	| _ ->\n";
266 		}
267 		else
268 			ret << "	| " << lma->lmId << " ->\n";
269 
270 		/* Write the block and close it off. */
271 		ret << "	begin ";
272 		INLINE_LIST( ret, lma->children, targState, inFinish );
273 		ret << " end\n";
274 	}
275 
276 	if (!catch_all)
277 		ret << "  | _ -> assert false\n";
278 
279 	ret <<
280 		"	end;\n"
281 		"\t";
282 }
283 
SET_ACT(ostream & ret,GenInlineItem * item)284 void OCamlCodeGen::SET_ACT( ostream &ret, GenInlineItem *item )
285 {
286 	ret << ACT() << " <- " << item->lmId << "; ";
287 }
288 
SET_TOKEND(ostream & ret,GenInlineItem * item)289 void OCamlCodeGen::SET_TOKEND( ostream &ret, GenInlineItem *item )
290 {
291 	/* The tokend action sets tokend. */
292 	ret << TOKEND() << " <- " << P();
293 	if ( item->offset != 0 )
294 		out << "+" << item->offset;
295 	out << "; ";
296 }
297 
GET_TOKEND(ostream & ret,GenInlineItem * item)298 void OCamlCodeGen::GET_TOKEND( ostream &ret, GenInlineItem *item )
299 {
300 	ret << TOKEND();
301 }
302 
INIT_TOKSTART(ostream & ret,GenInlineItem * item)303 void OCamlCodeGen::INIT_TOKSTART( ostream &ret, GenInlineItem *item )
304 {
305 	ret << TOKSTART() << " <- " << NULL_ITEM() << "; ";
306 }
307 
INIT_ACT(ostream & ret,GenInlineItem * item)308 void OCamlCodeGen::INIT_ACT( ostream &ret, GenInlineItem *item )
309 {
310 	ret << ACT() << " <- 0;";
311 }
312 
SET_TOKSTART(ostream & ret,GenInlineItem * item)313 void OCamlCodeGen::SET_TOKSTART( ostream &ret, GenInlineItem *item )
314 {
315 	ret << TOKSTART() << " <- " << P() << "; ";
316 }
317 
SUB_ACTION(ostream & ret,GenInlineItem * item,int targState,bool inFinish)318 void OCamlCodeGen::SUB_ACTION( ostream &ret, GenInlineItem *item,
319 		int targState, bool inFinish )
320 {
321 	if ( item->children->length() > 0 ) {
322 		/* Write the block and close it off. */
323 		ret << "begin ";
324 		INLINE_LIST( ret, item->children, targState, inFinish );
325 		ret << " end";
326 	}
327 }
328 
329 
330 /* Write out an inline tree structure. Walks the list and possibly calls out
331  * to virtual functions than handle language specific items in the tree. */
INLINE_LIST(ostream & ret,GenInlineList * inlineList,int targState,bool inFinish)332 void OCamlCodeGen::INLINE_LIST( ostream &ret, GenInlineList *inlineList,
333 		int targState, bool inFinish )
334 {
335 	for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) {
336 		switch ( item->type ) {
337 		case GenInlineItem::Text:
338 			ret << item->data;
339 			break;
340 		case GenInlineItem::Goto:
341 			GOTO( ret, item->targState->id, inFinish );
342 			break;
343 		case GenInlineItem::Call:
344 			CALL( ret, item->targState->id, targState, inFinish );
345 			break;
346 		case GenInlineItem::Next:
347 			NEXT( ret, item->targState->id, inFinish );
348 			break;
349 		case GenInlineItem::Ret:
350 			RET( ret, inFinish );
351 			break;
352 		case GenInlineItem::PChar:
353 			ret << P();
354 			break;
355 		case GenInlineItem::Char:
356 			ret << GET_KEY();
357 			break;
358 		case GenInlineItem::Hold:
359 			ret << P() << " <- " << P() << " - 1; ";
360 			break;
361 		case GenInlineItem::Exec:
362 			EXEC( ret, item, targState, inFinish );
363 			break;
364 		case GenInlineItem::Curs:
365 			CURS( ret, inFinish );
366 			break;
367 		case GenInlineItem::Targs:
368 			TARGS( ret, inFinish, targState );
369 			break;
370 		case GenInlineItem::Entry:
371 			ret << item->targState->id;
372 			break;
373 		case GenInlineItem::GotoExpr:
374 			GOTO_EXPR( ret, item, inFinish );
375 			break;
376 		case GenInlineItem::CallExpr:
377 			CALL_EXPR( ret, item, targState, inFinish );
378 			break;
379 		case GenInlineItem::NextExpr:
380 			NEXT_EXPR( ret, item, inFinish );
381 			break;
382 		case GenInlineItem::LmSwitch:
383 			LM_SWITCH( ret, item, targState, inFinish );
384 			break;
385 		case GenInlineItem::LmSetActId:
386 			SET_ACT( ret, item );
387 			break;
388 		case GenInlineItem::LmSetTokEnd:
389 			SET_TOKEND( ret, item );
390 			break;
391 		case GenInlineItem::LmGetTokEnd:
392 			GET_TOKEND( ret, item );
393 			break;
394 		case GenInlineItem::LmInitTokStart:
395 			INIT_TOKSTART( ret, item );
396 			break;
397 		case GenInlineItem::LmInitAct:
398 			INIT_ACT( ret, item );
399 			break;
400 		case GenInlineItem::LmSetTokStart:
401 			SET_TOKSTART( ret, item );
402 			break;
403 		case GenInlineItem::SubAction:
404 			SUB_ACTION( ret, item, targState, inFinish );
405 			break;
406 		case GenInlineItem::Break:
407 			BREAK( ret, targState );
408 			break;
409 		}
410 	}
411 }
412 /* Write out paths in line directives. Escapes any special characters. */
LDIR_PATH(char * path)413 string OCamlCodeGen::LDIR_PATH( char *path )
414 {
415 	ostringstream ret;
416 	for ( char *pc = path; *pc != 0; pc++ ) {
417 		if ( *pc == '\\' )
418 			ret << "\\\\";
419 		else
420 			ret << *pc;
421 	}
422 	return ret.str();
423 }
424 
ACTION(ostream & ret,GenAction * action,int targState,bool inFinish)425 void OCamlCodeGen::ACTION( ostream &ret, GenAction *action, int targState, bool inFinish )
426 {
427 	/* Write the preprocessor line info for going into the source file. */
428 	ocamlLineDirective( ret, action->loc.fileName, action->loc.line );
429 
430 	/* Write the block and close it off. */
431 	ret << "\t\tbegin ";
432 	INLINE_LIST( ret, action->inlineList, targState, inFinish );
433 	ret << " end;\n";
434 }
435 
CONDITION(ostream & ret,GenAction * condition)436 void OCamlCodeGen::CONDITION( ostream &ret, GenAction *condition )
437 {
438 	ret << "\n";
439 	ocamlLineDirective( ret, condition->loc.fileName, condition->loc.line );
440 	INLINE_LIST( ret, condition->inlineList, 0, false );
441 }
442 
ERROR_STATE()443 string OCamlCodeGen::ERROR_STATE()
444 {
445 	ostringstream ret;
446 	if ( redFsm->errState != 0 )
447 		ret << redFsm->errState->id;
448 	else
449 		ret << "-1";
450 	return ret.str();
451 }
452 
FIRST_FINAL_STATE()453 string OCamlCodeGen::FIRST_FINAL_STATE()
454 {
455 	ostringstream ret;
456 	if ( redFsm->firstFinState != 0 )
457 		ret << redFsm->firstFinState->id;
458 	else
459 		ret << redFsm->nextStateId;
460 	return ret.str();
461 }
462 
writeInit()463 void OCamlCodeGen::writeInit()
464 {
465 	out << "	begin\n";
466 
467 	if ( !noCS )
468 		out << "\t" << vCS() << " <- " << START() << ";\n";
469 
470 	/* If there are any calls, then the stack top needs initialization. */
471 	if ( redFsm->anyActionCalls() || redFsm->anyActionRets() )
472 		out << "\t" << TOP() << " <- 0;\n";
473 
474 	if ( hasLongestMatch ) {
475 		out <<
476 			"	" << TOKSTART() << " <- " << NULL_ITEM() << ";\n"
477 			"	" << TOKEND() << " <- " << NULL_ITEM() << ";\n"
478 			"	" << ACT() << " <- 0;\n";
479 	}
480 	out << "	end;\n";
481 }
482 
PRE_INCR(string val)483 string OCamlCodeGen::PRE_INCR(string val)
484 {
485   ostringstream ret;
486   ret << "(" << val << " <- " << val << " + 1; " << val << ")";
487   return ret.str();
488 }
489 
POST_INCR(string val)490 string OCamlCodeGen::POST_INCR(string val)
491 {
492   ostringstream ret;
493   ret << "(let temp = " << val << " in " << val << " <- " << val << " + 1; temp)";
494   return ret.str();
495 }
496 
PRE_DECR(string val)497 string OCamlCodeGen::PRE_DECR(string val)
498 {
499   ostringstream ret;
500   ret << "(" << val << " <- " << val << " - 1; " << val << ")";
501   return ret.str();
502 }
503 
POST_DECR(string val)504 string OCamlCodeGen::POST_DECR(string val)
505 {
506   ostringstream ret;
507   ret << "(let temp = " << val << " in " << val << " <- " << val << " - 1; temp)";
508   return ret.str();
509 }
510 
DATA_PREFIX()511 string OCamlCodeGen::DATA_PREFIX()
512 {
513   if ( data_prefix.empty() ) // init
514   {
515     data_prefix = string(fsmName) + "_";
516     if (data_prefix.size() > 0)
517       data_prefix[0] = ::tolower(data_prefix[0]); // uncapitalize
518   }
519 	if ( !noPrefix )
520 		return data_prefix;
521 	return "";
522 }
523 
524 /* Emit the alphabet data type. */
ALPH_TYPE()525 string OCamlCodeGen::ALPH_TYPE()
526 {
527 	string ret = keyOps->alphType->data1;
528 	if ( keyOps->alphType->data2 != 0 ) {
529 		ret += " ";
530 		ret += + keyOps->alphType->data2;
531 	}
532 	return ret;
533 }
534 
535 /* Emit the alphabet data type. */
WIDE_ALPH_TYPE()536 string OCamlCodeGen::WIDE_ALPH_TYPE()
537 {
538 	string ret;
539 	if ( redFsm->maxKey <= keyOps->maxKey )
540 		ret = ALPH_TYPE();
541 	else {
542 		long long maxKeyVal = redFsm->maxKey.getLongLong();
543 		HostType *wideType = keyOps->typeSubsumes( keyOps->isSigned, maxKeyVal );
544 		assert( wideType != 0 );
545 
546 		ret = wideType->data1;
547 		if ( wideType->data2 != 0 ) {
548 			ret += " ";
549 			ret += wideType->data2;
550 		}
551 	}
552 	return ret;
553 }
554 
STATE_IDS()555 void OCamlCodeGen::STATE_IDS()
556 {
557 	if ( redFsm->startState != 0 )
558 		STATIC_VAR( "int", START() ) << " = " << START_STATE_ID() << TOP_SEP ();
559 
560 	if ( !noFinal )
561 		STATIC_VAR( "int" , FIRST_FINAL() ) << " = " << FIRST_FINAL_STATE() << TOP_SEP();
562 
563 	if ( !noError )
564 		STATIC_VAR( "int", ERROR() ) << " = " << ERROR_STATE() << TOP_SEP();
565 
566 	out << "\n";
567 
568 	if ( !noEntry && entryPointNames.length() > 0 ) {
569 		for ( EntryNameVect::Iter en = entryPointNames; en.lte(); en++ ) {
570 			STATIC_VAR( "int", DATA_PREFIX() + "en_" + *en ) <<
571 					" = " << entryPointIds[en.pos()] << TOP_SEP();
572 		}
573 		out << "\n";
574 	}
575 }
576 
577 
writeStart()578 void OCamlCodeGen::writeStart()
579 {
580 	out << START_STATE_ID();
581 }
582 
writeFirstFinal()583 void OCamlCodeGen::writeFirstFinal()
584 {
585 	out << FIRST_FINAL_STATE();
586 }
587 
writeError()588 void OCamlCodeGen::writeError()
589 {
590 	out << ERROR_STATE();
591 }
592 
GET_KEY()593 string OCamlCodeGen::GET_KEY()
594 {
595 	ostringstream ret;
596 	if ( getKeyExpr != 0 ) {
597 		/* Emit the user supplied method of retrieving the key. */
598 		ret << "(";
599 		INLINE_LIST( ret, getKeyExpr, 0, false );
600 		ret << ")";
601 	}
602 	else {
603 		/* Expression for retrieving the key, use simple dereference. */
604 		ret << "data.[" << P() << "]";
605 	}
606 	return ret.str();
607 }
NULL_ITEM()608 string OCamlCodeGen::NULL_ITEM()
609 {
610 	return "-1";
611 }
612 
POINTER()613 string OCamlCodeGen::POINTER()
614 {
615 	// XXX C# has no pointers
616 	// multiple items seperated by commas can also be pointer types.
617 	return " ";
618 }
619 
PTR_CONST()620 string OCamlCodeGen::PTR_CONST()
621 {
622 	return "";
623 }
624 
OPEN_ARRAY(string type,string name)625 std::ostream &OCamlCodeGen::OPEN_ARRAY( string type, string name )
626 {
627 	out << "let " << name << " : " << type << " array = [|" << endl;
628 	return out;
629 }
630 
CLOSE_ARRAY()631 std::ostream &OCamlCodeGen::CLOSE_ARRAY()
632 {
633 	return out << "|]" << TOP_SEP();
634 }
635 
TOP_SEP()636 string OCamlCodeGen::TOP_SEP()
637 {
638   return "\n"; // original syntax
639 }
640 
ARR_SEP()641 string OCamlCodeGen::ARR_SEP()
642 {
643   return "; ";
644 }
645 
AT(const string & array,const string & index)646 string OCamlCodeGen::AT(const string& array, const string& index)
647 {
648   ostringstream ret;
649   ret << array << ".(" << index << ")";
650   return ret.str();
651 }
652 
STATIC_VAR(string type,string name)653 std::ostream &OCamlCodeGen::STATIC_VAR( string type, string name )
654 {
655 	out << "let " << name << " : " << type;
656 	return out;
657 }
658 
ARR_OFF(string ptr,string offset)659 string OCamlCodeGen::ARR_OFF( string ptr, string offset )
660 {
661 	// XXX C# can't do pointer arithmetic
662 	return "&" + ptr + "[" + offset + "]";
663 }
664 
CAST(string type)665 string OCamlCodeGen::CAST( string type )
666 {
667   return "";
668 //	return "(" + type + ")";
669 }
670 
UINT()671 string OCamlCodeGen::UINT( )
672 {
673 	return "uint";
674 }
675 
SWITCH_DEFAULT()676 std::ostream &OCamlCodeGen::SWITCH_DEFAULT()
677 {
678 	out << "		| _ -> ()\n";
679 	return out;
680 }
681 
CTRL_FLOW()682 string OCamlCodeGen::CTRL_FLOW()
683 {
684 	return "if true then ";
685 }
686 
finishRagelDef()687 void OCamlCodeGen::finishRagelDef()
688 {
689 	if ( codeStyle == GenGoto || codeStyle == GenFGoto ||
690 			codeStyle == GenIpGoto || codeStyle == GenSplit )
691 	{
692 		/* For directly executable machines there is no required state
693 		 * ordering. Choose a depth-first ordering to increase the
694 		 * potential for fall-throughs. */
695 		redFsm->depthFirstOrdering();
696 	}
697 	else {
698 		/* The frontend will do this for us, but it may be a good idea to
699 		 * force it if the intermediate file is edited. */
700 		redFsm->sortByStateId();
701 	}
702 
703 	/* Choose default transitions and the single transition. */
704 	redFsm->chooseDefaultSpan();
705 
706 	/* Maybe do flat expand, otherwise choose single. */
707 	if ( codeStyle == GenFlat || codeStyle == GenFFlat )
708 		redFsm->makeFlat();
709 	else
710 		redFsm->chooseSingle();
711 
712 	/* If any errors have occured in the input file then don't write anything. */
713 	if ( gblErrorCount > 0 )
714 		return;
715 
716 	if ( codeStyle == GenSplit )
717 		redFsm->partitionFsm( numSplitPartitions );
718 
719 	if ( codeStyle == GenIpGoto || codeStyle == GenSplit )
720 		redFsm->setInTrans();
721 
722 	/* Anlayze Machine will find the final action reference counts, among
723 	 * other things. We will use these in reporting the usage
724 	 * of fsm directives in action code. */
725 	analyzeMachine();
726 
727 	/* Determine if we should use indicies. */
728 	calcIndexSize();
729 }
730 
source_warning(const InputLoc & loc)731 ostream &OCamlCodeGen::source_warning( const InputLoc &loc )
732 {
733 	cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": warning: ";
734 	return cerr;
735 }
736 
source_error(const InputLoc & loc)737 ostream &OCamlCodeGen::source_error( const InputLoc &loc )
738 {
739 	gblErrorCount += 1;
740 	assert( sourceFileName != 0 );
741 	cerr << sourceFileName << ":" << loc.line << ":" << loc.col << ": ";
742 	return cerr;
743 }
744 
745