mlgoto.cpp 23 KB

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