redfsm.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  1. /*
  2. * Copyright 2001-2006 Adrian Thurston <thurston@complang.org>
  3. */
  4. /* This file is part of Ragel.
  5. *
  6. * Ragel is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Ragel is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Ragel; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19. */
  20. #include "redfsm.h"
  21. #include "avlmap.h"
  22. #include "mergesort.h"
  23. #include <iostream>
  24. #include <sstream>
  25. using std::ostringstream;
  26. string GenAction::nameOrLoc()
  27. {
  28. if ( name != 0 )
  29. return string(name);
  30. else {
  31. ostringstream ret;
  32. ret << loc.line << ":" << loc.col;
  33. return ret.str();
  34. }
  35. }
  36. RedFsmAp::RedFsmAp()
  37. :
  38. forcedErrorState(false),
  39. nextActionId(0),
  40. nextTransId(0),
  41. startState(0),
  42. errState(0),
  43. errTrans(0),
  44. firstFinState(0),
  45. numFinStates(0),
  46. bAnyToStateActions(false),
  47. bAnyFromStateActions(false),
  48. bAnyRegActions(false),
  49. bAnyEofActions(false),
  50. bAnyEofTrans(false),
  51. bAnyActionGotos(false),
  52. bAnyActionCalls(false),
  53. bAnyActionRets(false),
  54. bAnyActionByValControl(false),
  55. bAnyRegActionRets(false),
  56. bAnyRegActionByValControl(false),
  57. bAnyRegNextStmt(false),
  58. bAnyRegCurStateRef(false),
  59. bAnyRegBreak(false),
  60. bAnyConditions(false)
  61. {
  62. }
  63. /* Does the machine have any actions. */
  64. bool RedFsmAp::anyActions()
  65. {
  66. return actionMap.length() > 0;
  67. }
  68. void RedFsmAp::depthFirstOrdering( RedStateAp *state )
  69. {
  70. /* Nothing to do if the state is already on the list. */
  71. if ( state->onStateList )
  72. return;
  73. /* Doing depth first, put state on the list. */
  74. state->onStateList = true;
  75. stateList.append( state );
  76. /* At this point transitions should only be in ranges. */
  77. assert( state->outSingle.length() == 0 );
  78. assert( state->defTrans == 0 );
  79. /* Recurse on everything ranges. */
  80. for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) {
  81. if ( rtel->value->targ != 0 )
  82. depthFirstOrdering( rtel->value->targ );
  83. }
  84. }
  85. /* Ordering states by transition connections. */
  86. void RedFsmAp::depthFirstOrdering()
  87. {
  88. /* Init on state list flags. */
  89. for ( RedStateList::Iter st = stateList; st.lte(); st++ )
  90. st->onStateList = false;
  91. /* Clear out the state list, we will rebuild it. */
  92. int stateListLen = stateList.length();
  93. stateList.abandon();
  94. /* Add back to the state list from the start state and all other entry
  95. * points. */
  96. if ( startState != 0 )
  97. depthFirstOrdering( startState );
  98. for ( RedStateSet::Iter en = entryPoints; en.lte(); en++ )
  99. depthFirstOrdering( *en );
  100. if ( forcedErrorState )
  101. depthFirstOrdering( errState );
  102. /* Make sure we put everything back on. */
  103. assert( stateListLen == stateList.length() );
  104. }
  105. /* Assign state ids by appearance in the state list. */
  106. void RedFsmAp::sequentialStateIds()
  107. {
  108. /* Table based machines depend on the state numbers starting at zero. */
  109. nextStateId = 0;
  110. for ( RedStateList::Iter st = stateList; st.lte(); st++ )
  111. st->id = nextStateId++;
  112. }
  113. /* Stable sort the states by final state status. */
  114. void RedFsmAp::sortStatesByFinal()
  115. {
  116. /* Move forward through the list and throw final states onto the end. */
  117. RedStateAp *state = 0;
  118. RedStateAp *next = stateList.head;
  119. RedStateAp *last = stateList.tail;
  120. while ( state != last ) {
  121. /* Move forward and load up the next. */
  122. state = next;
  123. next = state->next;
  124. /* Throw to the end? */
  125. if ( state->isFinal ) {
  126. stateList.detach( state );
  127. stateList.append( state );
  128. }
  129. }
  130. }
  131. /* Assign state ids by final state state status. */
  132. void RedFsmAp::sortStateIdsByFinal()
  133. {
  134. /* Table based machines depend on this starting at zero. */
  135. nextStateId = 0;
  136. /* First pass to assign non final ids. */
  137. for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
  138. if ( ! st->isFinal )
  139. st->id = nextStateId++;
  140. }
  141. /* Second pass to assign final ids. */
  142. for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
  143. if ( st->isFinal )
  144. st->id = nextStateId++;
  145. }
  146. }
  147. struct CmpStateById
  148. {
  149. static int compare( RedStateAp *st1, RedStateAp *st2 )
  150. {
  151. if ( st1->id < st2->id )
  152. return -1;
  153. else if ( st1->id > st2->id )
  154. return 1;
  155. else
  156. return 0;
  157. }
  158. };
  159. void RedFsmAp::sortByStateId()
  160. {
  161. /* Make the array. */
  162. int pos = 0;
  163. RedStateAp **ptrList = new RedStateAp*[stateList.length()];
  164. for ( RedStateList::Iter st = stateList; st.lte(); st++, pos++ )
  165. ptrList[pos] = st;
  166. MergeSort<RedStateAp*, CmpStateById> mergeSort;
  167. mergeSort.sort( ptrList, stateList.length() );
  168. stateList.abandon();
  169. for ( int st = 0; st < pos; st++ )
  170. stateList.append( ptrList[st] );
  171. delete[] ptrList;
  172. }
  173. /* Find the final state with the lowest id. */
  174. void RedFsmAp::findFirstFinState()
  175. {
  176. for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
  177. if ( st->isFinal && (firstFinState == 0 || st->id < firstFinState->id) )
  178. firstFinState = st;
  179. }
  180. }
  181. void RedFsmAp::assignActionLocs()
  182. {
  183. int nextLocation = 0;
  184. for ( GenActionTableMap::Iter act = actionMap; act.lte(); act++ ) {
  185. /* Store the loc, skip over the array and a null terminator. */
  186. act->location = nextLocation;
  187. nextLocation += act->key.length() + 1;
  188. }
  189. }
  190. /* Check if we can extend the current range by displacing any ranges
  191. * ahead to the singles. */
  192. bool RedFsmAp::canExtend( const RedTransList &list, int pos )
  193. {
  194. /* Get the transition that we want to extend. */
  195. RedTransAp *extendTrans = list[pos].value;
  196. /* Look ahead in the transition list. */
  197. for ( int next = pos + 1; next < list.length(); pos++, next++ ) {
  198. /* If they are not continuous then cannot extend. */
  199. Key nextKey = list[next].lowKey;
  200. nextKey.decrement();
  201. if ( list[pos].highKey != nextKey )
  202. break;
  203. /* Check for the extenstion property. */
  204. if ( extendTrans == list[next].value )
  205. return true;
  206. /* If the span of the next element is more than one, then don't keep
  207. * checking, it won't be moved to single. */
  208. unsigned long long nextSpan = keyOps->span( list[next].lowKey, list[next].highKey );
  209. if ( nextSpan > 1 )
  210. break;
  211. }
  212. return false;
  213. }
  214. /* Move ranges to the singles list. */
  215. void RedFsmAp::moveTransToSingle( RedStateAp *state )
  216. {
  217. RedTransList &range = state->outRange;
  218. RedTransList &single = state->outSingle;
  219. for ( int rpos = 0; rpos < range.length(); ) {
  220. /* Check if this is a range we can extend. */
  221. if ( canExtend( range, rpos ) ) {
  222. /* Transfer singles over. */
  223. while ( range[rpos].value != range[rpos+1].value ) {
  224. /* Transfer the range to single. */
  225. single.append( range[rpos+1] );
  226. range.remove( rpos+1 );
  227. }
  228. /* Extend. */
  229. range[rpos].highKey = range[rpos+1].highKey;
  230. range.remove( rpos+1 );
  231. }
  232. /* Maybe move it to the singles. */
  233. else if ( keyOps->span( range[rpos].lowKey, range[rpos].highKey ) == 1 ) {
  234. single.append( range[rpos] );
  235. range.remove( rpos );
  236. }
  237. else {
  238. /* Keeping it in the ranges. */
  239. rpos += 1;
  240. }
  241. }
  242. }
  243. /* Look through ranges and choose suitable single character transitions. */
  244. void RedFsmAp::chooseSingle()
  245. {
  246. /* Loop the states. */
  247. for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
  248. /* Rewrite the transition list taking out the suitable single
  249. * transtions. */
  250. moveTransToSingle( st );
  251. }
  252. }
  253. void RedFsmAp::makeFlat()
  254. {
  255. for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
  256. if ( st->stateCondList.length() == 0 ) {
  257. st->condLowKey = 0;
  258. st->condHighKey = 0;
  259. }
  260. else {
  261. st->condLowKey = st->stateCondList.head->lowKey;
  262. st->condHighKey = st->stateCondList.tail->highKey;
  263. unsigned long long span = keyOps->span( st->condLowKey, st->condHighKey );
  264. st->condList = new GenCondSpace*[ span ];
  265. memset( st->condList, 0, sizeof(GenCondSpace*)*span );
  266. for ( GenStateCondList::Iter sci = st->stateCondList; sci.lte(); sci++ ) {
  267. unsigned long long base, trSpan;
  268. base = keyOps->span( st->condLowKey, sci->lowKey )-1;
  269. trSpan = keyOps->span( sci->lowKey, sci->highKey );
  270. for ( unsigned long long pos = 0; pos < trSpan; pos++ )
  271. st->condList[base+pos] = sci->condSpace;
  272. }
  273. }
  274. if ( st->outRange.length() == 0 ) {
  275. st->lowKey = st->highKey = 0;
  276. st->transList = 0;
  277. }
  278. else {
  279. st->lowKey = st->outRange[0].lowKey;
  280. st->highKey = st->outRange[st->outRange.length()-1].highKey;
  281. unsigned long long span = keyOps->span( st->lowKey, st->highKey );
  282. st->transList = new RedTransAp*[ span ];
  283. memset( st->transList, 0, sizeof(RedTransAp*)*span );
  284. for ( RedTransList::Iter trans = st->outRange; trans.lte(); trans++ ) {
  285. unsigned long long base, trSpan;
  286. base = keyOps->span( st->lowKey, trans->lowKey )-1;
  287. trSpan = keyOps->span( trans->lowKey, trans->highKey );
  288. for ( unsigned long long pos = 0; pos < trSpan; pos++ )
  289. st->transList[base+pos] = trans->value;
  290. }
  291. /* Fill in the gaps with the default transition. */
  292. for ( unsigned long long pos = 0; pos < span; pos++ ) {
  293. if ( st->transList[pos] == 0 )
  294. st->transList[pos] = st->defTrans;
  295. }
  296. }
  297. }
  298. }
  299. /* A default transition has been picked, move it from the outRange to the
  300. * default pointer. */
  301. void RedFsmAp::moveToDefault( RedTransAp *defTrans, RedStateAp *state )
  302. {
  303. /* Rewrite the outRange, omitting any ranges that use
  304. * the picked default. */
  305. RedTransList outRange;
  306. for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) {
  307. /* If it does not take the default, copy it over. */
  308. if ( rtel->value != defTrans )
  309. outRange.append( *rtel );
  310. }
  311. /* Save off the range we just created into the state's range. */
  312. state->outRange.transfer( outRange );
  313. /* Store the default. */
  314. state->defTrans = defTrans;
  315. }
  316. bool RedFsmAp::alphabetCovered( RedTransList &outRange )
  317. {
  318. /* Cannot cover without any out ranges. */
  319. if ( outRange.length() == 0 )
  320. return false;
  321. /* If the first range doesn't start at the the lower bound then the
  322. * alphabet is not covered. */
  323. RedTransList::Iter rtel = outRange;
  324. if ( keyOps->minKey < rtel->lowKey )
  325. return false;
  326. /* Check that every range is next to the previous one. */
  327. rtel.increment();
  328. for ( ; rtel.lte(); rtel++ ) {
  329. Key highKey = rtel[-1].highKey;
  330. highKey.increment();
  331. if ( highKey != rtel->lowKey )
  332. return false;
  333. }
  334. /* The last must extend to the upper bound. */
  335. RedTransEl *last = &outRange[outRange.length()-1];
  336. if ( last->highKey < keyOps->maxKey )
  337. return false;
  338. return true;
  339. }
  340. RedTransAp *RedFsmAp::chooseDefaultSpan( RedStateAp *state )
  341. {
  342. /* Make a set of transitions from the outRange. */
  343. RedTransSet stateTransSet;
  344. for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ )
  345. stateTransSet.insert( rtel->value );
  346. /* For each transition in the find how many alphabet characters the
  347. * transition spans. */
  348. unsigned long long *span = new unsigned long long[stateTransSet.length()];
  349. memset( span, 0, sizeof(unsigned long long) * stateTransSet.length() );
  350. for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) {
  351. /* Lookup the transition in the set. */
  352. RedTransAp **inSet = stateTransSet.find( rtel->value );
  353. int pos = inSet - stateTransSet.data;
  354. span[pos] += keyOps->span( rtel->lowKey, rtel->highKey );
  355. }
  356. /* Find the max span, choose it for making the default. */
  357. RedTransAp *maxTrans = 0;
  358. unsigned long long maxSpan = 0;
  359. for ( RedTransSet::Iter rtel = stateTransSet; rtel.lte(); rtel++ ) {
  360. if ( span[rtel.pos()] > maxSpan ) {
  361. maxSpan = span[rtel.pos()];
  362. maxTrans = *rtel;
  363. }
  364. }
  365. delete[] span;
  366. return maxTrans;
  367. }
  368. /* Pick default transitions from ranges for the states. */
  369. void RedFsmAp::chooseDefaultSpan()
  370. {
  371. /* Loop the states. */
  372. for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
  373. /* Only pick a default transition if the alphabet is covered. This
  374. * avoids any transitions in the out range that go to error and avoids
  375. * the need for an ERR state. */
  376. if ( alphabetCovered( st->outRange ) ) {
  377. /* Pick a default transition by largest span. */
  378. RedTransAp *defTrans = chooseDefaultSpan( st );
  379. /* Rewrite the transition list taking out the transition we picked
  380. * as the default and store the default. */
  381. moveToDefault( defTrans, st );
  382. }
  383. }
  384. }
  385. RedTransAp *RedFsmAp::chooseDefaultGoto( RedStateAp *state )
  386. {
  387. /* Make a set of transitions from the outRange. */
  388. RedTransSet stateTransSet;
  389. for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) {
  390. if ( rtel->value->targ == state->next )
  391. return rtel->value;
  392. }
  393. return 0;
  394. }
  395. void RedFsmAp::chooseDefaultGoto()
  396. {
  397. /* Loop the states. */
  398. for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
  399. /* Pick a default transition. */
  400. RedTransAp *defTrans = chooseDefaultGoto( st );
  401. if ( defTrans == 0 )
  402. defTrans = chooseDefaultSpan( st );
  403. /* Rewrite the transition list taking out the transition we picked
  404. * as the default and store the default. */
  405. moveToDefault( defTrans, st );
  406. }
  407. }
  408. RedTransAp *RedFsmAp::chooseDefaultNumRanges( RedStateAp *state )
  409. {
  410. /* Make a set of transitions from the outRange. */
  411. RedTransSet stateTransSet;
  412. for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ )
  413. stateTransSet.insert( rtel->value );
  414. /* For each transition in the find how many ranges use the transition. */
  415. int *numRanges = new int[stateTransSet.length()];
  416. memset( numRanges, 0, sizeof(int) * stateTransSet.length() );
  417. for ( RedTransList::Iter rtel = state->outRange; rtel.lte(); rtel++ ) {
  418. /* Lookup the transition in the set. */
  419. RedTransAp **inSet = stateTransSet.find( rtel->value );
  420. numRanges[inSet - stateTransSet.data] += 1;
  421. }
  422. /* Find the max number of ranges. */
  423. RedTransAp *maxTrans = 0;
  424. int maxNumRanges = 0;
  425. for ( RedTransSet::Iter rtel = stateTransSet; rtel.lte(); rtel++ ) {
  426. if ( numRanges[rtel.pos()] > maxNumRanges ) {
  427. maxNumRanges = numRanges[rtel.pos()];
  428. maxTrans = *rtel;
  429. }
  430. }
  431. delete[] numRanges;
  432. return maxTrans;
  433. }
  434. void RedFsmAp::chooseDefaultNumRanges()
  435. {
  436. /* Loop the states. */
  437. for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
  438. /* Pick a default transition. */
  439. RedTransAp *defTrans = chooseDefaultNumRanges( st );
  440. /* Rewrite the transition list taking out the transition we picked
  441. * as the default and store the default. */
  442. moveToDefault( defTrans, st );
  443. }
  444. }
  445. RedTransAp *RedFsmAp::getErrorTrans( )
  446. {
  447. /* If the error trans has not been made aready, make it. */
  448. if ( errTrans == 0 ) {
  449. /* This insert should always succeed since no transition created by
  450. * the user can point to the error state. */
  451. errTrans = new RedTransAp( getErrorState(), 0, nextTransId++ );
  452. RedTransAp *inRes = transSet.insert( errTrans );
  453. assert( inRes != 0 );
  454. }
  455. return errTrans;
  456. }
  457. RedStateAp *RedFsmAp::getErrorState()
  458. {
  459. /* Something went wrong. An error state is needed but one was not supplied
  460. * by the frontend. */
  461. assert( errState != 0 );
  462. return errState;
  463. }
  464. RedTransAp *RedFsmAp::allocateTrans( RedStateAp *targ, RedAction *action )
  465. {
  466. /* Create a reduced trans and look for it in the transiton set. */
  467. RedTransAp redTrans( targ, action, 0 );
  468. RedTransAp *inDict = transSet.find( &redTrans );
  469. if ( inDict == 0 ) {
  470. inDict = new RedTransAp( targ, action, nextTransId++ );
  471. transSet.insert( inDict );
  472. }
  473. return inDict;
  474. }
  475. void RedFsmAp::partitionFsm( int nparts )
  476. {
  477. /* At this point the states are ordered by a depth-first traversal. We
  478. * will allocate to partitions based on this ordering. */
  479. this->nParts = nparts;
  480. int partSize = stateList.length() / nparts;
  481. int remainder = stateList.length() % nparts;
  482. int numInPart = partSize;
  483. int partition = 0;
  484. if ( remainder-- > 0 )
  485. numInPart += 1;
  486. for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
  487. st->partition = partition;
  488. numInPart -= 1;
  489. if ( numInPart == 0 ) {
  490. partition += 1;
  491. numInPart = partSize;
  492. if ( remainder-- > 0 )
  493. numInPart += 1;
  494. }
  495. }
  496. }
  497. void RedFsmAp::setInTrans()
  498. {
  499. /* First pass counts the number of transitions. */
  500. for ( TransApSet::Iter trans = transSet; trans.lte(); trans++ )
  501. trans->targ->numInTrans += 1;
  502. /* Pass over states to allocate the needed memory. Reset the counts so we
  503. * can use them as the current size. */
  504. for ( RedStateList::Iter st = stateList; st.lte(); st++ ) {
  505. st->inTrans = new RedTransAp*[st->numInTrans];
  506. st->numInTrans = 0;
  507. }
  508. /* Second pass over transitions copies pointers into the in trans list. */
  509. for ( TransApSet::Iter trans = transSet; trans.lte(); trans++ )
  510. trans->targ->inTrans[trans->targ->numInTrans++] = trans;
  511. }