You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

877 lines
27 KiB

  1. /**CFile***********************************************************************
  2. FileName [mtrGroup.c]
  3. PackageName [mtr]
  4. Synopsis [Functions to support group specification for reordering.]
  5. Description [External procedures included in this module:
  6. <ul>
  7. <li> Mtr_InitGroupTree()
  8. <li> Mtr_MakeGroup()
  9. <li> Mtr_DissolveGroup()
  10. <li> Mtr_FindGroup()
  11. <li> Mtr_SwapGroups()
  12. <li> Mtr_ReorderGroups()
  13. <li> Mtr_PrintGroups()
  14. <li> Mtr_ReadGroups()
  15. </ul>
  16. Static procedures included in this module:
  17. <ul>
  18. <li> mtrShiftHL
  19. </ul>
  20. ]
  21. SeeAlso [cudd package]
  22. Author [Fabio Somenzi]
  23. Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
  24. All rights reserved.
  25. Redistribution and use in source and binary forms, with or without
  26. modification, are permitted provided that the following conditions
  27. are met:
  28. Redistributions of source code must retain the above copyright
  29. notice, this list of conditions and the following disclaimer.
  30. Redistributions in binary form must reproduce the above copyright
  31. notice, this list of conditions and the following disclaimer in the
  32. documentation and/or other materials provided with the distribution.
  33. Neither the name of the University of Colorado nor the names of its
  34. contributors may be used to endorse or promote products derived from
  35. this software without specific prior written permission.
  36. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  37. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  38. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  39. FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  40. COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  41. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  42. BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  43. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  44. CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  45. LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  46. ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  47. POSSIBILITY OF SUCH DAMAGE.]
  48. ******************************************************************************/
  49. #include "util.h"
  50. #include "mtrInt.h"
  51. /*---------------------------------------------------------------------------*/
  52. /* Constant declarations */
  53. /*---------------------------------------------------------------------------*/
  54. /*---------------------------------------------------------------------------*/
  55. /* Stucture declarations */
  56. /*---------------------------------------------------------------------------*/
  57. /*---------------------------------------------------------------------------*/
  58. /* Type declarations */
  59. /*---------------------------------------------------------------------------*/
  60. /*---------------------------------------------------------------------------*/
  61. /* Variable declarations */
  62. /*---------------------------------------------------------------------------*/
  63. #ifndef lint
  64. static char rcsid[] MTR_UNUSED = "$Id: mtrGroup.c,v 1.21 2012/02/05 01:06:19 fabio Exp $";
  65. #endif
  66. /*---------------------------------------------------------------------------*/
  67. /* Macro declarations */
  68. /*---------------------------------------------------------------------------*/
  69. /**AutomaticStart*************************************************************/
  70. /*---------------------------------------------------------------------------*/
  71. /* Static function prototypes */
  72. /*---------------------------------------------------------------------------*/
  73. static int mtrShiftHL (MtrNode *node, int shift);
  74. /**AutomaticEnd***************************************************************/
  75. /*---------------------------------------------------------------------------*/
  76. /* Definition of exported functions */
  77. /*---------------------------------------------------------------------------*/
  78. /**Function********************************************************************
  79. Synopsis [Allocate new tree.]
  80. Description [Allocate new tree with one node, whose low and size
  81. fields are specified by the lower and size parameters.
  82. Returns pointer to tree root.]
  83. SideEffects [None]
  84. SeeAlso [Mtr_InitTree Mtr_FreeTree]
  85. ******************************************************************************/
  86. MtrNode *
  87. Mtr_InitGroupTree(
  88. int lower,
  89. int size)
  90. {
  91. MtrNode *root;
  92. root = Mtr_InitTree();
  93. if (root == NULL) return(NULL);
  94. root->flags = MTR_DEFAULT;
  95. root->low = lower;
  96. root->size = size;
  97. return(root);
  98. } /* end of Mtr_InitGroupTree */
  99. /**Function********************************************************************
  100. Synopsis [Makes a new group with size leaves starting at low.]
  101. Description [Makes a new group with size leaves starting at low.
  102. If the new group intersects an existing group, it must
  103. either contain it or be contained by it. This procedure relies on
  104. the low and size fields of each node. It also assumes that the
  105. children of each node are sorted in order of increasing low. In
  106. case of a valid request, the flags of the new group are set to the
  107. value passed in `flags.' Returns the pointer to the root of the new
  108. group upon successful termination; NULL otherwise. If the group
  109. already exists, the pointer to its root is returned.]
  110. SideEffects [None]
  111. SeeAlso [Mtr_DissolveGroup Mtr_ReadGroups Mtr_FindGroup]
  112. ******************************************************************************/
  113. MtrNode *
  114. Mtr_MakeGroup(
  115. MtrNode * root /* root of the group tree */,
  116. unsigned int low /* lower bound of the group */,
  117. unsigned int size /* size of the group */,
  118. unsigned int flags /* flags for the new group */)
  119. {
  120. MtrNode *node,
  121. *first,
  122. *last,
  123. *previous,
  124. *newn;
  125. /* Sanity check. */
  126. if (size == 0)
  127. return(NULL);
  128. /* Check whether current group includes new group. This check is
  129. ** necessary at the top-level call. In the subsequent calls it is
  130. ** redundant. */
  131. if (low < (unsigned int) root->low ||
  132. low + size > (unsigned int) (root->low + root->size))
  133. return(NULL);
  134. /* At this point we know that the new group is contained
  135. ** in the group of root. We have two possible cases here:
  136. ** - root is a terminal node;
  137. ** - root has children. */
  138. /* Root has no children: create a new group. */
  139. if (root->child == NULL) {
  140. newn = Mtr_AllocNode();
  141. if (newn == NULL) return(NULL); /* out of memory */
  142. newn->low = low;
  143. newn->size = size;
  144. newn->flags = flags;
  145. newn->parent = root;
  146. newn->elder = newn->younger = newn->child = NULL;
  147. root->child = newn;
  148. return(newn);
  149. }
  150. /* Root has children: Find all children of root that are included
  151. ** in the new group. If the group of any child entirely contains
  152. ** the new group, call Mtr_MakeGroup recursively. */
  153. previous = NULL;
  154. first = root->child; /* guaranteed to be non-NULL */
  155. while (first != NULL && low >= (unsigned int) (first->low + first->size)) {
  156. previous = first;
  157. first = first->younger;
  158. }
  159. if (first == NULL) {
  160. /* We have scanned the entire list and we need to append a new
  161. ** child at the end of it. Previous points to the last child
  162. ** of root. */
  163. newn = Mtr_AllocNode();
  164. if (newn == NULL) return(NULL); /* out of memory */
  165. newn->low = low;
  166. newn->size = size;
  167. newn->flags = flags;
  168. newn->parent = root;
  169. newn->elder = previous;
  170. previous->younger = newn;
  171. newn->younger = newn->child = NULL;
  172. return(newn);
  173. }
  174. /* Here first is non-NULL and low < first->low + first->size. */
  175. if (low >= (unsigned int) first->low &&
  176. low + size <= (unsigned int) (first->low + first->size)) {
  177. /* The new group is contained in the group of first. */
  178. newn = Mtr_MakeGroup(first, low, size, flags);
  179. return(newn);
  180. } else if (low + size <= first->low) {
  181. /* The new group is entirely contained in the gap between
  182. ** previous and first. */
  183. newn = Mtr_AllocNode();
  184. if (newn == NULL) return(NULL); /* out of memory */
  185. newn->low = low;
  186. newn->size = size;
  187. newn->flags = flags;
  188. newn->child = NULL;
  189. newn->parent = root;
  190. newn->elder = previous;
  191. newn->younger = first;
  192. first->elder = newn;
  193. if (previous != NULL) {
  194. previous->younger = newn;
  195. } else {
  196. root->child = newn;
  197. }
  198. return(newn);
  199. } else if (low < (unsigned int) first->low &&
  200. low + size < (unsigned int) (first->low + first->size)) {
  201. /* Trying to cut an existing group: not allowed. */
  202. return(NULL);
  203. } else if (low > first->low) {
  204. /* The new group neither is contained in the group of first
  205. ** (this was tested above) nor contains it. It is therefore
  206. ** trying to cut an existing group: not allowed. */
  207. return(NULL);
  208. }
  209. /* First holds the pointer to the first child contained in the new
  210. ** group. Here low <= first->low and low + size >= first->low +
  211. ** first->size. One of the two inequalities is strict. */
  212. last = first->younger;
  213. while (last != NULL &&
  214. (unsigned int) (last->low + last->size) < low + size) {
  215. last = last->younger;
  216. }
  217. if (last == NULL) {
  218. /* All the chilren of root from first onward become children
  219. ** of the new group. */
  220. newn = Mtr_AllocNode();
  221. if (newn == NULL) return(NULL); /* out of memory */
  222. newn->low = low;
  223. newn->size = size;
  224. newn->flags = flags;
  225. newn->child = first;
  226. newn->parent = root;
  227. newn->elder = previous;
  228. newn->younger = NULL;
  229. first->elder = NULL;
  230. if (previous != NULL) {
  231. previous->younger = newn;
  232. } else {
  233. root->child = newn;
  234. }
  235. last = first;
  236. while (last != NULL) {
  237. last->parent = newn;
  238. last = last->younger;
  239. }
  240. return(newn);
  241. }
  242. /* Here last != NULL and low + size <= last->low + last->size. */
  243. if (low + size - 1 >= (unsigned int) last->low &&
  244. low + size < (unsigned int) (last->low + last->size)) {
  245. /* Trying to cut an existing group: not allowed. */
  246. return(NULL);
  247. }
  248. /* First and last point to the first and last of the children of
  249. ** root that are included in the new group. Allocate a new node
  250. ** and make all children of root between first and last chidren of
  251. ** the new node. Previous points to the child of root immediately
  252. ** preceeding first. If it is NULL, then first is the first child
  253. ** of root. */
  254. newn = Mtr_AllocNode();
  255. if (newn == NULL) return(NULL); /* out of memory */
  256. newn->low = low;
  257. newn->size = size;
  258. newn->flags = flags;
  259. newn->child = first;
  260. newn->parent = root;
  261. if (previous == NULL) {
  262. root->child = newn;
  263. } else {
  264. previous->younger = newn;
  265. }
  266. newn->elder = previous;
  267. newn->younger = last->younger;
  268. if (last->younger != NULL) {
  269. last->younger->elder = newn;
  270. }
  271. last->younger = NULL;
  272. first->elder = NULL;
  273. for (node = first; node != NULL; node = node->younger) {
  274. node->parent = newn;
  275. }
  276. return(newn);
  277. } /* end of Mtr_MakeGroup */
  278. /**Function********************************************************************
  279. Synopsis [Merges the children of `group' with the children of its
  280. parent.]
  281. Description [Merges the children of `group' with the children of its
  282. parent. Disposes of the node pointed by group. If group is the
  283. root of the group tree, this procedure leaves the tree unchanged.
  284. Returns the pointer to the parent of `group' upon successful
  285. termination; NULL otherwise.]
  286. SideEffects [None]
  287. SeeAlso [Mtr_MakeGroup]
  288. ******************************************************************************/
  289. MtrNode *
  290. Mtr_DissolveGroup(
  291. MtrNode * group /* group to be dissolved */)
  292. {
  293. MtrNode *parent;
  294. MtrNode *last;
  295. parent = group->parent;
  296. if (parent == NULL) return(NULL);
  297. if (MTR_TEST(group,MTR_TERMINAL) || group->child == NULL) return(NULL);
  298. /* Make all children of group children of its parent, and make
  299. ** last point to the last child of group. */
  300. for (last = group->child; last->younger != NULL; last = last->younger) {
  301. last->parent = parent;
  302. }
  303. last->parent = parent;
  304. last->younger = group->younger;
  305. if (group->younger != NULL) {
  306. group->younger->elder = last;
  307. }
  308. group->child->elder = group->elder;
  309. if (group == parent->child) {
  310. parent->child = group->child;
  311. } else {
  312. group->elder->younger = group->child;
  313. }
  314. Mtr_DeallocNode(group);
  315. return(parent);
  316. } /* end of Mtr_DissolveGroup */
  317. /**Function********************************************************************
  318. Synopsis [Finds a group with size leaves starting at low, if it exists.]
  319. Description [Finds a group with size leaves starting at low, if it
  320. exists. This procedure relies on the low and size fields of each
  321. node. It also assumes that the children of each node are sorted in
  322. order of increasing low. Returns the pointer to the root of the
  323. group upon successful termination; NULL otherwise.]
  324. SideEffects [None]
  325. SeeAlso []
  326. ******************************************************************************/
  327. MtrNode *
  328. Mtr_FindGroup(
  329. MtrNode * root /* root of the group tree */,
  330. unsigned int low /* lower bound of the group */,
  331. unsigned int size /* upper bound of the group */)
  332. {
  333. MtrNode *node;
  334. #ifdef MTR_DEBUG
  335. /* We cannot have a non-empty proper subgroup of a singleton set. */
  336. assert(!MTR_TEST(root,MTR_TERMINAL));
  337. #endif
  338. /* Sanity check. */
  339. if (size < 1) return(NULL);
  340. /* Check whether current group includes the group sought. This
  341. ** check is necessary at the top-level call. In the subsequent
  342. ** calls it is redundant. */
  343. if (low < (unsigned int) root->low ||
  344. low + size > (unsigned int) (root->low + root->size))
  345. return(NULL);
  346. if (root->size == size && root->low == low)
  347. return(root);
  348. if (root->child == NULL)
  349. return(NULL);
  350. /* Find all chidren of root that are included in the new group. If
  351. ** the group of any child entirely contains the new group, call
  352. ** Mtr_MakeGroup recursively. */
  353. node = root->child;
  354. while (low >= (unsigned int) (node->low + node->size)) {
  355. node = node->younger;
  356. }
  357. if (low + size <= (unsigned int) (node->low + node->size)) {
  358. /* The group is contained in the group of node. */
  359. node = Mtr_FindGroup(node, low, size);
  360. return(node);
  361. } else {
  362. return(NULL);
  363. }
  364. } /* end of Mtr_FindGroup */
  365. /**Function********************************************************************
  366. Synopsis [Swaps two children of a tree node.]
  367. Description [Swaps two children of a tree node. Adjusts the high and
  368. low fields of the two nodes and their descendants. The two children
  369. must be adjacent. However, first may be the younger sibling of second.
  370. Returns 1 in case of success; 0 otherwise.]
  371. SideEffects [None]
  372. SeeAlso []
  373. ******************************************************************************/
  374. int
  375. Mtr_SwapGroups(
  376. MtrNode * first /* first node to be swapped */,
  377. MtrNode * second /* second node to be swapped */)
  378. {
  379. MtrNode *node;
  380. MtrNode *parent;
  381. int sizeFirst;
  382. int sizeSecond;
  383. if (second->younger == first) { /* make first first */
  384. node = first;
  385. first = second;
  386. second = node;
  387. } else if (first->younger != second) { /* non-adjacent */
  388. return(0);
  389. }
  390. sizeFirst = first->size;
  391. sizeSecond = second->size;
  392. /* Swap the two nodes. */
  393. parent = first->parent;
  394. if (parent == NULL || second->parent != parent) return(0);
  395. if (parent->child == first) {
  396. parent->child = second;
  397. } else { /* first->elder != NULL */
  398. first->elder->younger = second;
  399. }
  400. if (second->younger != NULL) {
  401. second->younger->elder = first;
  402. }
  403. first->younger = second->younger;
  404. second->elder = first->elder;
  405. first->elder = second;
  406. second->younger = first;
  407. /* Adjust the high and low fields. */
  408. if (!mtrShiftHL(first,sizeSecond)) return(0);
  409. if (!mtrShiftHL(second,-sizeFirst)) return(0);
  410. return(1);
  411. } /* end of Mtr_SwapGroups */
  412. /**Function********************************************************************
  413. Synopsis [Fix variable tree at the end of tree sifting.]
  414. Description [Fix the levels in the variable tree sorting siblings
  415. according to them. It should be called on a non-NULL tree. It then
  416. maintains this invariant. It applies insertion sorting to the list of
  417. siblings The order is determined by permutation, which is used to find
  418. the new level of the node index. Index must refer to the first variable
  419. in the group.]
  420. SideEffects [The tree is modified.]
  421. SeeAlso []
  422. ******************************************************************************/
  423. void
  424. Mtr_ReorderGroups(
  425. MtrNode *treenode,
  426. int *permutation)
  427. {
  428. MtrNode *auxnode;
  429. /* Initialize sorted list to first element. */
  430. MtrNode *sorted = treenode;
  431. sorted->low = permutation[sorted->index];
  432. if (sorted->child != NULL)
  433. Mtr_ReorderGroups(sorted->child, permutation);
  434. auxnode = treenode->younger;
  435. while (auxnode != NULL) {
  436. MtrNode *rightplace;
  437. MtrNode *moving = auxnode;
  438. auxnode->low = permutation[auxnode->index];
  439. if (auxnode->child != NULL)
  440. Mtr_ReorderGroups(auxnode->child, permutation);
  441. rightplace = auxnode->elder;
  442. /* Find insertion point. */
  443. while (rightplace != NULL && auxnode->low < rightplace->low)
  444. rightplace = rightplace->elder;
  445. auxnode = auxnode->younger;
  446. if (auxnode != NULL) {
  447. auxnode->elder = moving->elder;
  448. auxnode->elder->younger = auxnode;
  449. } else {
  450. moving->elder->younger = NULL;
  451. }
  452. if (rightplace == NULL) { /* Move to head of sorted list. */
  453. sorted->elder = moving;
  454. moving->elder = NULL;
  455. moving->younger = sorted;
  456. sorted = moving;
  457. } else { /* Splice. */
  458. moving->elder = rightplace;
  459. moving->younger = rightplace->younger;
  460. if (rightplace->younger != NULL)
  461. rightplace->younger->elder = moving;
  462. rightplace->younger = moving;
  463. }
  464. }
  465. /* Fix parent. */
  466. if (sorted->parent != NULL)
  467. sorted->parent->child = sorted;
  468. } /* end of Mtr_ReorderGroups */
  469. /**Function********************************************************************
  470. Synopsis [Prints the groups as a parenthesized list.]
  471. Description [Prints the groups as a parenthesized list. After each
  472. group, the group's flag are printed, preceded by a `|'. For each
  473. flag (except MTR_TERMINAL) a character is printed.
  474. <ul>
  475. <li>F: MTR_FIXED
  476. <li>N: MTR_NEWNODE
  477. <li>S: MTR_SOFT
  478. </ul>
  479. The second argument, silent, if different from 0, causes
  480. Mtr_PrintGroups to only check the syntax of the group tree.
  481. ]
  482. SideEffects [None]
  483. SeeAlso [Mtr_PrintTree]
  484. ******************************************************************************/
  485. void
  486. Mtr_PrintGroups(
  487. MtrNode * root /* root of the group tree */,
  488. int silent /* flag to check tree syntax only */)
  489. {
  490. MtrNode *node;
  491. assert(root != NULL);
  492. assert(root->younger == NULL || root->younger->elder == root);
  493. assert(root->elder == NULL || root->elder->younger == root);
  494. #if SIZEOF_VOID_P == 8
  495. if (!silent) (void) printf("(%u",root->low);
  496. #else
  497. if (!silent) (void) printf("(%hu",root->low);
  498. #endif
  499. if (MTR_TEST(root,MTR_TERMINAL) || root->child == NULL) {
  500. if (!silent) (void) printf(",");
  501. } else {
  502. node = root->child;
  503. while (node != NULL) {
  504. assert(node->low >= root->low && (int) (node->low + node->size) <= (int) (root->low + root->size));
  505. assert(node->parent == root);
  506. Mtr_PrintGroups(node,silent);
  507. node = node->younger;
  508. }
  509. }
  510. if (!silent) {
  511. #if SIZEOF_VOID_P == 8
  512. (void) printf("%u", root->low + root->size - 1);
  513. #else
  514. (void) printf("%hu", root->low + root->size - 1);
  515. #endif
  516. if (root->flags != MTR_DEFAULT) {
  517. (void) printf("|");
  518. if (MTR_TEST(root,MTR_FIXED)) (void) printf("F");
  519. if (MTR_TEST(root,MTR_NEWNODE)) (void) printf("N");
  520. if (MTR_TEST(root,MTR_SOFT)) (void) printf("S");
  521. }
  522. (void) printf(")");
  523. if (root->parent == NULL) (void) printf("\n");
  524. }
  525. assert((root->flags &~(MTR_TERMINAL | MTR_SOFT | MTR_FIXED | MTR_NEWNODE)) == 0);
  526. return;
  527. } /* end of Mtr_PrintGroups */
  528. /**Function********************************************************************
  529. Synopsis [Prints the variable order as a parenthesized list.]
  530. Description [Prints the variable order as a parenthesized list. After each
  531. group, the group's flag are printed, preceded by a `|'. For each
  532. flag (except MTR_TERMINAL) a character is printed.
  533. <ul>
  534. <li>F: MTR_FIXED
  535. <li>N: MTR_NEWNODE
  536. <li>S: MTR_SOFT
  537. </ul>
  538. The second argument, gives the map from levels to variable indices.
  539. ]
  540. SideEffects [None]
  541. SeeAlso [Mtr_PrintGroups]
  542. ******************************************************************************/
  543. int
  544. Mtr_PrintGroupedOrder(
  545. MtrNode * root /* root of the group tree */,
  546. int *invperm /* map from levels to indices */,
  547. FILE *fp /* output file */)
  548. {
  549. MtrNode *child;
  550. MtrHalfWord level;
  551. int retval;
  552. assert(root != NULL);
  553. assert(root->younger == NULL || root->younger->elder == root);
  554. assert(root->elder == NULL || root->elder->younger == root);
  555. retval = fprintf(fp,"(");
  556. if (retval == EOF) return(0);
  557. level = root->low;
  558. child = root->child;
  559. while (child != NULL) {
  560. assert(child->low >= root->low && (child->low + child->size) <= (root->low + root->size));
  561. assert(child->parent == root);
  562. while (level < child->low) {
  563. retval = fprintf(fp,"%d%s", invperm[level], (level < root->low + root->size - 1) ? "," : "");
  564. if (retval == EOF) return(0);
  565. level++;
  566. }
  567. retval = Mtr_PrintGroupedOrder(child,invperm,fp);
  568. if (retval == 0) return(0);
  569. level += child->size;
  570. if (level < root->low + root->size - 1) {
  571. retval = fprintf(fp,",");
  572. if (retval == EOF) return(0);
  573. }
  574. child = child->younger;
  575. }
  576. while (level < root->low + root->size) {
  577. retval = fprintf(fp,"%d%s", invperm[level], (level < root->low + root->size - 1) ? "," : "");
  578. if (retval == EOF) return(0);
  579. level++;
  580. }
  581. if (root->flags != MTR_DEFAULT) {
  582. retval = fprintf(fp,"|");
  583. if (retval == EOF) return(0);
  584. if (MTR_TEST(root,MTR_FIXED)) {
  585. retval = fprintf(fp,"F");
  586. if (retval == EOF) return(0);
  587. }
  588. if (MTR_TEST(root,MTR_NEWNODE)) {
  589. retval = fprintf(fp,"N");
  590. if (retval == EOF) return(0);
  591. }
  592. if (MTR_TEST(root,MTR_SOFT)) {
  593. retval = fprintf(fp,"S");
  594. if (retval == EOF) return(0);
  595. }
  596. }
  597. retval = fprintf(fp,")");
  598. if (retval == EOF) return(0);
  599. if (root->parent == NULL) {
  600. retval = fprintf(fp,"\n");
  601. if (retval == EOF) return(0);
  602. }
  603. assert((root->flags &~(MTR_SOFT | MTR_FIXED | MTR_NEWNODE)) == 0);
  604. return(1);
  605. } /* end of Mtr_PrintGroupedOrder */
  606. /**Function********************************************************************
  607. Synopsis [Reads groups from a file and creates a group tree.]
  608. Description [Reads groups from a file and creates a group tree.
  609. Each group is specified by three fields:
  610. <xmp>
  611. low size flags.
  612. </xmp>
  613. Low and size are (short) integers. Flags is a string composed of the
  614. following characters (with associated translation):
  615. <ul>
  616. <li>D: MTR_DEFAULT
  617. <li>F: MTR_FIXED
  618. <li>N: MTR_NEWNODE
  619. <li>S: MTR_SOFT
  620. <li>T: MTR_TERMINAL
  621. </ul>
  622. Normally, the only flags that are needed are D and F. Groups and
  623. fields are separated by white space (spaces, tabs, and newlines).
  624. Returns a pointer to the group tree if successful; NULL otherwise.]
  625. SideEffects [None]
  626. SeeAlso [Mtr_InitGroupTree Mtr_MakeGroup]
  627. ******************************************************************************/
  628. MtrNode *
  629. Mtr_ReadGroups(
  630. FILE * fp /* file pointer */,
  631. int nleaves /* number of leaves of the new tree */)
  632. {
  633. int low;
  634. int size;
  635. int err;
  636. unsigned int flags;
  637. MtrNode *root;
  638. MtrNode *node;
  639. char attrib[8*sizeof(unsigned int)+1];
  640. char *c;
  641. root = Mtr_InitGroupTree(0,nleaves);
  642. if (root == NULL) return NULL;
  643. while (! feof(fp)) {
  644. /* Read a triple and check for consistency. */
  645. err = fscanf(fp, "%d %d %s", &low, &size, attrib);
  646. if (err == EOF) {
  647. break;
  648. } else if (err != 3) {
  649. Mtr_FreeTree(root);
  650. return(NULL);
  651. } else if (low < 0 || low+size > nleaves || size < 1) {
  652. Mtr_FreeTree(root);
  653. return(NULL);
  654. } else if (strlen(attrib) > 8 * sizeof(MtrHalfWord)) {
  655. /* Not enough bits in the flags word to store these many
  656. ** attributes. */
  657. Mtr_FreeTree(root);
  658. return(NULL);
  659. }
  660. /* Parse the flag string. Currently all flags are permitted,
  661. ** to make debugging easier. Normally, specifying NEWNODE
  662. ** wouldn't be allowed. */
  663. flags = MTR_DEFAULT;
  664. for (c=attrib; *c != 0; c++) {
  665. switch (*c) {
  666. case 'D':
  667. break;
  668. case 'F':
  669. flags |= MTR_FIXED;
  670. break;
  671. case 'N':
  672. flags |= MTR_NEWNODE;
  673. break;
  674. case 'S':
  675. flags |= MTR_SOFT;
  676. break;
  677. case 'T':
  678. flags |= MTR_TERMINAL;
  679. break;
  680. default:
  681. return NULL;
  682. }
  683. }
  684. node = Mtr_MakeGroup(root, (MtrHalfWord) low, (MtrHalfWord) size,
  685. flags);
  686. if (node == NULL) {
  687. Mtr_FreeTree(root);
  688. return(NULL);
  689. }
  690. }
  691. return(root);
  692. } /* end of Mtr_ReadGroups */
  693. /*---------------------------------------------------------------------------*/
  694. /* Definition of internal functions */
  695. /*---------------------------------------------------------------------------*/
  696. /*---------------------------------------------------------------------------*/
  697. /* Definition of static functions */
  698. /*---------------------------------------------------------------------------*/
  699. /**Function********************************************************************
  700. Synopsis [Adjusts the low fields of a node and its descendants.]
  701. Description [Adjusts the low fields of a node and its
  702. descendants. Adds shift to low of each node. Checks that no
  703. out-of-bounds values result. Returns 1 in case of success; 0
  704. otherwise.]
  705. SideEffects [None]
  706. SeeAlso []
  707. ******************************************************************************/
  708. static int
  709. mtrShiftHL(
  710. MtrNode * node /* group tree node */,
  711. int shift /* amount by which low should be changed */)
  712. {
  713. MtrNode *auxnode;
  714. int low;
  715. low = (int) node->low;
  716. low += shift;
  717. if (low < 0 || low + (int) (node->size - 1) > (int) MTR_MAXHIGH) return(0);
  718. node->low = (MtrHalfWord) low;
  719. if (!MTR_TEST(node,MTR_TERMINAL) && node->child != NULL) {
  720. auxnode = node->child;
  721. do {
  722. if (!mtrShiftHL(auxnode,shift)) return(0);
  723. auxnode = auxnode->younger;
  724. } while (auxnode != NULL);
  725. }
  726. return(1);
  727. } /* end of mtrShiftHL */