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