cdipgoto.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  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 "cdipgoto.h"
  24. #include "redfsm.h"
  25. #include "gendata.h"
  26. #include "bstmap.h"
  27. bool IpGotoCodeGen::useAgainLabel()
  28. {
  29. return redFsm->anyActionRets() ||
  30. redFsm->anyActionByValControl() ||
  31. redFsm->anyRegNextStmt();
  32. }
  33. void IpGotoCodeGen::EOF_CHECK( ostream &ret, int gotoDest )
  34. {
  35. ret <<
  36. " if ( " << P() << " == " << PE() << " )\n"
  37. " goto _test_eof" << gotoDest << ";\n";
  38. testEofUsed = true;
  39. }
  40. void IpGotoCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
  41. {
  42. ret << "{";
  43. if ( inFinish && !noEnd )
  44. EOF_CHECK( ret, gotoDest );
  45. ret << CTRL_FLOW() << "goto st" << gotoDest << ";";
  46. ret << "}";
  47. }
  48. void IpGotoCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
  49. {
  50. if ( prePushExpr != 0 ) {
  51. ret << "{";
  52. INLINE_LIST( ret, prePushExpr, 0, false, false );
  53. }
  54. ret << "{" << STACK() << "[" << TOP() << "++] = " << targState << ";";
  55. if ( inFinish && !noEnd )
  56. EOF_CHECK( ret, callDest );
  57. ret << CTRL_FLOW() << "goto st" << callDest << ";";
  58. ret << "}";
  59. if ( prePushExpr != 0 )
  60. ret << "}";
  61. }
  62. void IpGotoCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState, bool inFinish )
  63. {
  64. if ( prePushExpr != 0 ) {
  65. ret << "{";
  66. INLINE_LIST( ret, prePushExpr, 0, false, false );
  67. }
  68. ret << "{";
  69. ret << STACK() << "[" << TOP() << "++] = " << targState << "; " << vCS() << " = (";
  70. INLINE_LIST( ret, ilItem->children, 0, inFinish, false );
  71. ret << ");";
  72. if ( inFinish && !noEnd )
  73. FsmCodeGen::EOF_CHECK( ret );
  74. ret << CTRL_FLOW() << "goto _again;";
  75. ret << "}";
  76. if ( prePushExpr != 0 )
  77. ret << "}";
  78. }
  79. void IpGotoCodeGen::RET( ostream &ret, bool inFinish )
  80. {
  81. ret << "{" << vCS() << " = " << STACK() << "[--" << TOP() << "];";
  82. if ( postPopExpr != 0 ) {
  83. ret << "{";
  84. INLINE_LIST( ret, postPopExpr, 0, false, false );
  85. ret << "}";
  86. }
  87. if ( inFinish && !noEnd )
  88. FsmCodeGen::EOF_CHECK( ret );
  89. ret << CTRL_FLOW() << "goto _again;";
  90. ret << "}";
  91. }
  92. void IpGotoCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
  93. {
  94. ret << "{";
  95. ret << vCS() << " = (";
  96. INLINE_LIST( ret, ilItem->children, 0, inFinish, false );
  97. ret << ");";
  98. if ( inFinish && !noEnd )
  99. FsmCodeGen::EOF_CHECK( ret );
  100. ret << CTRL_FLOW() << "goto _again;";
  101. ret << "}";
  102. }
  103. void IpGotoCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
  104. {
  105. ret << vCS() << " = " << nextDest << ";";
  106. }
  107. void IpGotoCodeGen::NEXT_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
  108. {
  109. ret << vCS() << " = (";
  110. INLINE_LIST( ret, ilItem->children, 0, inFinish, false );
  111. ret << ");";
  112. }
  113. void IpGotoCodeGen::CURS( ostream &ret, bool inFinish )
  114. {
  115. ret << "(_ps)";
  116. }
  117. void IpGotoCodeGen::TARGS( ostream &ret, bool inFinish, int targState )
  118. {
  119. ret << targState;
  120. }
  121. void IpGotoCodeGen::BREAK( ostream &ret, int targState, bool csForced )
  122. {
  123. outLabelUsed = true;
  124. ret << "{" << P() << "++; ";
  125. if ( !csForced )
  126. ret << vCS() << " = " << targState << "; ";
  127. ret << CTRL_FLOW() << "goto _out;}";
  128. }
  129. bool IpGotoCodeGen::IN_TRANS_ACTIONS( RedStateAp *state )
  130. {
  131. bool anyWritten = false;
  132. /* Emit any transitions that have actions and that go to this state. */
  133. for ( int it = 0; it < state->numInTrans; it++ ) {
  134. RedTransAp *trans = state->inTrans[it];
  135. if ( trans->action != 0 && trans->labelNeeded ) {
  136. /* Remember that we wrote an action so we know to write the
  137. * line directive for going back to the output. */
  138. anyWritten = true;
  139. /* Write the label for the transition so it can be jumped to. */
  140. out << "tr" << trans->id << ":\n";
  141. /* If the action contains a next, then we must preload the current
  142. * state since the action may or may not set it. */
  143. if ( trans->action->anyNextStmt() )
  144. out << " " << vCS() << " = " << trans->targ->id << ";\n";
  145. /* Write each action in the list. */
  146. for ( GenActionTable::Iter item = trans->action->key; item.lte(); item++ ) {
  147. ACTION( out, item->value, trans->targ->id, false,
  148. trans->action->anyNextStmt() );
  149. }
  150. /* If the action contains a next then we need to reload, otherwise
  151. * jump directly to the target state. */
  152. if ( trans->action->anyNextStmt() )
  153. out << "\tgoto _again;\n";
  154. else
  155. out << "\tgoto st" << trans->targ->id << ";\n";
  156. }
  157. }
  158. return anyWritten;
  159. }
  160. /* Called from GotoCodeGen::STATE_GOTOS just before writing the gotos for each
  161. * state. */
  162. void IpGotoCodeGen::GOTO_HEADER( RedStateAp *state )
  163. {
  164. bool anyWritten = IN_TRANS_ACTIONS( state );
  165. if ( state->labelNeeded )
  166. out << "st" << state->id << ":\n";
  167. if ( state->toStateAction != 0 ) {
  168. /* Remember that we wrote an action. Write every action in the list. */
  169. anyWritten = true;
  170. for ( GenActionTable::Iter item = state->toStateAction->key; item.lte(); item++ ) {
  171. ACTION( out, item->value, state->id, false,
  172. state->toStateAction->anyNextStmt() );
  173. }
  174. }
  175. /* Advance and test buffer pos. */
  176. if ( state->labelNeeded ) {
  177. if ( !noEnd ) {
  178. out <<
  179. " if ( ++" << P() << " == " << PE() << " )\n"
  180. " goto _test_eof" << state->id << ";\n";
  181. }
  182. else {
  183. out <<
  184. " " << P() << " += 1;\n";
  185. }
  186. }
  187. /* Give the state a switch case. */
  188. out << "case " << state->id << ":\n";
  189. if ( state->fromStateAction != 0 ) {
  190. /* Remember that we wrote an action. Write every action in the list. */
  191. anyWritten = true;
  192. for ( GenActionTable::Iter item = state->fromStateAction->key; item.lte(); item++ ) {
  193. ACTION( out, item->value, state->id, false,
  194. state->fromStateAction->anyNextStmt() );
  195. }
  196. }
  197. if ( anyWritten )
  198. genLineDirective( out );
  199. /* Record the prev state if necessary. */
  200. if ( state->anyRegCurStateRef() )
  201. out << " _ps = " << state->id << ";\n";
  202. }
  203. void IpGotoCodeGen::STATE_GOTO_ERROR()
  204. {
  205. /* In the error state we need to emit some stuff that usually goes into
  206. * the header. */
  207. RedStateAp *state = redFsm->errState;
  208. bool anyWritten = IN_TRANS_ACTIONS( state );
  209. /* No case label needed since we don't switch on the error state. */
  210. if ( anyWritten )
  211. genLineDirective( out );
  212. if ( state->labelNeeded )
  213. out << "st" << state->id << ":\n";
  214. /* Break out here. */
  215. outLabelUsed = true;
  216. out << vCS() << " = " << state->id << ";\n";
  217. out << " goto _out;\n";
  218. }
  219. /* Emit the goto to take for a given transition. */
  220. std::ostream &IpGotoCodeGen::TRANS_GOTO( RedTransAp *trans, int level )
  221. {
  222. if ( trans->action != 0 ) {
  223. /* Go to the transition which will go to the state. */
  224. out << TABS(level) << "goto tr" << trans->id << ";";
  225. }
  226. else {
  227. /* Go directly to the target state. */
  228. out << TABS(level) << "goto st" << trans->targ->id << ";";
  229. }
  230. return out;
  231. }
  232. std::ostream &IpGotoCodeGen::EXIT_STATES()
  233. {
  234. for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
  235. if ( st->outNeeded ) {
  236. testEofUsed = true;
  237. out << " _test_eof" << st->id << ": " << vCS() << " = " <<
  238. st->id << "; goto _test_eof;\n";
  239. }
  240. }
  241. return out;
  242. }
  243. std::ostream &IpGotoCodeGen::AGAIN_CASES()
  244. {
  245. for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
  246. out <<
  247. " case " << st->id << ": goto st" << st->id << ";\n";
  248. }
  249. return out;
  250. }
  251. std::ostream &IpGotoCodeGen::FINISH_CASES()
  252. {
  253. bool anyWritten = false;
  254. for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
  255. if ( st->eofAction != 0 ) {
  256. if ( st->eofAction->eofRefs == 0 )
  257. st->eofAction->eofRefs = new IntSet;
  258. st->eofAction->eofRefs->insert( st->id );
  259. }
  260. }
  261. for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
  262. if ( st->eofTrans != 0 )
  263. out << " case " << st->id << ": goto tr" << st->eofTrans->id << ";\n";
  264. }
  265. for ( GenActionTableMap::Iter act = redFsm->actionMap; act.lte(); act++ ) {
  266. if ( act->eofRefs != 0 ) {
  267. for ( IntSet::Iter pst = *act->eofRefs; pst.lte(); pst++ )
  268. out << " case " << *pst << ": \n";
  269. /* Remember that we wrote a trans so we know to write the
  270. * line directive for going back to the output. */
  271. anyWritten = true;
  272. /* Write each action in the eof action list. */
  273. for ( GenActionTable::Iter item = act->key; item.lte(); item++ )
  274. ACTION( out, item->value, STATE_ERR_STATE, true, false );
  275. out << "\tbreak;\n";
  276. }
  277. }
  278. if ( anyWritten )
  279. genLineDirective( out );
  280. return out;
  281. }
  282. void IpGotoCodeGen::setLabelsNeeded( GenInlineList *inlineList )
  283. {
  284. for ( GenInlineList::Iter item = *inlineList; item.lte(); item++ ) {
  285. switch ( item->type ) {
  286. case GenInlineItem::Goto: case GenInlineItem::Call: {
  287. /* Mark the target as needing a label. */
  288. item->targState->labelNeeded = true;
  289. break;
  290. }
  291. default: break;
  292. }
  293. if ( item->children != 0 )
  294. setLabelsNeeded( item->children );
  295. }
  296. }
  297. /* Set up labelNeeded flag for each state. */
  298. void IpGotoCodeGen::setLabelsNeeded()
  299. {
  300. /* If we use the _again label, then we the _again switch, which uses all
  301. * labels. */
  302. if ( useAgainLabel() ) {
  303. for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
  304. st->labelNeeded = true;
  305. }
  306. else {
  307. /* Do not use all labels by default, init all labelNeeded vars to false. */
  308. for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ )
  309. st->labelNeeded = false;
  310. /* Walk all transitions and set only those that have targs. */
  311. for ( TransApSet::Iter trans = redFsm->transSet; trans.lte(); trans++ ) {
  312. /* If there is no action with a next statement, then the label will be
  313. * needed. */
  314. if ( trans->action == 0 || !trans->action->anyNextStmt() )
  315. trans->targ->labelNeeded = true;
  316. /* Need labels for states that have goto or calls in action code
  317. * invoked on characters (ie, not from out action code). */
  318. if ( trans->action != 0 ) {
  319. /* Loop the actions. */
  320. for ( GenActionTable::Iter act = trans->action->key; act.lte(); act++ ) {
  321. /* Get the action and walk it's tree. */
  322. setLabelsNeeded( act->value->inlineList );
  323. }
  324. }
  325. }
  326. for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
  327. if ( st->eofAction != 0 ) {
  328. for ( GenActionTable::Iter item = st->eofAction->key; item.lte(); item++ )
  329. setLabelsNeeded( item->value->inlineList );
  330. }
  331. }
  332. }
  333. if ( !noEnd ) {
  334. for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
  335. if ( st != redFsm->errState )
  336. st->outNeeded = st->labelNeeded;
  337. }
  338. }
  339. }
  340. void IpGotoCodeGen::writeData()
  341. {
  342. STATE_IDS();
  343. }
  344. void IpGotoCodeGen::writeExec()
  345. {
  346. /* Must set labels immediately before writing because we may depend on the
  347. * noend write option. */
  348. setLabelsNeeded();
  349. testEofUsed = false;
  350. outLabelUsed = false;
  351. out << " {\n";
  352. if ( redFsm->anyRegCurStateRef() )
  353. out << " int _ps = 0;\n";
  354. if ( redFsm->anyConditions() )
  355. out << " " << WIDE_ALPH_TYPE() << " _widec;\n";
  356. if ( !noEnd ) {
  357. testEofUsed = true;
  358. out <<
  359. " if ( " << P() << " == " << PE() << " )\n"
  360. " goto _test_eof;\n";
  361. }
  362. if ( useAgainLabel() ) {
  363. out <<
  364. " goto _resume;\n"
  365. "\n"
  366. "_again:\n"
  367. " switch ( " << vCS() << " ) {\n";
  368. AGAIN_CASES() <<
  369. " default: break;\n"
  370. " }\n"
  371. "\n";
  372. if ( !noEnd ) {
  373. testEofUsed = true;
  374. out <<
  375. " if ( ++" << P() << " == " << PE() << " )\n"
  376. " goto _test_eof;\n";
  377. }
  378. else {
  379. out <<
  380. " " << P() << " += 1;\n";
  381. }
  382. out << "_resume:\n";
  383. }
  384. out <<
  385. " switch ( " << vCS() << " )\n {\n";
  386. STATE_GOTOS();
  387. SWITCH_DEFAULT() <<
  388. " }\n";
  389. EXIT_STATES() <<
  390. "\n";
  391. if ( testEofUsed )
  392. out << " _test_eof: {}\n";
  393. if ( redFsm->anyEofTrans() || redFsm->anyEofActions() ) {
  394. out <<
  395. " if ( " << P() << " == " << vEOF() << " )\n"
  396. " {\n"
  397. " switch ( " << vCS() << " ) {\n";
  398. FINISH_CASES();
  399. SWITCH_DEFAULT() <<
  400. " }\n"
  401. " }\n"
  402. "\n";
  403. }
  404. if ( outLabelUsed )
  405. out << " _out: {}\n";
  406. out <<
  407. " }\n";
  408. }