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 "mlgoto.h"
26 #include "redfsm.h"
27 #include "bstmap.h"
28 #include "gendata.h"
29
30 /* Emit the goto to take for a given transition. */
TRANS_GOTO(RedTransAp * trans,int level)31 std::ostream &OCamlGotoCodeGen::TRANS_GOTO( RedTransAp *trans, int level )
32 {
33 out << TABS(level) << "tr" << trans->id << " ()";
34 return out;
35 }
36
TO_STATE_ACTION_SWITCH()37 std::ostream &OCamlGotoCodeGen::TO_STATE_ACTION_SWITCH()
38 {
39 /* Walk the list of functions, printing the cases. */
40 for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
41 /* Write out referenced actions. */
42 if ( act->numToStateRefs > 0 ) {
43 /* Write the case label, the action and the case break. */
44 out << "\t| " << act->actionId << " ->\n";
45 ACTION( out, act, 0, false );
46 out << "\t()\n";
47 }
48 }
49
50 genLineDirective( out );
51 return out;
52 }
53
FROM_STATE_ACTION_SWITCH()54 std::ostream &OCamlGotoCodeGen::FROM_STATE_ACTION_SWITCH()
55 {
56 /* Walk the list of functions, printing the cases. */
57 for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
58 /* Write out referenced actions. */
59 if ( act->numFromStateRefs > 0 ) {
60 /* Write the case label, the action and the case break. */
61 out << "\t| " << act->actionId << " ->\n";
62 ACTION( out, act, 0, false );
63 out << "\t()\n";
64 }
65 }
66
67 genLineDirective( out );
68 return out;
69 }
70
EOF_ACTION_SWITCH()71 std::ostream &OCamlGotoCodeGen::EOF_ACTION_SWITCH()
72 {
73 /* Walk the list of functions, printing the cases. */
74 for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
75 /* Write out referenced actions. */
76 if ( act->numEofRefs > 0 ) {
77 /* Write the case label, the action and the case break. */
78 out << "\t| " << act->actionId << " ->\n";
79 ACTION( out, act, 0, true );
80 out << "\t()\n";
81 }
82 }
83
84 genLineDirective( out );
85 return out;
86 }
87
ACTION_SWITCH()88 std::ostream &OCamlGotoCodeGen::ACTION_SWITCH()
89 {
90 /* Walk the list of functions, printing the cases. */
91 for ( GenActionList::Iter act = actionList; act.lte(); act++ ) {
92 /* Write out referenced actions. */
93 if ( act->numTransRefs > 0 ) {
94 /* Write the case label, the action and the case break. */
95 out << "\t| " << act->actionId << " ->\n";
96 ACTION( out, act, 0, false );
97 out << "\t()\n";
98 }
99 }
100
101 genLineDirective( out );
102 return out;
103 }
104
GOTO_HEADER(RedStateAp * state)105 void OCamlGotoCodeGen::GOTO_HEADER( RedStateAp *state )
106 {
107 /* Label the state. */
108 out << "| " << state->id << " ->\n";
109 }
110
111
emitSingleSwitch(RedStateAp * state)112 void OCamlGotoCodeGen::emitSingleSwitch( RedStateAp *state )
113 {
114 /* Load up the singles. */
115 int numSingles = state->outSingle.length();
116 RedTransEl *data = state->outSingle.data;
117
118 if ( numSingles == 1 ) {
119 /* If there is a single single key then write it out as an if. */
120 out << "\tif " << GET_WIDE_KEY(state) << " = " <<
121 KEY(data[0].lowKey) << " then\n\t\t";
122
123 /* Virtual function for writing the target of the transition. */
124 TRANS_GOTO(data[0].value, 0) << " else\n";
125 }
126 else if ( numSingles > 1 ) {
127 /* Write out single keys in a switch if there is more than one. */
128 out << "\tmatch " << GET_WIDE_KEY(state) << " with\n";
129
130 /* Write out the single indicies. */
131 for ( int j = 0; j < numSingles; j++ ) {
132 out << "\t\t| " << ALPHA_KEY(data[j].lowKey) << " -> ";
133 TRANS_GOTO(data[j].value, 0) << "\n";
134 }
135
136 out << "\t\t| _ ->\n";
137 }
138 }
139
emitRangeBSearch(RedStateAp * state,int level,int low,int high,RedTransAp * def)140 void OCamlGotoCodeGen::emitRangeBSearch( RedStateAp *state, int level, int low, int high, RedTransAp* def)
141 {
142 /* Get the mid position, staying on the lower end of the range. */
143 int mid = (low + high) >> 1;
144 RedTransEl *data = state->outRange.data;
145
146 /* Determine if we need to look higher or lower. */
147 bool anyLower = mid > low;
148 bool anyHigher = mid < high;
149
150 /* Determine if the keys at mid are the limits of the alphabet. */
151 bool limitLow = data[mid].lowKey == keyOps->minKey;
152 bool limitHigh = data[mid].highKey == keyOps->maxKey;
153
154 if ( anyLower && anyHigher ) {
155 /* Can go lower and higher than mid. */
156 out << TABS(level) << "if " << GET_WIDE_KEY(state) << " < " <<
157 KEY(data[mid].lowKey) << " then begin\n";
158 emitRangeBSearch( state, level+1, low, mid-1, def );
159 out << TABS(level) << " end else if " << GET_WIDE_KEY(state) << " > " <<
160 KEY(data[mid].highKey) << " then begin\n";
161 emitRangeBSearch( state, level+1, mid+1, high, def );
162 out << TABS(level) << " end else\n";
163 TRANS_GOTO(data[mid].value, level+1) << "\n";
164 }
165 else if ( anyLower && !anyHigher ) {
166 /* Can go lower than mid but not higher. */
167 out << TABS(level) << "if " << GET_WIDE_KEY(state) << " < " <<
168 KEY(data[mid].lowKey) << " then begin\n";
169 emitRangeBSearch( state, level+1, low, mid-1, def );
170
171 /* if the higher is the highest in the alphabet then there is no
172 * sense testing it. */
173 if ( limitHigh ) {
174 out << TABS(level) << " end else\n";
175 TRANS_GOTO(data[mid].value, level+1) << "\n";
176 }
177 else {
178 out << TABS(level) << " end else if " << GET_WIDE_KEY(state) << " <= " <<
179 KEY(data[mid].highKey) << " then\n";
180 TRANS_GOTO(data[mid].value, level+1) << "\n" << TABS(level) << "else\n";
181 TRANS_GOTO(def, level+1) << "\n";
182 }
183 }
184 else if ( !anyLower && anyHigher ) {
185 /* Can go higher than mid but not lower. */
186 out << TABS(level) << "if " << GET_WIDE_KEY(state) << " > " <<
187 KEY(data[mid].highKey) << " then begin\n";
188 emitRangeBSearch( state, level+1, mid+1, high, def );
189
190 /* If the lower end is the lowest in the alphabet then there is no
191 * sense testing it. */
192 if ( limitLow ) {
193 out << TABS(level) << " end else\n";
194 TRANS_GOTO(data[mid].value, level+1) << "\n";
195 }
196 else {
197 out << TABS(level) << " end else if " << GET_WIDE_KEY(state) << " >= " <<
198 KEY(data[mid].lowKey) << " then\n";
199 TRANS_GOTO(data[mid].value, level+1) << "\n" << TABS(level) << "else\n";
200 TRANS_GOTO(def, level+1) << "\n";
201 }
202 }
203 else {
204 /* Cannot go higher or lower than mid. It's mid or bust. What
205 * tests to do depends on limits of alphabet. */
206 if ( !limitLow && !limitHigh ) {
207 out << TABS(level) << "if " << KEY(data[mid].lowKey) << " <= " <<
208 GET_WIDE_KEY(state) << " && " << GET_WIDE_KEY(state) << " <= " <<
209 KEY(data[mid].highKey) << " then\n";
210 TRANS_GOTO(data[mid].value, level+1) << "\n" << TABS(level) << "else\n";
211 TRANS_GOTO(def, level+1) << "\n";
212 }
213 else if ( limitLow && !limitHigh ) {
214 out << TABS(level) << "if " << GET_WIDE_KEY(state) << " <= " <<
215 KEY(data[mid].highKey) << " then\n";
216 TRANS_GOTO(data[mid].value, level+1) << "\n" << TABS(level) << "else\n";
217 TRANS_GOTO(def, level+1) << "\n";
218 }
219 else if ( !limitLow && limitHigh ) {
220 out << TABS(level) << "if " << KEY(data[mid].lowKey) << " <= " <<
221 GET_WIDE_KEY(state) << " then\n";
222 TRANS_GOTO(data[mid].value, level+1) << "\n" << TABS(level) << "else\n";
223 TRANS_GOTO(def, level+1) << "\n";
224 }
225 else {
226 /* Both high and low are at the limit. No tests to do. */
227 TRANS_GOTO(data[mid].value, level+1) << "\n";
228 }
229 }
230 }
231
STATE_GOTO_ERROR()232 void OCamlGotoCodeGen::STATE_GOTO_ERROR()
233 {
234 /* Label the state and bail immediately. */
235 outLabelUsed = true;
236 RedStateAp *state = redFsm->errState;
237 out << "| " << state->id << " ->\n";
238 out << " do_out ()\n";
239 }
240
COND_TRANSLATE(GenStateCond * stateCond,int level)241 void OCamlGotoCodeGen::COND_TRANSLATE( GenStateCond *stateCond, int level )
242 {
243 GenCondSpace *condSpace = stateCond->condSpace;
244 out << TABS(level) << "_widec = " << CAST(WIDE_ALPH_TYPE()) << "(" <<
245 KEY(condSpace->baseKey) << " + (" << GET_KEY() <<
246 " - " << KEY(keyOps->minKey) << "));\n";
247
248 for ( GenCondSet::Iter csi = condSpace->condSet; csi.lte(); csi++ ) {
249 out << TABS(level) << "if ( ";
250 CONDITION( out, *csi );
251 Size condValOffset = ((1 << csi.pos()) * keyOps->alphSize());
252 out << " ) _widec += " << condValOffset << ";\n";
253 }
254 }
255
emitCondBSearch(RedStateAp * state,int level,int low,int high)256 void OCamlGotoCodeGen::emitCondBSearch( RedStateAp *state, int level, int low, int high )
257 {
258 /* Get the mid position, staying on the lower end of the range. */
259 int mid = (low + high) >> 1;
260 GenStateCond **data = state->stateCondVect.data;
261
262 /* Determine if we need to look higher or lower. */
263 bool anyLower = mid > low;
264 bool anyHigher = mid < high;
265
266 /* Determine if the keys at mid are the limits of the alphabet. */
267 bool limitLow = data[mid]->lowKey == keyOps->minKey;
268 bool limitHigh = data[mid]->highKey == keyOps->maxKey;
269
270 if ( anyLower && anyHigher ) {
271 /* Can go lower and higher than mid. */
272 out << TABS(level) << "if ( " << GET_KEY() << " < " <<
273 KEY(data[mid]->lowKey) << " ) {\n";
274 emitCondBSearch( state, level+1, low, mid-1 );
275 out << TABS(level) << "} else if ( " << GET_KEY() << " > " <<
276 KEY(data[mid]->highKey) << " ) {\n";
277 emitCondBSearch( state, level+1, mid+1, high );
278 out << TABS(level) << "} else {\n";
279 COND_TRANSLATE(data[mid], level+1);
280 out << TABS(level) << "}\n";
281 }
282 else if ( anyLower && !anyHigher ) {
283 /* Can go lower than mid but not higher. */
284 out << TABS(level) << "if ( " << GET_KEY() << " < " <<
285 KEY(data[mid]->lowKey) << " ) {\n";
286 emitCondBSearch( state, level+1, low, mid-1 );
287
288 /* if the higher is the highest in the alphabet then there is no
289 * sense testing it. */
290 if ( limitHigh ) {
291 out << TABS(level) << "} else {\n";
292 COND_TRANSLATE(data[mid], level+1);
293 out << TABS(level) << "}\n";
294 }
295 else {
296 out << TABS(level) << "} else if ( " << GET_KEY() << " <= " <<
297 KEY(data[mid]->highKey) << " ) {\n";
298 COND_TRANSLATE(data[mid], level+1);
299 out << TABS(level) << "}\n";
300 }
301 }
302 else if ( !anyLower && anyHigher ) {
303 /* Can go higher than mid but not lower. */
304 out << TABS(level) << "if ( " << GET_KEY() << " > " <<
305 KEY(data[mid]->highKey) << " ) {\n";
306 emitCondBSearch( state, level+1, mid+1, high );
307
308 /* If the lower end is the lowest in the alphabet then there is no
309 * sense testing it. */
310 if ( limitLow ) {
311 out << TABS(level) << "} else {\n";
312 COND_TRANSLATE(data[mid], level+1);
313 out << TABS(level) << "}\n";
314 }
315 else {
316 out << TABS(level) << "} else if ( " << GET_KEY() << " >= " <<
317 KEY(data[mid]->lowKey) << " ) {\n";
318 COND_TRANSLATE(data[mid], level+1);
319 out << TABS(level) << "}\n";
320 }
321 }
322 else {
323 /* Cannot go higher or lower than mid. It's mid or bust. What
324 * tests to do depends on limits of alphabet. */
325 if ( !limitLow && !limitHigh ) {
326 out << TABS(level) << "if ( " << KEY(data[mid]->lowKey) << " <= " <<
327 GET_KEY() << " && " << GET_KEY() << " <= " <<
328 KEY(data[mid]->highKey) << " ) {\n";
329 COND_TRANSLATE(data[mid], level+1);
330 out << TABS(level) << "}\n";
331 }
332 else if ( limitLow && !limitHigh ) {
333 out << TABS(level) << "if ( " << GET_KEY() << " <= " <<
334 KEY(data[mid]->highKey) << " ) {\n";
335 COND_TRANSLATE(data[mid], level+1);
336 out << TABS(level) << "}\n";
337 }
338 else if ( !limitLow && limitHigh ) {
339 out << TABS(level) << "if ( " << KEY(data[mid]->lowKey) << " <= " <<
340 GET_KEY() << " )\n {";
341 COND_TRANSLATE(data[mid], level+1);
342 out << TABS(level) << "}\n";
343 }
344 else {
345 /* Both high and low are at the limit. No tests to do. */
346 COND_TRANSLATE(data[mid], level);
347 }
348 }
349 }
350
STATE_GOTOS()351 std::ostream &OCamlGotoCodeGen::STATE_GOTOS()
352 {
353 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
354 if ( st == redFsm->errState )
355 STATE_GOTO_ERROR();
356 else {
357 /* Writing code above state gotos. */
358 GOTO_HEADER( st );
359 out << "\tbegin\n";
360
361 if ( st->stateCondVect.length() > 0 ) {
362 out << " _widec = " << GET_KEY() << ";\n";
363 emitCondBSearch( st, 1, 0, st->stateCondVect.length() - 1 );
364 }
365
366 /* Try singles. */
367 if ( st->outSingle.length() > 0 )
368 emitSingleSwitch( st );
369
370 /* Default case is to binary search for the ranges, if that fails then */
371 if ( st->outRange.length() > 0 )
372 emitRangeBSearch( st, 1, 0, st->outRange.length() - 1, st->defTrans );
373 else
374 /* Write the default transition. */
375 TRANS_GOTO( st->defTrans, 1 ) << "\n";
376
377 out << "\tend\n";
378 }
379 }
380 return out;
381 }
382
TRANSITIONS()383 std::ostream &OCamlGotoCodeGen::TRANSITIONS()
384 {
385 /* Emit any transitions that have functions and that go to
386 * this state. */
387 for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) {
388 /* Write the label for the transition so it can be jumped to. */
389 out << " and tr" << trans->id << " () = ";
390
391 /* Destination state. */
392 if ( trans->action != 0 && trans->action->anyCurStateRef() )
393 out << "_ps = " << vCS() << ";";
394 out << vCS() << " <- " << trans->targ->id << "; ";
395
396 if ( trans->action != 0 ) {
397 /* Write out the transition func. */
398 out << "f" << trans->action->actListId << " ()\n";
399 }
400 else {
401 /* No code to execute, just loop around. */
402 out << "do_again ()\n";
403 }
404 }
405 return out;
406 }
407
EXEC_FUNCS()408 std::ostream &OCamlGotoCodeGen::EXEC_FUNCS()
409 {
410 /* Make labels that set acts and jump to execFuncs. Loop func indicies. */
411 for ( GenActionTableMap::Iter redAct = redFsm->actionMap; redAct.lte(); redAct++ ) {
412 if ( redAct->numTransRefs > 0 ) {
413 out << " and f" << redAct->actListId << " () = " <<
414 "state.acts <- " << itoa( redAct->location+1 ) << "; "
415 "execFuncs ()\n";
416 }
417 }
418
419 out <<
420 "\n"
421 "and execFuncs () =\n"
422 " state.nacts <- " << AT( A(), POST_INCR( "state.acts") ) << ";\n"
423 " begin try while " << POST_DECR("state.nacts") << " > 0 do\n"
424 " match " << AT( A(), POST_INCR("state.acts") ) << " with\n";
425 ACTION_SWITCH();
426 SWITCH_DEFAULT() <<
427 " done with Goto_again -> () end;\n"
428 " do_again ()\n";
429 return out;
430 }
431
TO_STATE_ACTION(RedStateAp * state)432 unsigned int OCamlGotoCodeGen::TO_STATE_ACTION( RedStateAp *state )
433 {
434 int act = 0;
435 if ( state->toStateAction != 0 )
436 act = state->toStateAction->location+1;
437 return act;
438 }
439
FROM_STATE_ACTION(RedStateAp * state)440 unsigned int OCamlGotoCodeGen::FROM_STATE_ACTION( RedStateAp *state )
441 {
442 int act = 0;
443 if ( state->fromStateAction != 0 )
444 act = state->fromStateAction->location+1;
445 return act;
446 }
447
EOF_ACTION(RedStateAp * state)448 unsigned int OCamlGotoCodeGen::EOF_ACTION( RedStateAp *state )
449 {
450 int act = 0;
451 if ( state->eofAction != 0 )
452 act = state->eofAction->location+1;
453 return act;
454 }
455
TO_STATE_ACTIONS()456 std::ostream &OCamlGotoCodeGen::TO_STATE_ACTIONS()
457 {
458 /* Take one off for the psuedo start state. */
459 int numStates = redFsm->stateList.length();
460 unsigned int *vals = new unsigned int[numStates];
461 memset( vals, 0, sizeof(unsigned int)*numStates );
462
463 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
464 vals[st->id] = TO_STATE_ACTION(st);
465
466 out << "\t";
467 for ( int st = 0; st < redFsm->nextStateId; st++ ) {
468 /* Write any eof action. */
469 out << vals[st];
470 if ( st < numStates-1 ) {
471 out << ARR_SEP();
472 if ( (st+1) % IALL == 0 )
473 out << "\n\t";
474 }
475 }
476 out << "\n";
477 delete[] vals;
478 return out;
479 }
480
FROM_STATE_ACTIONS()481 std::ostream &OCamlGotoCodeGen::FROM_STATE_ACTIONS()
482 {
483 /* Take one off for the psuedo start state. */
484 int numStates = redFsm->stateList.length();
485 unsigned int *vals = new unsigned int[numStates];
486 memset( vals, 0, sizeof(unsigned int)*numStates );
487
488 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
489 vals[st->id] = FROM_STATE_ACTION(st);
490
491 out << "\t";
492 for ( int st = 0; st < redFsm->nextStateId; st++ ) {
493 /* Write any eof action. */
494 out << vals[st];
495 if ( st < numStates-1 ) {
496 out << ARR_SEP();
497 if ( (st+1) % IALL == 0 )
498 out << "\n\t";
499 }
500 }
501 out << "\n";
502 delete[] vals;
503 return out;
504 }
505
EOF_ACTIONS()506 std::ostream &OCamlGotoCodeGen::EOF_ACTIONS()
507 {
508 /* Take one off for the psuedo start state. */
509 int numStates = redFsm->stateList.length();
510 unsigned int *vals = new unsigned int[numStates];
511 memset( vals, 0, sizeof(unsigned int)*numStates );
512
513 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
514 vals[st->id] = EOF_ACTION(st);
515
516 out << "\t";
517 for ( int st = 0; st < redFsm->nextStateId; st++ ) {
518 /* Write any eof action. */
519 out << vals[st];
520 if ( st < numStates-1 ) {
521 out << ARR_SEP();
522 if ( (st+1) % IALL == 0 )
523 out << "\n\t";
524 }
525 }
526 out << "\n";
527 delete[] vals;
528 return out;
529 }
530
FINISH_CASES()531 std::ostream &OCamlGotoCodeGen::FINISH_CASES()
532 {
533 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
534 /* States that are final and have an out action need a case. */
535 if ( st->eofAction != 0 ) {
536 /* Write the case label. */
537 out << "\t\t| " << st->id << " -> ";
538
539 /* Write the goto func. */
540 out << "f" << st->eofAction->actListId << " ()\n";
541 }
542 }
543
544 return out;
545 }
546
GOTO(ostream & ret,int gotoDest,bool inFinish)547 void OCamlGotoCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
548 {
549 ret << "begin " << vCS() << " <- " << gotoDest << "; " <<
550 CTRL_FLOW() << "raise Goto_again end";
551 }
552
GOTO_EXPR(ostream & ret,GenInlineItem * ilItem,bool inFinish)553 void OCamlGotoCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
554 {
555 ret << "begin " << vCS() << " <- (";
556 INLINE_LIST( ret, ilItem->children, 0, inFinish );
557 ret << "); " << CTRL_FLOW() << "raise Goto_again end";
558 }
559
CURS(ostream & ret,bool inFinish)560 void OCamlGotoCodeGen::CURS( ostream &ret, bool inFinish )
561 {
562 ret << "(_ps)";
563 }
564
TARGS(ostream & ret,bool inFinish,int targState)565 void OCamlGotoCodeGen::TARGS( ostream &ret, bool inFinish, int targState )
566 {
567 ret << "(" << vCS() << ")";
568 }
569
NEXT(ostream & ret,int nextDest,bool inFinish)570 void OCamlGotoCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
571 {
572 ret << vCS() << " <- " << nextDest << ";";
573 }
574
NEXT_EXPR(ostream & ret,GenInlineItem * ilItem,bool inFinish)575 void OCamlGotoCodeGen::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
576 {
577 ret << vCS() << " <- (";
578 INLINE_LIST( ret, ilItem->children, 0, inFinish );
579 ret << ");";
580 }
581
CALL(ostream & ret,int callDest,int targState,bool inFinish)582 void OCamlGotoCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
583 {
584 if ( prePushExpr != 0 ) {
585 ret << "begin ";
586 INLINE_LIST( ret, prePushExpr, 0, false );
587 }
588
589 ret << "begin " << AT( STACK(), POST_INCR(TOP()) ) << " <- " << vCS() << "; ";
590 ret << vCS() << " <- " << callDest << "; " << CTRL_FLOW() << "raise Goto_again end ";
591
592 if ( prePushExpr != 0 )
593 ret << "end";
594 }
595
CALL_EXPR(ostream & ret,GenInlineItem * ilItem,int targState,bool inFinish)596 void OCamlGotoCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish )
597 {
598 if ( prePushExpr != 0 ) {
599 ret << "begin ";
600 INLINE_LIST( ret, prePushExpr, 0, false );
601 }
602
603 ret << "begin " << AT(STACK(), POST_INCR(TOP()) ) << " <- " << vCS() << "; " << vCS() << " <- (";
604 INLINE_LIST( ret, ilItem->children, targState, inFinish );
605 ret << "); " << CTRL_FLOW() << "raise Goto_again end ";
606
607 if ( prePushExpr != 0 )
608 ret << "end";
609 }
610
RET(ostream & ret,bool inFinish)611 void OCamlGotoCodeGen::RET( ostream &ret, bool inFinish )
612 {
613 ret << "begin " << vCS() << " <- " << AT(STACK(), PRE_DECR(TOP()) ) << "; ";
614
615 if ( postPopExpr != 0 ) {
616 ret << "begin ";
617 INLINE_LIST( ret, postPopExpr, 0, false );
618 ret << "end ";
619 }
620
621 ret << CTRL_FLOW() << "raise Goto_again end";
622 }
623
BREAK(ostream & ret,int targState)624 void OCamlGotoCodeGen::BREAK( ostream &ret, int targState )
625 {
626 outLabelUsed = true;
627 ret << "begin " << P() << " <- " << P() << " + 1; " << CTRL_FLOW() << "raise Goto_out end";
628 }
629
writeData()630 void OCamlGotoCodeGen::writeData()
631 {
632 if ( redFsm->anyActions() ) {
633 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActArrItem), A() );
634 ACTIONS_ARRAY();
635 CLOSE_ARRAY() <<
636 "\n";
637 }
638
639 if ( redFsm->anyToStateActions() ) {
640 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), TSA() );
641 TO_STATE_ACTIONS();
642 CLOSE_ARRAY() <<
643 "\n";
644 }
645
646 if ( redFsm->anyFromStateActions() ) {
647 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), FSA() );
648 FROM_STATE_ACTIONS();
649 CLOSE_ARRAY() <<
650 "\n";
651 }
652
653 if ( redFsm->anyEofActions() ) {
654 OPEN_ARRAY( ARRAY_TYPE(redFsm->maxActionLoc), EA() );
655 EOF_ACTIONS();
656 CLOSE_ARRAY() <<
657 "\n";
658 }
659
660 STATE_IDS();
661
662 out << "type " << TYPE_STATE() << " = { mutable acts : " << ARRAY_TYPE(redFsm->maxActionLoc) <<
663 " ; mutable nacts : " << ARRAY_TYPE(redFsm->maxActArrItem) << "; }"
664 << TOP_SEP();
665
666 out << "exception Goto_again" << TOP_SEP();
667 }
668
writeExec()669 void OCamlGotoCodeGen::writeExec()
670 {
671 testEofUsed = false;
672 outLabelUsed = false;
673
674 out << " begin\n";
675
676 // if ( redFsm->anyRegCurStateRef() )
677 // out << " int _ps = 0;\n";
678
679 if ( redFsm->anyToStateActions() || redFsm->anyRegActions()
680 || redFsm->anyFromStateActions() )
681 {
682 out << " let state = { acts = 0; nacts = 0; } in\n";
683 }
684
685 // if ( redFsm->anyConditions() )
686 // out << " " << WIDE_ALPH_TYPE() << " _widec;\n";
687
688 out << "\n";
689 out << " let rec do_start () =\n";
690
691 if ( !noEnd ) {
692 testEofUsed = true;
693 out <<
694 " if " << P() << " = " << PE() << " then\n"
695 " do_test_eof ()\n"
696 "\telse\n";
697 }
698
699 if ( redFsm->errState != 0 ) {
700 outLabelUsed = true;
701 out <<
702 " if " << vCS() << " = " << redFsm->errState->id << " then\n"
703 " do_out ()\n"
704 "\telse\n";
705 }
706 out << "\tdo_resume ()\n";
707
708 out << "and do_resume () =\n";
709
710 if ( redFsm->anyFromStateActions() ) {
711 out <<
712 " state.acts <- " << AT( FSA(), vCS() ) << ";\n"
713 " state.nacts <- " << AT( A(), POST_INCR("state.acts") ) << ";\n"
714 " while " << POST_DECR("state.nacts") << " > 0 do\n"
715 " begin match " << AT( A(), POST_INCR("state.acts") ) << " with\n";
716 FROM_STATE_ACTION_SWITCH();
717 SWITCH_DEFAULT() <<
718 " end\n"
719 " done;\n"
720 "\n";
721 }
722
723 out <<
724 " begin match " << vCS() << " with\n";
725 STATE_GOTOS();
726 SWITCH_DEFAULT() <<
727 " end\n"
728 "\n";
729 TRANSITIONS() <<
730 "\n";
731
732 if ( redFsm->anyRegActions() )
733 EXEC_FUNCS() << "\n";
734
735 // if ( redFsm->anyRegActions() || redFsm->anyActionGotos() ||
736 // redFsm->anyActionCalls() || redFsm->anyActionRets() )
737 out << "\tand do_again () =\n";
738
739 if ( redFsm->anyToStateActions() ) {
740 out <<
741 " state.acts <- " << AT( TSA(), vCS() ) << ";\n"
742 " state.nacts <- " << AT( A(), POST_INCR("state.acts") ) << ";\n"
743 " while " << POST_DECR("state.nacts") << " > 0 do\n"
744 " begin match " << AT( A(), POST_INCR("state.acts") ) << " with\n";
745 TO_STATE_ACTION_SWITCH();
746 SWITCH_DEFAULT() <<
747 " end\n"
748 " done;\n"
749 "\n";
750 }
751
752 if ( redFsm->errState != 0 ) {
753 outLabelUsed = true;
754 out <<
755 " match " << vCS() << " with\n"
756 "\t| " << redFsm->errState->id << " -> do_out ()\n"
757 "\t| _ ->\n";
758 }
759
760 out << "\t" << P() << " <- " << P() << " + 1;\n";
761
762 if ( !noEnd ) {
763 out <<
764 " if " << P() << " <> " << PE() << " then\n"
765 " do_resume ()\n"
766 "\telse do_test_eof ()\n";
767 }
768 else {
769 out <<
770 " do_resume ()\n";
771 }
772
773 // if ( testEofUsed )
774 out << "and do_test_eof () =\n";
775
776 if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
777 out <<
778 " if " << P() << " = " << vEOF() << " then\n"
779 " begin\n";
780
781 if ( redFsm->anyEofTrans() ) {
782 out <<
783 " match " << vCS() << " with\n";
784
785 for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
786 if ( st->eofTrans != 0 )
787 out << " | " << st->id << " -> tr" << st->eofTrans->id << " ()\n";
788 }
789
790 out << "\t| _ -> ();\n";
791 }
792
793 if ( redFsm->anyEofActions() ) {
794 out <<
795 " let __acts = ref " << AT( EA(), vCS() ) << " in\n"
796 " let __nacts = ref " << AT( A(), "!__acts" ) << " in\n"
797 " incr __acts;\n"
798 " begin try while !__nacts > 0 do\n"
799 " decr __nacts;\n"
800 " begin match " << AT( A(), POST_INCR("__acts.contents") ) << " with\n";
801 EOF_ACTION_SWITCH();
802 SWITCH_DEFAULT() <<
803 " end;\n"
804 " done with Goto_again -> do_again () end;\n";
805 }
806
807 out <<
808 " end\n"
809 "\n";
810 }
811 else
812 {
813 out << "\t()\n";
814 }
815
816 if ( outLabelUsed )
817 out << " and do_out () = ()\n";
818
819 out << "\tin do_start ()\n";
820 out << " end;\n";
821 }
822