fsmstate.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. /*
  2. * Copyright 2002 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. /* Construct a mark index for a specified number of states. Must new up
  26. * an array that is states^2 in size. */
  27. MarkIndex::MarkIndex( int states ) : numStates(states)
  28. {
  29. /* Total pairs is states^2. Actually only use half of these, but we allocate
  30. * them all to make indexing into the array easier. */
  31. int total = states * states;
  32. /* New up chars so that individual DListEl constructors are
  33. * not called. Zero out the mem manually. */
  34. array = new bool[total];
  35. memset( array, 0, sizeof(bool) * total );
  36. }
  37. /* Free the array used to store state pairs. */
  38. MarkIndex::~MarkIndex()
  39. {
  40. delete[] array;
  41. }
  42. /* Mark a pair of states. States are specified by their number. The
  43. * marked states are moved from the unmarked list to the marked list. */
  44. void MarkIndex::markPair(int state1, int state2)
  45. {
  46. int pos = ( state1 >= state2 ) ?
  47. ( state1 * numStates ) + state2 :
  48. ( state2 * numStates ) + state1;
  49. array[pos] = true;
  50. }
  51. /* Returns true if the pair of states are marked. Returns false otherwise.
  52. * Ordering of states given does not matter. */
  53. bool MarkIndex::isPairMarked(int state1, int state2)
  54. {
  55. int pos = ( state1 >= state2 ) ?
  56. ( state1 * numStates ) + state2 :
  57. ( state2 * numStates ) + state1;
  58. return array[pos];
  59. }
  60. /* Create a new fsm state. State has not out transitions or in transitions, not
  61. * out out transition data and not number. */
  62. StateAp::StateAp()
  63. :
  64. /* No out or in transitions. */
  65. outList(),
  66. inList(),
  67. /* No EOF target. */
  68. eofTarget(0),
  69. /* No entry points, or epsilon trans. */
  70. entryIds(),
  71. epsilonTrans(),
  72. /* Conditions. */
  73. stateCondList(),
  74. /* No transitions in from other states. */
  75. foreignInTrans(0),
  76. /* Only used during merging. Normally null. */
  77. stateDictEl(0),
  78. eptVect(0),
  79. /* No state identification bits. */
  80. stateBits(0),
  81. /* No Priority data. */
  82. outPriorTable(),
  83. /* No Action data. */
  84. toStateActionTable(),
  85. fromStateActionTable(),
  86. outActionTable(),
  87. outCondSet(),
  88. errActionTable(),
  89. eofActionTable()
  90. {
  91. }
  92. /* Copy everything except actual the transitions. That is left up to the
  93. * FsmAp copy constructor. */
  94. StateAp::StateAp(const StateAp &other)
  95. :
  96. /* All lists are cleared. They will be filled in when the
  97. * individual transitions are duplicated and attached. */
  98. outList(),
  99. inList(),
  100. /* Set this using the original state's eofTarget. It will get mapped back
  101. * to the new machine in the Fsm copy constructor. */
  102. eofTarget(other.eofTarget),
  103. /* Duplicate the entry id set and epsilon transitions. These
  104. * are sets of integers and as such need no fixing. */
  105. entryIds(other.entryIds),
  106. epsilonTrans(other.epsilonTrans),
  107. /* Copy in the elements of the conditions. */
  108. stateCondList( other.stateCondList ),
  109. /* No transitions in from other states. */
  110. foreignInTrans(0),
  111. /* This is only used during merging. Normally null. */
  112. stateDictEl(0),
  113. eptVect(0),
  114. /* Fsm state data. */
  115. stateBits(other.stateBits),
  116. /* Copy in priority data. */
  117. outPriorTable(other.outPriorTable),
  118. /* Copy in action data. */
  119. toStateActionTable(other.toStateActionTable),
  120. fromStateActionTable(other.fromStateActionTable),
  121. outActionTable(other.outActionTable),
  122. outCondSet(other.outCondSet),
  123. errActionTable(other.errActionTable),
  124. eofActionTable(other.eofActionTable)
  125. {
  126. /* Duplicate all the transitions. */
  127. for ( TransList::Iter trans = other.outList; trans.lte(); trans++ ) {
  128. /* Dupicate and store the orginal target in the transition. This will
  129. * be corrected once all the states have been created. */
  130. TransAp *newTrans = new TransAp(*trans);
  131. assert( trans->lmActionTable.length() == 0 );
  132. newTrans->toState = trans->toState;
  133. outList.append( newTrans );
  134. }
  135. }
  136. /* If there is a state dict element, then delete it. Everything else is left
  137. * up to the FsmGraph destructor. */
  138. StateAp::~StateAp()
  139. {
  140. if ( stateDictEl != 0 )
  141. delete stateDictEl;
  142. }
  143. /* Compare two states using pointers to the states. With the approximate
  144. * compare, the idea is that if the compare finds them the same, they can
  145. * immediately be merged. */
  146. int ApproxCompare::compare( const StateAp *state1, const StateAp *state2 )
  147. {
  148. int compareRes;
  149. /* Test final state status. */
  150. if ( (state1->stateBits & STB_ISFINAL) && !(state2->stateBits & STB_ISFINAL) )
  151. return -1;
  152. else if ( !(state1->stateBits & STB_ISFINAL) && (state2->stateBits & STB_ISFINAL) )
  153. return 1;
  154. /* Test epsilon transition sets. */
  155. compareRes = CmpEpsilonTrans::compare( state1->epsilonTrans,
  156. state2->epsilonTrans );
  157. if ( compareRes != 0 )
  158. return compareRes;
  159. /* Compare the out transitions. */
  160. compareRes = FsmAp::compareStateData( state1, state2 );
  161. if ( compareRes != 0 )
  162. return compareRes;
  163. /* Use a pair iterator to get the transition pairs. */
  164. PairIter<TransAp> outPair( state1->outList.head, state2->outList.head );
  165. for ( ; !outPair.end(); outPair++ ) {
  166. switch ( outPair.userState ) {
  167. case RangeInS1:
  168. compareRes = FsmAp::compareFullPtr( outPair.s1Tel.trans, 0 );
  169. if ( compareRes != 0 )
  170. return compareRes;
  171. break;
  172. case RangeInS2:
  173. compareRes = FsmAp::compareFullPtr( 0, outPair.s2Tel.trans );
  174. if ( compareRes != 0 )
  175. return compareRes;
  176. break;
  177. case RangeOverlap:
  178. compareRes = FsmAp::compareFullPtr(
  179. outPair.s1Tel.trans, outPair.s2Tel.trans );
  180. if ( compareRes != 0 )
  181. return compareRes;
  182. break;
  183. case BreakS1:
  184. case BreakS2:
  185. break;
  186. }
  187. }
  188. /* Check EOF targets. */
  189. if ( state1->eofTarget < state2->eofTarget )
  190. return -1;
  191. else if ( state1->eofTarget > state2->eofTarget )
  192. return 1;
  193. /* Got through the entire state comparison, deem them equal. */
  194. return 0;
  195. }
  196. /* Compare class used in the initial partition. */
  197. int InitPartitionCompare::compare( const StateAp *state1 , const StateAp *state2 )
  198. {
  199. int compareRes;
  200. /* Test final state status. */
  201. if ( (state1->stateBits & STB_ISFINAL) && !(state2->stateBits & STB_ISFINAL) )
  202. return -1;
  203. else if ( !(state1->stateBits & STB_ISFINAL) && (state2->stateBits & STB_ISFINAL) )
  204. return 1;
  205. /* Test epsilon transition sets. */
  206. compareRes = CmpEpsilonTrans::compare( state1->epsilonTrans,
  207. state2->epsilonTrans );
  208. if ( compareRes != 0 )
  209. return compareRes;
  210. /* Compare the out transitions. */
  211. compareRes = FsmAp::compareStateData( state1, state2 );
  212. if ( compareRes != 0 )
  213. return compareRes;
  214. /* Use a pair iterator to test the condition pairs. */
  215. PairIter<StateCond> condPair( state1->stateCondList.head, state2->stateCondList.head );
  216. for ( ; !condPair.end(); condPair++ ) {
  217. switch ( condPair.userState ) {
  218. case RangeInS1:
  219. return 1;
  220. case RangeInS2:
  221. return -1;
  222. case RangeOverlap: {
  223. CondSpace *condSpace1 = condPair.s1Tel.trans->condSpace;
  224. CondSpace *condSpace2 = condPair.s2Tel.trans->condSpace;
  225. if ( condSpace1 < condSpace2 )
  226. return -1;
  227. else if ( condSpace1 > condSpace2 )
  228. return 1;
  229. break;
  230. }
  231. case BreakS1:
  232. case BreakS2:
  233. break;
  234. }
  235. }
  236. /* Use a pair iterator to test the transition pairs. */
  237. PairIter<TransAp> outPair( state1->outList.head, state2->outList.head );
  238. for ( ; !outPair.end(); outPair++ ) {
  239. switch ( outPair.userState ) {
  240. case RangeInS1:
  241. compareRes = FsmAp::compareDataPtr( outPair.s1Tel.trans, 0 );
  242. if ( compareRes != 0 )
  243. return compareRes;
  244. break;
  245. case RangeInS2:
  246. compareRes = FsmAp::compareDataPtr( 0, outPair.s2Tel.trans );
  247. if ( compareRes != 0 )
  248. return compareRes;
  249. break;
  250. case RangeOverlap:
  251. compareRes = FsmAp::compareDataPtr(
  252. outPair.s1Tel.trans, outPair.s2Tel.trans );
  253. if ( compareRes != 0 )
  254. return compareRes;
  255. break;
  256. case BreakS1:
  257. case BreakS2:
  258. break;
  259. }
  260. }
  261. return 0;
  262. }
  263. /* Compare class for the sort that does the partitioning. */
  264. int PartitionCompare::compare( const StateAp *state1, const StateAp *state2 )
  265. {
  266. int compareRes;
  267. /* Use a pair iterator to get the transition pairs. */
  268. PairIter<TransAp> outPair( state1->outList.head, state2->outList.head );
  269. for ( ; !outPair.end(); outPair++ ) {
  270. switch ( outPair.userState ) {
  271. case RangeInS1:
  272. compareRes = FsmAp::comparePartPtr( outPair.s1Tel.trans, 0 );
  273. if ( compareRes != 0 )
  274. return compareRes;
  275. break;
  276. case RangeInS2:
  277. compareRes = FsmAp::comparePartPtr( 0, outPair.s2Tel.trans );
  278. if ( compareRes != 0 )
  279. return compareRes;
  280. break;
  281. case RangeOverlap:
  282. compareRes = FsmAp::comparePartPtr(
  283. outPair.s1Tel.trans, outPair.s2Tel.trans );
  284. if ( compareRes != 0 )
  285. return compareRes;
  286. break;
  287. case BreakS1:
  288. case BreakS2:
  289. break;
  290. }
  291. }
  292. /* Test eof targets. */
  293. if ( state1->eofTarget == 0 && state2->eofTarget != 0 )
  294. return -1;
  295. else if ( state1->eofTarget != 0 && state2->eofTarget == 0 )
  296. return 1;
  297. else if ( state1->eofTarget != 0 ) {
  298. /* Both eof targets are set. */
  299. compareRes = CmpOrd< MinPartition* >::compare(
  300. state1->eofTarget->alg.partition, state2->eofTarget->alg.partition );
  301. if ( compareRes != 0 )
  302. return compareRes;
  303. }
  304. return 0;
  305. }
  306. /* Compare class for the sort that does the partitioning. */
  307. bool MarkCompare::shouldMark( MarkIndex &markIndex, const StateAp *state1,
  308. const StateAp *state2 )
  309. {
  310. /* Use a pair iterator to get the transition pairs. */
  311. PairIter<TransAp> outPair( state1->outList.head, state2->outList.head );
  312. for ( ; !outPair.end(); outPair++ ) {
  313. switch ( outPair.userState ) {
  314. case RangeInS1:
  315. if ( FsmAp::shouldMarkPtr( markIndex, outPair.s1Tel.trans, 0 ) )
  316. return true;
  317. break;
  318. case RangeInS2:
  319. if ( FsmAp::shouldMarkPtr( markIndex, 0, outPair.s2Tel.trans ) )
  320. return true;
  321. break;
  322. case RangeOverlap:
  323. if ( FsmAp::shouldMarkPtr( markIndex,
  324. outPair.s1Tel.trans, outPair.s2Tel.trans ) )
  325. return true;
  326. break;
  327. case BreakS1:
  328. case BreakS2:
  329. break;
  330. }
  331. }
  332. return false;
  333. }
  334. /*
  335. * Transition Comparison.
  336. */
  337. /* Compare target partitions. Either pointer may be null. */
  338. int FsmAp::comparePartPtr( TransAp *trans1, TransAp *trans2 )
  339. {
  340. if ( trans1 != 0 ) {
  341. /* If trans1 is set then so should trans2. The initial partitioning
  342. * guarantees this for us. */
  343. if ( trans1->toState == 0 && trans2->toState != 0 )
  344. return -1;
  345. else if ( trans1->toState != 0 && trans2->toState == 0 )
  346. return 1;
  347. else if ( trans1->toState != 0 ) {
  348. /* Both of targets are set. */
  349. return CmpOrd< MinPartition* >::compare(
  350. trans1->toState->alg.partition, trans2->toState->alg.partition );
  351. }
  352. }
  353. return 0;
  354. }
  355. /* Compares two transition pointers according to priority and functions.
  356. * Either pointer may be null. Does not consider to state or from state. */
  357. int FsmAp::compareDataPtr( TransAp *trans1, TransAp *trans2 )
  358. {
  359. if ( trans1 == 0 && trans2 != 0 )
  360. return -1;
  361. else if ( trans1 != 0 && trans2 == 0 )
  362. return 1;
  363. else if ( trans1 != 0 ) {
  364. /* Both of the transition pointers are set. */
  365. int compareRes = compareTransData( trans1, trans2 );
  366. if ( compareRes != 0 )
  367. return compareRes;
  368. }
  369. return 0;
  370. }
  371. /* Compares two transitions according to target state, priority and functions.
  372. * Does not consider from state. Either of the pointers may be null. */
  373. int FsmAp::compareFullPtr( TransAp *trans1, TransAp *trans2 )
  374. {
  375. if ( (trans1 != 0) ^ (trans2 != 0) ) {
  376. /* Exactly one of the transitions is set. */
  377. if ( trans1 != 0 )
  378. return -1;
  379. else
  380. return 1;
  381. }
  382. else if ( trans1 != 0 ) {
  383. /* Both of the transition pointers are set. Test target state,
  384. * priority and funcs. */
  385. if ( trans1->toState < trans2->toState )
  386. return -1;
  387. else if ( trans1->toState > trans2->toState )
  388. return 1;
  389. else if ( trans1->toState != 0 ) {
  390. /* Test transition data. */
  391. int compareRes = compareTransData( trans1, trans2 );
  392. if ( compareRes != 0 )
  393. return compareRes;
  394. }
  395. }
  396. return 0;
  397. }
  398. bool FsmAp::shouldMarkPtr( MarkIndex &markIndex, TransAp *trans1,
  399. TransAp *trans2 )
  400. {
  401. if ( (trans1 != 0) ^ (trans2 != 0) ) {
  402. /* Exactly one of the transitions is set. The initial mark round
  403. * should rule out this case. */
  404. assert( false );
  405. }
  406. else if ( trans1 != 0 ) {
  407. /* Both of the transitions are set. If the target pair is marked, then
  408. * the pair we are considering gets marked. */
  409. return markIndex.isPairMarked( trans1->toState->alg.stateNum,
  410. trans2->toState->alg.stateNum );
  411. }
  412. /* Neither of the transitiosn are set. */
  413. return false;
  414. }