fsmattach.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. /*
  2. * Copyright 2001 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. #include <iostream>
  24. using namespace std;
  25. /* Insert a transition into an inlist. The head must be supplied. */
  26. void FsmAp::attachToInList( StateAp *from, StateAp *to,
  27. TransAp *&head, TransAp *trans )
  28. {
  29. trans->ilnext = head;
  30. trans->ilprev = 0;
  31. /* If in trans list is not empty, set the head->prev to trans. */
  32. if ( head != 0 )
  33. head->ilprev = trans;
  34. /* Now insert ourselves at the front of the list. */
  35. head = trans;
  36. /* Keep track of foreign transitions for from and to. */
  37. if ( from != to ) {
  38. if ( misfitAccounting ) {
  39. /* If the number of foreign in transitions is about to go up to 1 then
  40. * move it from the misfit list to the main list. */
  41. if ( to->foreignInTrans == 0 )
  42. stateList.append( misfitList.detach( to ) );
  43. }
  44. to->foreignInTrans += 1;
  45. }
  46. };
  47. /* Detach a transition from an inlist. The head of the inlist must be supplied. */
  48. void FsmAp::detachFromInList( StateAp *from, StateAp *to,
  49. TransAp *&head, TransAp *trans )
  50. {
  51. /* Detach in the inTransList. */
  52. if ( trans->ilprev == 0 )
  53. head = trans->ilnext;
  54. else
  55. trans->ilprev->ilnext = trans->ilnext;
  56. if ( trans->ilnext != 0 )
  57. trans->ilnext->ilprev = trans->ilprev;
  58. /* Keep track of foreign transitions for from and to. */
  59. if ( from != to ) {
  60. to->foreignInTrans -= 1;
  61. if ( misfitAccounting ) {
  62. /* If the number of foreign in transitions goes down to 0 then move it
  63. * from the main list to the misfit list. */
  64. if ( to->foreignInTrans == 0 )
  65. misfitList.append( stateList.detach( to ) );
  66. }
  67. }
  68. }
  69. /* Attach states on the default transition, range list or on out/in list key.
  70. * First makes a new transition. If there is already a transition out from
  71. * fromState on the default, then will assertion fail. */
  72. TransAp *FsmAp::attachNewTrans( StateAp *from, StateAp *to, Key lowKey, Key highKey )
  73. {
  74. /* Make the new transition. */
  75. TransAp *retVal = new TransAp();
  76. /* The transition is now attached. Remember the parties involved. */
  77. retVal->fromState = from;
  78. retVal->toState = to;
  79. /* Make the entry in the out list for the transitions. */
  80. from->outList.append( retVal );
  81. /* Set the the keys of the new trans. */
  82. retVal->lowKey = lowKey;
  83. retVal->highKey = highKey;
  84. /* Attach using inList as the head pointer. */
  85. if ( to != 0 )
  86. attachToInList( from, to, to->inList.head, retVal );
  87. return retVal;
  88. }
  89. /* Attach for range lists or for the default transition. This attach should
  90. * be used when a transition already is allocated and must be attached to a
  91. * target state. Does not handle adding the transition into the out list. */
  92. void FsmAp::attachTrans( StateAp *from, StateAp *to, TransAp *trans )
  93. {
  94. assert( trans->fromState == 0 && trans->toState == 0 );
  95. trans->fromState = from;
  96. trans->toState = to;
  97. if ( to != 0 ) {
  98. /* Attach using the inList pointer as the head pointer. */
  99. attachToInList( from, to, to->inList.head, trans );
  100. }
  101. }
  102. /* Redirect a transition away from error and towards some state. This is just
  103. * like attachTrans except it requires fromState to be set and does not touch
  104. * it. */
  105. void FsmAp::redirectErrorTrans( StateAp *from, StateAp *to, TransAp *trans )
  106. {
  107. assert( trans->fromState != 0 && trans->toState == 0 );
  108. trans->toState = to;
  109. if ( to != 0 ) {
  110. /* Attach using the inList pointer as the head pointer. */
  111. attachToInList( from, to, to->inList.head, trans );
  112. }
  113. }
  114. /* Detach for out/in lists or for default transition. */
  115. void FsmAp::detachTrans( StateAp *from, StateAp *to, TransAp *trans )
  116. {
  117. assert( trans->fromState == from && trans->toState == to );
  118. trans->fromState = 0;
  119. trans->toState = 0;
  120. if ( to != 0 ) {
  121. /* Detach using to's inList pointer as the head. */
  122. detachFromInList( from, to, to->inList.head, trans );
  123. }
  124. }
  125. /* Detach a state from the graph. Detaches and deletes transitions in and out
  126. * of the state. Empties inList and outList. Removes the state from the final
  127. * state set. A detached state becomes useless and should be deleted. */
  128. void FsmAp::detachState( StateAp *state )
  129. {
  130. /* Detach the in transitions from the inList list of transitions. */
  131. while ( state->inList.head != 0 ) {
  132. /* Get pointers to the trans and the state. */
  133. TransAp *trans = state->inList.head;
  134. StateAp *fromState = trans->fromState;
  135. /* Detach the transitions from the source state. */
  136. detachTrans( fromState, state, trans );
  137. /* Ok to delete the transition. */
  138. fromState->outList.detach( trans );
  139. delete trans;
  140. }
  141. /* Remove the entry points in on the machine. */
  142. while ( state->entryIds.length() > 0 )
  143. unsetEntry( state->entryIds[0], state );
  144. /* Detach out range transitions. */
  145. for ( TransList::Iter trans = state->outList; trans.lte(); ) {
  146. TransList::Iter next = trans.next();
  147. detachTrans( state, trans->toState, trans );
  148. delete trans;
  149. trans = next;
  150. }
  151. /* Delete all of the out range pointers. */
  152. state->outList.abandon();
  153. /* Unset final stateness before detaching from graph. */
  154. if ( state->stateBits & STB_ISFINAL )
  155. finStateSet.remove( state );
  156. }
  157. /* Duplicate a transition. Makes a new transition that is attached to the same
  158. * dest as srcTrans. The new transition has functions and priority taken from
  159. * srcTrans. Used for merging a transition in to a free spot. The trans can
  160. * just be dropped in. It does not conflict with an existing trans and need
  161. * not be crossed. Returns the new transition. */
  162. TransAp *FsmAp::dupTrans( StateAp *from, TransAp *srcTrans )
  163. {
  164. /* Make a new transition. */
  165. TransAp *newTrans = new TransAp();
  166. /* We can attach the transition, one does not exist. */
  167. attachTrans( from, srcTrans->toState, newTrans );
  168. /* Call the user callback to add in the original source transition. */
  169. addInTrans( newTrans, srcTrans );
  170. return newTrans;
  171. }
  172. /* In crossing, src trans and dest trans both go to existing states. Make one
  173. * state from the sets of states that src and dest trans go to. */
  174. TransAp *FsmAp::fsmAttachStates( MergeData &md, StateAp *from,
  175. TransAp *destTrans, TransAp *srcTrans )
  176. {
  177. /* The priorities are equal. We must merge the transitions. Does the
  178. * existing trans go to the state we are to attach to? ie, are we to
  179. * simply double up the transition? */
  180. StateAp *toState = srcTrans->toState;
  181. StateAp *existingState = destTrans->toState;
  182. if ( existingState == toState ) {
  183. /* The transition is a double up to the same state. Copy the src
  184. * trans into itself. We don't need to merge in the from out trans
  185. * data, that was done already. */
  186. addInTrans( destTrans, srcTrans );
  187. }
  188. else {
  189. /* The trans is not a double up. Dest trans cannot be the same as src
  190. * trans. Set up the state set. */
  191. StateSet stateSet;
  192. /* We go to all the states the existing trans goes to, plus... */
  193. if ( existingState->stateDictEl == 0 )
  194. stateSet.insert( existingState );
  195. else
  196. stateSet.insert( existingState->stateDictEl->stateSet );
  197. /* ... all the states that we have been told to go to. */
  198. if ( toState->stateDictEl == 0 )
  199. stateSet.insert( toState );
  200. else
  201. stateSet.insert( toState->stateDictEl->stateSet );
  202. /* Look for the state. If it is not there already, make it. */
  203. StateDictEl *lastFound;
  204. if ( md.stateDict.insert( stateSet, &lastFound ) ) {
  205. /* Make a new state representing the combination of states in
  206. * stateSet. It gets added to the fill list. This means that we
  207. * need to fill in it's transitions sometime in the future. We
  208. * don't do that now (ie, do not recurse). */
  209. StateAp *combinState = addState();
  210. /* Link up the dict element and the state. */
  211. lastFound->targState = combinState;
  212. combinState->stateDictEl = lastFound;
  213. /* Add to the fill list. */
  214. md.fillListAppend( combinState );
  215. }
  216. /* Get the state insertted/deleted. */
  217. StateAp *targ = lastFound->targState;
  218. /* Detach the state from existing state. */
  219. detachTrans( from, existingState, destTrans );
  220. /* Re-attach to the new target. */
  221. attachTrans( from, targ, destTrans );
  222. /* Add in src trans to the existing transition that we redirected to
  223. * the new state. We don't need to merge in the from out trans data,
  224. * that was done already. */
  225. addInTrans( destTrans, srcTrans );
  226. }
  227. return destTrans;
  228. }
  229. /* Two transitions are to be crossed, handle the possibility of either going
  230. * to the error state. */
  231. TransAp *FsmAp::mergeTrans( MergeData &md, StateAp *from,
  232. TransAp *destTrans, TransAp *srcTrans )
  233. {
  234. TransAp *retTrans = 0;
  235. if ( destTrans->toState == 0 && srcTrans->toState == 0 ) {
  236. /* Error added into error. */
  237. addInTrans( destTrans, srcTrans );
  238. retTrans = destTrans;
  239. }
  240. else if ( destTrans->toState == 0 && srcTrans->toState != 0 ) {
  241. /* Non error added into error we need to detach and reattach, */
  242. detachTrans( from, destTrans->toState, destTrans );
  243. attachTrans( from, srcTrans->toState, destTrans );
  244. addInTrans( destTrans, srcTrans );
  245. retTrans = destTrans;
  246. }
  247. else if ( srcTrans->toState == 0 ) {
  248. /* Dest goes somewhere but src doesn't, just add it it in. */
  249. addInTrans( destTrans, srcTrans );
  250. retTrans = destTrans;
  251. }
  252. else {
  253. /* Both go somewhere, run the actual cross. */
  254. retTrans = fsmAttachStates( md, from, destTrans, srcTrans );
  255. }
  256. return retTrans;
  257. }
  258. /* Find the trans with the higher priority. If src is lower priority then dest then
  259. * src is ignored. If src is higher priority than dest, then src overwrites dest. If
  260. * the priorities are equal, then they are merged. */
  261. TransAp *FsmAp::crossTransitions( MergeData &md, StateAp *from,
  262. TransAp *destTrans, TransAp *srcTrans )
  263. {
  264. TransAp *retTrans;
  265. /* Compare the priority of the dest and src transitions. */
  266. int compareRes = comparePrior( destTrans->priorTable, srcTrans->priorTable );
  267. if ( compareRes < 0 ) {
  268. /* Src trans has a higher priority than dest, src overwrites dest.
  269. * Detach dest and return a copy of src. */
  270. detachTrans( from, destTrans->toState, destTrans );
  271. retTrans = dupTrans( from, srcTrans );
  272. }
  273. else if ( compareRes > 0 ) {
  274. /* The dest trans has a higher priority, use dest. */
  275. retTrans = destTrans;
  276. }
  277. else {
  278. /* Src trans and dest trans have the same priority, they must be merged. */
  279. retTrans = mergeTrans( md, from, destTrans, srcTrans );
  280. }
  281. /* Return the transition that resulted from the cross. */
  282. return retTrans;
  283. }
  284. /* Copy the transitions in srcList to the outlist of dest. The srcList should
  285. * not be the outList of dest, otherwise you would be copying the contents of
  286. * srcList into itself as it's iterated: bad news. */
  287. void FsmAp::outTransCopy( MergeData &md, StateAp *dest, TransAp *srcList )
  288. {
  289. /* The destination list. */
  290. TransList destList;
  291. /* Set up an iterator to stop at breaks. */
  292. PairIter<TransAp> outPair( dest->outList.head, srcList );
  293. for ( ; !outPair.end(); outPair++ ) {
  294. switch ( outPair.userState ) {
  295. case RangeInS1: {
  296. /* The pair iter is the authority on the keys. It may have needed
  297. * to break the dest range. */
  298. TransAp *destTrans = outPair.s1Tel.trans;
  299. destTrans->lowKey = outPair.s1Tel.lowKey;
  300. destTrans->highKey = outPair.s1Tel.highKey;
  301. destList.append( destTrans );
  302. break;
  303. }
  304. case RangeInS2: {
  305. /* Src range may get crossed with dest's default transition. */
  306. TransAp *newTrans = dupTrans( dest, outPair.s2Tel.trans );
  307. /* Set up the transition's keys and append to the dest list. */
  308. newTrans->lowKey = outPair.s2Tel.lowKey;
  309. newTrans->highKey = outPair.s2Tel.highKey;
  310. destList.append( newTrans );
  311. break;
  312. }
  313. case RangeOverlap: {
  314. /* Exact overlap, cross them. */
  315. TransAp *newTrans = crossTransitions( md, dest,
  316. outPair.s1Tel.trans, outPair.s2Tel.trans );
  317. /* Set up the transition's keys and append to the dest list. */
  318. newTrans->lowKey = outPair.s1Tel.lowKey;
  319. newTrans->highKey = outPair.s1Tel.highKey;
  320. destList.append( newTrans );
  321. break;
  322. }
  323. case BreakS1: {
  324. /* Since we are always writing to the dest trans, the dest needs
  325. * to be copied when it is broken. The copy goes into the first
  326. * half of the break to "break it off". */
  327. outPair.s1Tel.trans = dupTrans( dest, outPair.s1Tel.trans );
  328. break;
  329. }
  330. case BreakS2:
  331. break;
  332. }
  333. }
  334. /* Abandon the old outList and transfer destList into it. */
  335. dest->outList.transfer( destList );
  336. }
  337. /* Move all the transitions that go into src so that they go into dest. */
  338. void FsmAp::inTransMove( StateAp *dest, StateAp *src )
  339. {
  340. /* Do not try to move in trans to and from the same state. */
  341. assert( dest != src );
  342. /* If src is the start state, dest becomes the start state. */
  343. if ( src == startState ) {
  344. unsetStartState();
  345. setStartState( dest );
  346. }
  347. /* For each entry point into, create an entry point into dest, when the
  348. * state is detached, the entry points to src will be removed. */
  349. for ( EntryIdSet::Iter enId = src->entryIds; enId.lte(); enId++ )
  350. changeEntry( *enId, dest, src );
  351. /* Move the transitions in inList. */
  352. while ( src->inList.head != 0 ) {
  353. /* Get trans and from state. */
  354. TransAp *trans = src->inList.head;
  355. StateAp *fromState = trans->fromState;
  356. /* Detach from src, reattach to dest. */
  357. detachTrans( fromState, src, trans );
  358. attachTrans( fromState, dest, trans );
  359. }
  360. }