csipgoto.cpp 11 KB

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