fsmbase.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602
  1. /*
  2. * Copyright 2001-2007 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 <string.h>
  21. #include <assert.h>
  22. #include "fsmgraph.h"
  23. /* Simple singly linked list append routine for the fill list. The new state
  24. * goes to the end of the list. */
  25. void MergeData::fillListAppend( StateAp *state )
  26. {
  27. state->alg.next = 0;
  28. if ( stfillHead == 0 ) {
  29. /* List is empty, state becomes head and tail. */
  30. stfillHead = state;
  31. stfillTail = state;
  32. }
  33. else {
  34. /* List is not empty, state goes after last element. */
  35. stfillTail->alg.next = state;
  36. stfillTail = state;
  37. }
  38. }
  39. /* Graph constructor. */
  40. FsmAp::FsmAp()
  41. :
  42. /* No start state. */
  43. startState(0),
  44. errState(0),
  45. /* Misfit accounting is a switch, turned on only at specific times. It
  46. * controls what happens when states have no way in from the outside
  47. * world.. */
  48. misfitAccounting(false)
  49. {
  50. }
  51. /* Copy all graph data including transitions. */
  52. FsmAp::FsmAp( const FsmAp &graph )
  53. :
  54. /* Lists start empty. Will be filled by copy. */
  55. stateList(),
  56. misfitList(),
  57. /* Copy in the entry points,
  58. * pointers will be resolved later. */
  59. entryPoints(graph.entryPoints),
  60. startState(graph.startState),
  61. errState(0),
  62. /* Will be filled by copy. */
  63. finStateSet(),
  64. /* Misfit accounting is only on during merging. */
  65. misfitAccounting(false)
  66. {
  67. /* Create the states and record their map in the original state. */
  68. StateList::Iter origState = graph.stateList;
  69. for ( ; origState.lte(); origState++ ) {
  70. /* Make the new state. */
  71. StateAp *newState = new StateAp( *origState );
  72. /* Add the state to the list. */
  73. stateList.append( newState );
  74. /* Set the mapsTo item of the old state. */
  75. origState->alg.stateMap = newState;
  76. }
  77. /* Derefernce all the state maps. */
  78. for ( StateList::Iter state = stateList; state.lte(); state++ ) {
  79. for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) {
  80. /* The points to the original in the src machine. The taget's duplicate
  81. * is in the statemap. */
  82. StateAp *toState = trans->toState != 0 ? trans->toState->alg.stateMap : 0;
  83. /* Attach The transition to the duplicate. */
  84. trans->toState = 0;
  85. attachTrans( state, toState, trans );
  86. }
  87. /* Fix the eofTarg, if set. */
  88. if ( state->eofTarget != 0 )
  89. state->eofTarget = state->eofTarget->alg.stateMap;
  90. }
  91. /* Fix the state pointers in the entry points array. */
  92. EntryMapEl *eel = entryPoints.data;
  93. for ( int e = 0; e < entryPoints.length(); e++, eel++ ) {
  94. /* Get the duplicate of the state. */
  95. eel->value = eel->value->alg.stateMap;
  96. /* Foreign in transitions must be built up when duping machines so
  97. * increment it here. */
  98. eel->value->foreignInTrans += 1;
  99. }
  100. /* Fix the start state pointer and the new start state's count of in
  101. * transiions. */
  102. startState = startState->alg.stateMap;
  103. startState->foreignInTrans += 1;
  104. /* Build the final state set. */
  105. StateSet::Iter st = graph.finStateSet;
  106. for ( ; st.lte(); st++ )
  107. finStateSet.insert((*st)->alg.stateMap);
  108. }
  109. /* Deletes all transition data then deletes each state. */
  110. FsmAp::~FsmAp()
  111. {
  112. /* Delete all the transitions. */
  113. for ( StateList::Iter state = stateList; state.lte(); state++ ) {
  114. /* Iterate the out transitions, deleting them. */
  115. state->outList.empty();
  116. }
  117. /* Delete all the states. */
  118. stateList.empty();
  119. }
  120. /* Set a state final. The state has its isFinState set to true and the state
  121. * is added to the finStateSet. */
  122. void FsmAp::setFinState( StateAp *state )
  123. {
  124. /* Is it already a fin state. */
  125. if ( state->stateBits & STB_ISFINAL )
  126. return;
  127. state->stateBits |= STB_ISFINAL;
  128. finStateSet.insert( state );
  129. }
  130. /* Set a state non-final. The has its isFinState flag set false and the state
  131. * is removed from the final state set. */
  132. void FsmAp::unsetFinState( StateAp *state )
  133. {
  134. /* Is it already a non-final state? */
  135. if ( ! (state->stateBits & STB_ISFINAL) )
  136. return;
  137. /* When a state looses its final state status it must relinquish all the
  138. * properties that are allowed only for final states. */
  139. clearOutData( state );
  140. state->stateBits &= ~ STB_ISFINAL;
  141. finStateSet.remove( state );
  142. }
  143. /* Set and unset a state as the start state. */
  144. void FsmAp::setStartState( StateAp *state )
  145. {
  146. /* Sould change from unset to set. */
  147. assert( startState == 0 );
  148. startState = state;
  149. if ( misfitAccounting ) {
  150. /* If the number of foreign in transitions is about to go up to 1 then
  151. * take it off the misfit list and put it on the head list. */
  152. if ( state->foreignInTrans == 0 )
  153. stateList.append( misfitList.detach( state ) );
  154. }
  155. /* Up the foreign in transitions to the state. */
  156. state->foreignInTrans += 1;
  157. }
  158. void FsmAp::unsetStartState()
  159. {
  160. /* Should change from set to unset. */
  161. assert( startState != 0 );
  162. /* Decrement the entry's count of foreign entries. */
  163. startState->foreignInTrans -= 1;
  164. if ( misfitAccounting ) {
  165. /* If the number of foreign in transitions just went down to 0 then take
  166. * it off the main list and put it on the misfit list. */
  167. if ( startState->foreignInTrans == 0 )
  168. misfitList.append( stateList.detach( startState ) );
  169. }
  170. startState = 0;
  171. }
  172. /* Associate an id with a state. Makes the state a named entry point. Has no
  173. * effect if the entry point is already mapped to the state. */
  174. void FsmAp::setEntry( int id, StateAp *state )
  175. {
  176. /* Insert the id into the state. If the state is already labelled with id,
  177. * nothing to do. */
  178. if ( state->entryIds.insert( id ) ) {
  179. /* Insert the entry and assert that it succeeds. */
  180. entryPoints.insertMulti( id, state );
  181. if ( misfitAccounting ) {
  182. /* If the number of foreign in transitions is about to go up to 1 then
  183. * take it off the misfit list and put it on the head list. */
  184. if ( state->foreignInTrans == 0 )
  185. stateList.append( misfitList.detach( state ) );
  186. }
  187. /* Up the foreign in transitions to the state. */
  188. state->foreignInTrans += 1;
  189. }
  190. }
  191. /* Remove the association of an id with a state. The state looses it's entry
  192. * point status. Assumes that the id is indeed mapped to state. */
  193. void FsmAp::unsetEntry( int id, StateAp *state )
  194. {
  195. /* Find the entry point in on id. */
  196. EntryMapEl *enLow = 0, *enHigh = 0;
  197. entryPoints.findMulti( id, enLow, enHigh );
  198. while ( enLow->value != state )
  199. enLow += 1;
  200. /* Remove the record from the map. */
  201. entryPoints.remove( enLow );
  202. /* Remove the state's sense of the link. */
  203. state->entryIds.remove( id );
  204. state->foreignInTrans -= 1;
  205. if ( misfitAccounting ) {
  206. /* If the number of foreign in transitions just went down to 0 then take
  207. * it off the main list and put it on the misfit list. */
  208. if ( state->foreignInTrans == 0 )
  209. misfitList.append( stateList.detach( state ) );
  210. }
  211. }
  212. /* Remove all association of an id with states. Assumes that the id is indeed
  213. * mapped to a state. */
  214. void FsmAp::unsetEntry( int id )
  215. {
  216. /* Find the entry point in on id. */
  217. EntryMapEl *enLow = 0, *enHigh = 0;
  218. entryPoints.findMulti( id, enLow, enHigh );
  219. for ( EntryMapEl *mel = enLow; mel <= enHigh; mel++ ) {
  220. /* Remove the state's sense of the link. */
  221. mel->value->entryIds.remove( id );
  222. mel->value->foreignInTrans -= 1;
  223. if ( misfitAccounting ) {
  224. /* If the number of foreign in transitions just went down to 0
  225. * then take it off the main list and put it on the misfit list. */
  226. if ( mel->value->foreignInTrans == 0 )
  227. misfitList.append( stateList.detach( mel->value ) );
  228. }
  229. }
  230. /* Remove the records from the entry points map. */
  231. entryPoints.removeMulti( enLow, enHigh );
  232. }
  233. void FsmAp::changeEntry( int id, StateAp *to, StateAp *from )
  234. {
  235. /* Find the entry in the entry map. */
  236. EntryMapEl *enLow = 0, *enHigh = 0;
  237. entryPoints.findMulti( id, enLow, enHigh );
  238. while ( enLow->value != from )
  239. enLow += 1;
  240. /* Change it to the new target. */
  241. enLow->value = to;
  242. /* Remove from's sense of the link. */
  243. from->entryIds.remove( id );
  244. from->foreignInTrans -= 1;
  245. if ( misfitAccounting ) {
  246. /* If the number of foreign in transitions just went down to 0 then take
  247. * it off the main list and put it on the misfit list. */
  248. if ( from->foreignInTrans == 0 )
  249. misfitList.append( stateList.detach( from ) );
  250. }
  251. /* Add to's sense of the link. */
  252. if ( to->entryIds.insert( id ) != 0 ) {
  253. if ( misfitAccounting ) {
  254. /* If the number of foreign in transitions is about to go up to 1 then
  255. * take it off the misfit list and put it on the head list. */
  256. if ( to->foreignInTrans == 0 )
  257. stateList.append( misfitList.detach( to ) );
  258. }
  259. /* Up the foreign in transitions to the state. */
  260. to->foreignInTrans += 1;
  261. }
  262. }
  263. /* Clear all entry points from a machine. */
  264. void FsmAp::unsetAllEntryPoints()
  265. {
  266. for ( EntryMap::Iter en = entryPoints; en.lte(); en++ ) {
  267. /* Kill all the state's entry points at once. */
  268. if ( en->value->entryIds.length() > 0 ) {
  269. en->value->foreignInTrans -= en->value->entryIds.length();
  270. if ( misfitAccounting ) {
  271. /* If the number of foreign in transitions just went down to 0
  272. * then take it off the main list and put it on the misfit
  273. * list. */
  274. if ( en->value->foreignInTrans == 0 )
  275. misfitList.append( stateList.detach( en->value ) );
  276. }
  277. /* Clear the set of ids out all at once. */
  278. en->value->entryIds.empty();
  279. }
  280. }
  281. /* Now clear out the entry map all at once. */
  282. entryPoints.empty();
  283. }
  284. /* Assigning an epsilon transition into final states. */
  285. void FsmAp::epsilonTrans( int id )
  286. {
  287. for ( StateSet::Iter fs = finStateSet; fs.lte(); fs++ )
  288. (*fs)->epsilonTrans.append( id );
  289. }
  290. /* Mark all states reachable from state. Traverses transitions forward. Used
  291. * for removing states that have no path into them. */
  292. void FsmAp::markReachableFromHere( StateAp *state )
  293. {
  294. /* Base case: return; */
  295. if ( state->stateBits & STB_ISMARKED )
  296. return;
  297. /* Set this state as processed. We are going to visit all states that this
  298. * state has a transition to. */
  299. state->stateBits |= STB_ISMARKED;
  300. /* Recurse on all out transitions. */
  301. for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) {
  302. if ( trans->toState != 0 )
  303. markReachableFromHere( trans->toState );
  304. }
  305. }
  306. void FsmAp::markReachableFromHereStopFinal( StateAp *state )
  307. {
  308. /* Base case: return; */
  309. if ( state->stateBits & STB_ISMARKED )
  310. return;
  311. /* Set this state as processed. We are going to visit all states that this
  312. * state has a transition to. */
  313. state->stateBits |= STB_ISMARKED;
  314. /* Recurse on all out transitions. */
  315. for ( TransList::Iter trans = state->outList; trans.lte(); trans++ ) {
  316. StateAp *toState = trans->toState;
  317. if ( toState != 0 && !toState->isFinState() )
  318. markReachableFromHereStopFinal( toState );
  319. }
  320. }
  321. /* Mark all states reachable from state. Traverse transitions backwards. Used
  322. * for removing dead end paths in graphs. */
  323. void FsmAp::markReachableFromHereReverse( StateAp *state )
  324. {
  325. /* Base case: return; */
  326. if ( state->stateBits & STB_ISMARKED )
  327. return;
  328. /* Set this state as processed. We are going to visit all states with
  329. * transitions into this state. */
  330. state->stateBits |= STB_ISMARKED;
  331. /* Recurse on all items in transitions. */
  332. for ( TransInList::Iter trans = state->inList; trans.lte(); trans++ )
  333. markReachableFromHereReverse( trans->fromState );
  334. }
  335. /* Determine if there are any entry points into a start state other than the
  336. * start state. Setting starting transitions requires that the start state be
  337. * isolated. In most cases a start state will already be isolated. */
  338. bool FsmAp::isStartStateIsolated()
  339. {
  340. /* If there are any in transitions then the state is not isolated. */
  341. if ( startState->inList.head != 0 )
  342. return false;
  343. /* If there are any entry points then isolated. */
  344. if ( startState->entryIds.length() > 0 )
  345. return false;
  346. return true;
  347. }
  348. /* Bring in other's entry points. Assumes others states are going to be
  349. * copied into this machine. */
  350. void FsmAp::copyInEntryPoints( FsmAp *other )
  351. {
  352. /* Use insert multi because names are not unique. */
  353. for ( EntryMap::Iter en = other->entryPoints; en.lte(); en++ )
  354. entryPoints.insertMulti( en->key, en->value );
  355. }
  356. void FsmAp::unsetAllFinStates()
  357. {
  358. for ( StateSet::Iter st = finStateSet; st.lte(); st++ )
  359. (*st)->stateBits &= ~ STB_ISFINAL;
  360. finStateSet.empty();
  361. }
  362. void FsmAp::setFinBits( int finStateBits )
  363. {
  364. for ( int s = 0; s < finStateSet.length(); s++ )
  365. finStateSet.data[s]->stateBits |= finStateBits;
  366. }
  367. /* Tests the integrity of the transition lists and the fromStates. */
  368. void FsmAp::verifyIntegrity()
  369. {
  370. for ( StateList::Iter state = stateList; state.lte(); state++ ) {
  371. /* Walk the out transitions and assert fromState is correct. */
  372. for ( TransList::Iter trans = state->outList; trans.lte(); trans++ )
  373. assert( trans->fromState == state );
  374. /* Walk the inlist and assert toState is correct. */
  375. for ( TransInList::Iter trans = state->inList; trans.lte(); trans++ )
  376. assert( trans->toState == state );
  377. }
  378. }
  379. void FsmAp::verifyReachability()
  380. {
  381. /* Mark all the states that can be reached
  382. * through the set of entry points. */
  383. markReachableFromHere( startState );
  384. for ( EntryMap::Iter en = entryPoints; en.lte(); en++ )
  385. markReachableFromHere( en->value );
  386. /* Check that everything got marked. */
  387. for ( StateList::Iter st = stateList; st.lte(); st++ ) {
  388. /* Assert it got marked and then clear the mark. */
  389. assert( st->stateBits & STB_ISMARKED );
  390. st->stateBits &= ~ STB_ISMARKED;
  391. }
  392. }
  393. void FsmAp::verifyNoDeadEndStates()
  394. {
  395. /* Mark all states that have paths to the final states. */
  396. for ( StateSet::Iter pst = finStateSet; pst.lte(); pst++ )
  397. markReachableFromHereReverse( *pst );
  398. /* Start state gets honorary marking. Must be done AFTER recursive call. */
  399. startState->stateBits |= STB_ISMARKED;
  400. /* Make sure everything got marked. */
  401. for ( StateList::Iter st = stateList; st.lte(); st++ ) {
  402. /* Assert the state got marked and unmark it. */
  403. assert( st->stateBits & STB_ISMARKED );
  404. st->stateBits &= ~ STB_ISMARKED;
  405. }
  406. }
  407. void FsmAp::depthFirstOrdering( StateAp *state )
  408. {
  409. /* Nothing to do if the state is already on the list. */
  410. if ( state->stateBits & STB_ONLIST )
  411. return;
  412. /* Doing depth first, put state on the list. */
  413. state->stateBits |= STB_ONLIST;
  414. stateList.append( state );
  415. /* Recurse on everything ranges. */
  416. for ( TransList::Iter tel = state->outList; tel.lte(); tel++ ) {
  417. if ( tel->toState != 0 )
  418. depthFirstOrdering( tel->toState );
  419. }
  420. }
  421. /* Ordering states by transition connections. */
  422. void FsmAp::depthFirstOrdering()
  423. {
  424. /* Init on state list flags. */
  425. for ( StateList::Iter st = stateList; st.lte(); st++ )
  426. st->stateBits &= ~STB_ONLIST;
  427. /* Clear out the state list, we will rebuild it. */
  428. int stateListLen = stateList.length();
  429. stateList.abandon();
  430. /* Add back to the state list from the start state and all other entry
  431. * points. */
  432. if ( errState != 0 )
  433. depthFirstOrdering( errState );
  434. depthFirstOrdering( startState );
  435. for ( EntryMap::Iter en = entryPoints; en.lte(); en++ )
  436. depthFirstOrdering( en->value );
  437. /* Make sure we put everything back on. */
  438. assert( stateListLen == stateList.length() );
  439. }
  440. /* Stable sort the states by final state status. */
  441. void FsmAp::sortStatesByFinal()
  442. {
  443. /* Move forward through the list and throw final states onto the end. */
  444. StateAp *state = 0;
  445. StateAp *next = stateList.head;
  446. StateAp *last = stateList.tail;
  447. while ( state != last ) {
  448. /* Move forward and load up the next. */
  449. state = next;
  450. next = state->next;
  451. /* Throw to the end? */
  452. if ( state->isFinState() ) {
  453. stateList.detach( state );
  454. stateList.append( state );
  455. }
  456. }
  457. }
  458. void FsmAp::setStateNumbers( int base )
  459. {
  460. for ( StateList::Iter state = stateList; state.lte(); state++ )
  461. state->alg.stateNum = base++;
  462. }
  463. bool FsmAp::checkErrTrans( StateAp *state, TransAp *trans )
  464. {
  465. /* Might go directly to error state. */
  466. if ( trans->toState == 0 )
  467. return true;
  468. if ( trans->prev == 0 ) {
  469. /* If this is the first transition. */
  470. if ( keyOps->minKey < trans->lowKey )
  471. return true;
  472. }
  473. else {
  474. /* Not the first transition. Compare against the prev. */
  475. TransAp *prev = trans->prev;
  476. Key nextKey = prev->highKey;
  477. nextKey.increment();
  478. if ( nextKey < trans->lowKey )
  479. return true;
  480. }
  481. return false;
  482. }
  483. bool FsmAp::checkErrTransFinish( StateAp *state )
  484. {
  485. /* Check if there are any ranges already. */
  486. if ( state->outList.length() == 0 )
  487. return true;
  488. else {
  489. /* Get the last and check for a gap on the end. */
  490. TransAp *last = state->outList.tail;
  491. if ( last->highKey < keyOps->maxKey )
  492. return true;
  493. }
  494. return 0;
  495. }
  496. bool FsmAp::hasErrorTrans()
  497. {
  498. bool result;
  499. for ( StateList::Iter st = stateList; st.lte(); st++ ) {
  500. for ( TransList::Iter tr = st->outList; tr.lte(); tr++ ) {
  501. result = checkErrTrans( st, tr );
  502. if ( result )
  503. return true;
  504. }
  505. result = checkErrTransFinish( st );
  506. if ( result )
  507. return true;
  508. }
  509. return false;
  510. }