goipgoto.cpp 13 KB

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