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