OOP.txt 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757
  1. ClassDecl ::=
  2. CLASS Classidentifier['(' Name { ',' Name } ')'] ';'
  3. [ClassFieldDefList]
  4. [MethodDecList]
  5. END Classidentifier ';'
  6. ClassFieldDefList ::=
  7. ClassFieldDef {';' ClassFieldDef }
  8. ClassFieldDef ::=
  9. IdentifierList ':' TypeDef |
  10. Identifier '=' Name
  11. MethodDecList ::=
  12. MethodDec {',' MethodDec }
  13. MethodDec ::=
  14. [VIRTUAL] PEOCEDURE MethodIdentifier
  15. [FormalList [':' Name ]]
  16. Example:
  17. (* ========================================== *)
  18. (* (c) 1990-1992 Clarion Software Corporation *)
  19. (* ========================================== *)
  20. DEFINITION MODULE Table;
  21. (*
  22. This module implements classes that allow the creation and maintenance
  23. of homogeneous tables of ordered objects. The internal structure of the
  24. table is an AVL Balanced Tree. The algorithms are based on an example
  25. given in Niklaus Wirth's "Algorithms + Data Structures = Programs". That
  26. book also gives a detailed description of AVL Balanced Trees.
  27. *)
  28. TYPE
  29. BalanceFlag = SHORTINT [-1..1];
  30. ElementPtr = POINTER TO Element;
  31. CLASS Element;
  32. Right : ElementPtr; (* Pointer to right sub-tree *)
  33. Left : ElementPtr; (* Pointer to left sub-tree *)
  34. Bal : BalanceFlag; (* Tree balance flag *)
  35. VIRTUAL PROCEDURE Compare( p : ElementPtr ) : INTEGER;
  36. (*
  37. Must be implemented by the client. This
  38. procedure should return one of the
  39. following integer values:
  40. <0 if 'THIS' is less than 'p'
  41. 0 if 'THIS' is equal to 'p'
  42. >0 if 'THIS' is greater than 'p'
  43. *)
  44. END Element ;
  45. TYPE
  46. Action = PROCEDURE ( ElementPtr );
  47. (* This procedure type is used by 'Apply' *)
  48. CLASS TABLE;
  49. Root : ElementPtr; (* The root of this tree *)
  50. PROCEDURE Insert( VAR x : Element );
  51. (* Insert the element 'x' into this table *)
  52. PROCEDURE Find( VAR p : Element ) : BOOLEAN;
  53. (* Search table for a element matching 'p'.
  54. Returns 'TRUE' and sets all fields of 'p' if
  55. found; otherwise returns 'FALSE'
  56. *)
  57. PROCEDURE Delete( VAR x : Element );
  58. (* Delete the element matching 'p' from table *)
  59. PROCEDURE Apply( p : Action );
  60. (* Apply procedure 'p' to all elements in order *)
  61. PROCEDURE Init;
  62. (* Initialize the table *)
  63. PROCEDURE Eq( t2 : TABLE ) : INTEGER;
  64. (* Compare 'THIS' with 't2'. The return values
  65. are:
  66. <0 'THIS' is less than 't2'
  67. 0 'THIS' is equal to 't2'
  68. >0 'THIS' is greater than 't2'
  69. ** RESTRICTION : Table must not generate a
  70. tree greater than 32 levels deep (around
  71. 2^32 elements
  72. *)
  73. PROCEDURE SubSet( t2 : TABLE ) : BOOLEAN;
  74. (* Are the elements in this table a subset of
  75. the elememts in table 't2'? *)
  76. PROCEDURE Copy() : TABLE;
  77. (* Make a copy this table *)
  78. PROCEDURE Incl( t2 : TABLE );
  79. (* Include elements from table 't2' in this
  80. table *)
  81. PROCEDURE Excl( t2 : TABLE );
  82. (* Exclude elements from table 't2' from this
  83. table *)
  84. PROCEDURE Empty() : BOOLEAN;
  85. (* Is this table empty? *)
  86. PROCEDURE Dispose;
  87. (* Dispose of all elements of this table *)
  88. END TABLE ;
  89. END Table.
  90. (* ==================================================== *)
  91. (* Copyright (C) 1990-1992 Clarion Software Corporation *)
  92. (* ==================================================== *)
  93. IMPLEMENTATION MODULE Table;
  94. IMPORT Lib;
  95. FROM Storage IMPORT ALLOCATE, DEALLOCATE;
  96. CLASS IMPLEMENTATION Element;
  97. VIRTUAL PROCEDURE Compare( p : ElementPtr ) : INTEGER;
  98. (* It is an error not to supply an implementation of this
  99. method. The client MUST supply a method to compare
  100. 'THIS' with 'p'.
  101. *)
  102. BEGIN
  103. Lib.FatalError(' implemeted by client ');
  104. RETURN 0;
  105. END Compare;
  106. BEGIN
  107. END Element ;
  108. CLASS GenElem (Element) ;
  109. GenericData : CHAR;
  110. END GenElem;
  111. CLASS IMPLEMENTATION GenElem;
  112. BEGIN
  113. END GenElem;
  114. TYPE
  115. GenElemPtr = POINTER TO GenElem;
  116. (* The above definitions are a skeleton for all the
  117. implementation of the 'Element' CLASS. This enables
  118. the 'TABLE' class to successfully copy any client
  119. implementation of 'Element'
  120. *)
  121. CLASS IMPLEMENTATION TABLE;
  122. PROCEDURE Insert( VAR x : Element );
  123. (* Insert a new element 'x' in 'THIS' table *)
  124. PROCEDURE Search( VAR p : ElementPtr; VAR h : BOOLEAN);
  125. (* Searches a tree 'p' for the element 'x'. If it is found
  126. then the new value replaces the old. If 'x' is not
  127. in the tree, then 'x' becomes a new leaf of the tree.
  128. *)
  129. VAR
  130. p1 : ElementPtr;
  131. p2 : ElementPtr;
  132. BEGIN
  133. IF (p = NIL) THEN (* Create new leaf *)
  134. ALLOCATE(p,SIZE(x));
  135. Lib.Move(ADR(x),p,SIZE(x));
  136. p^.Bal := 0;
  137. p^.Left := NIL;
  138. p^.Right := NIL;
  139. h := TRUE; (* Tree requires balancing *)
  140. ELSE
  141. IF (x.Compare(p) < 0) THEN (* 'THIS' is < 'p' *)
  142. (* Search the 'Left' branch of 'p' recursively
  143. until 'x' is either found or created.
  144. *)
  145. Search(p^.Left,h);
  146. IF h THEN (* i.e. requires balancing *)
  147. CASE p^.Bal OF
  148. | 1 :
  149. p^.Bal := 0;
  150. h := FALSE;
  151. | 0 :
  152. p^.Bal := -1;
  153. | -1 :
  154. p1 := p^.Left;
  155. IF (p1^.Bal = -1) THEN
  156. p^.Left := p1^.Right;
  157. p1^.Right := p;
  158. p^.Bal := 0;
  159. p := p1;
  160. ELSE
  161. p2 := p1^.Right;
  162. p1^.Right := p2^.Left;
  163. p2^.Left := p1;
  164. p^.Left := p2^.Right;
  165. p2^.Right := p;
  166. IF (p2^.Bal = -1) THEN
  167. p^.Bal := 1;
  168. ELSE
  169. p^.Bal := 0;
  170. END;
  171. IF (p2^.Bal = 1) THEN
  172. p1^.Bal := -1;
  173. ELSE
  174. p1^.Bal := 0;
  175. END;
  176. p := p2;
  177. END;
  178. p^.Bal := 0;
  179. h := FALSE; (* Balancing done *)
  180. END (* CASE *);
  181. END (* of balancing 'Left' sub-tree *);
  182. ELSIF (x.Compare(p) > 0) THEN (* 'THIS' > 'p' *)
  183. (* Search the 'Right' branch of 'p' recursively
  184. until 'x' is either found or created.
  185. *)
  186. Search( p^.Right,h);
  187. IF h THEN (* i.e. tree needs balancing *)
  188. CASE p^.Bal OF
  189. | -1 :
  190. p^.Bal := 0;
  191. h := FALSE;
  192. | 0 :
  193. p^.Bal := 1;
  194. | 1 :
  195. p1 := p^.Right;
  196. IF (p1^.Bal = 1) THEN
  197. p^.Right := p1^.Left;
  198. p1^.Left := p;
  199. p^.Bal := 0;
  200. p := p1;
  201. ELSE
  202. p2 := p1^.Left;
  203. p1^.Left := p2^.Right;
  204. p2^.Right := p1;
  205. p^.Right := p2^.Left;
  206. p2^.Left := p;
  207. IF (p2^.Bal = 1) THEN
  208. p^.Bal := -1;
  209. ELSE
  210. p^.Bal := 0;
  211. END;
  212. IF (p2^.Bal = -1) THEN
  213. p1^.Bal := 1;
  214. ELSE
  215. p1^.Bal := 0;
  216. END;
  217. p := p2;
  218. END;
  219. p^.Bal := 0;
  220. h := FALSE; (* Tree balanced *)
  221. END (* CASE *);
  222. END (* Balancing 'Right' sub-tree *);
  223. ELSE (* 'THIS' and 'p' are the same *)
  224. h := FALSE;
  225. Lib.Move(ADR(GenElemPtr(ADR(x))^.GenericData),
  226. ADR(GenElemPtr(p)^.GenericData),
  227. SIZE(x)-VSIZE(Element.Bal));
  228. END (* Possible comaprison results *);
  229. END;
  230. END Search;
  231. VAR
  232. h : BOOLEAN;
  233. BEGIN
  234. IF (Root # NIL) AND (ADR(Root^.Compare) # ADR(x.Compare)) THEN
  235. (* All table elements must be homogeneous; i.e. they must be of
  236. the same CLASS
  237. *)
  238. Lib.FatalError('object not compatible with table');
  239. END;
  240. Search(Root,h);
  241. END Insert;
  242. PROCEDURE Find( VAR x : Element ) : BOOLEAN;
  243. (* Search for 'x' in 'THIS' tree; if 'x' is found in
  244. 'THIS' tree then the function returns 'TRUE' and 'x'
  245. is set to the mathing element. Otherwise the
  246. method returns 'FALSE'.
  247. *)
  248. PROCEDURE _Find( r : ElementPtr ) : ElementPtr;
  249. (* Implements the search algorithm *)
  250. BEGIN
  251. LOOP
  252. IF (r = NIL) THEN (* No match *)
  253. RETURN r;
  254. ELSIF (x.Compare(r) < 0) THEN (* 'THIS' < r *)
  255. r := r^.Left;
  256. ELSIF (x.Compare(r) > 0) THEN (* 'THIS' > r *)
  257. r := r^.Right;
  258. ELSE (* FOUND IT! *)
  259. RETURN r;
  260. END;
  261. END (* LOOP *);
  262. END _Find;
  263. VAR
  264. p : ElementPtr;
  265. BEGIN
  266. p := _Find(Root);
  267. IF (p # NIL) THEN (* Element Located *)
  268. Lib.Move(p,ADR(x),SIZE(x));
  269. RETURN TRUE;
  270. ELSE
  271. RETURN FALSE;
  272. END;
  273. END Find;
  274. PROCEDURE Delete( VAR x : Element );
  275. (* Locate the element 'x' in 'THIS' tree and delete it *)
  276. VAR
  277. q : ElementPtr;
  278. PROCEDURE r_Balance( VAR p : ElementPtr; VAR h : BOOLEAN);
  279. (* Blance a right sub-tree *)
  280. VAR
  281. p1 : ElementPtr;
  282. p2 : ElementPtr;
  283. b1 : BalanceFlag;
  284. b2 : BalanceFlag;
  285. BEGIN
  286. CASE p^.Bal OF
  287. | -1 :
  288. p^.Bal := 0;
  289. | 0 :
  290. p^.Bal := 1;
  291. h := FALSE;
  292. | 1 :
  293. p1 := p^.Right;
  294. b1 := p1^.Bal;
  295. IF (b1 >= 0) THEN
  296. p^.Right := p1^.Left;
  297. p1^.Left := p;
  298. IF (b1 = 0) THEN
  299. p^.Bal := 1;
  300. p1^.Bal := -1;
  301. h := FALSE
  302. ELSE
  303. p^.Bal := 0;
  304. p1^.Bal := 0;
  305. END;
  306. p := p1;
  307. ELSE
  308. p2 := p1^.Left;
  309. b2 := p2^.Bal;
  310. p1^.Left := p2^.Right;
  311. p2^.Right := p1;
  312. p^.Right := p2^.Left;
  313. p2^.Left := p;
  314. IF (b2 = 1) THEN
  315. p^.Bal := -1;
  316. ELSE
  317. p^.Bal := 0;
  318. END;
  319. IF (b2 = -1) THEN
  320. p1^.Bal := 1;
  321. ELSE
  322. p1^.Bal := 0;
  323. END;
  324. p := p2;
  325. p2^.Bal := 0;
  326. END;
  327. END (* CASE *);
  328. END r_Balance;
  329. PROCEDURE l_Balance( VAR p : ElementPtr; VAR h : BOOLEAN);
  330. (* Balance a left sub-tree *)
  331. VAR
  332. p1 : ElementPtr;
  333. p2 : ElementPtr;
  334. b1 : BalanceFlag;
  335. b2 : BalanceFlag;
  336. BEGIN
  337. CASE p^.Bal OF
  338. | 1 :
  339. p^.Bal := 0;
  340. | 0 :
  341. p^.Bal := -1;
  342. h := FALSE;
  343. | -1 :
  344. p1 := p^.Left;
  345. b1 := p1^.Bal;
  346. IF (b1 <= 0) THEN
  347. p^.Left := p1^.Right;
  348. p1^.Right := p;
  349. IF (b1 = 0) THEN
  350. p^.Bal := -1;
  351. p1^.Bal := 1;
  352. h := FALSE
  353. ELSE
  354. p^.Bal := 0;
  355. p1^.Bal := 0;
  356. END;
  357. p := p1;
  358. ELSE
  359. p2 := p1^.Right;
  360. b2 := p2^.Bal;
  361. p1^.Right := p2^.Left;
  362. p2^.Left := p1;
  363. p^.Left := p2^.Right;
  364. p2^.Right := p;
  365. IF (b2 = -1) THEN
  366. p^.Bal := 1;
  367. ELSE
  368. p^.Bal := 0;
  369. END;
  370. IF (b2 = 1) THEN
  371. p1^.Bal := -1;
  372. ELSE
  373. p1^.Bal := 0;
  374. END;
  375. p := p2;
  376. p2^.Bal := 0;
  377. END;
  378. END (* CASE *);
  379. END l_Balance;
  380. PROCEDURE DeleteLeaf( VAR r : ElementPtr; VAR h : BOOLEAN );
  381. (* Recursively search for extreme right-hand node of
  382. the sub-tree 'r' and move data into 'q'
  383. *)
  384. BEGIN
  385. IF (r^.Right # NIL) THEN
  386. DeleteLeaf(r^.Right,h);
  387. IF h THEN
  388. l_Balance(r,h);
  389. END;
  390. ELSE
  391. Lib.Move(ADR(GenElemPtr(r)^.GenericData),
  392. ADR(GenElemPtr(q)^.GenericData),
  393. SIZE(x)-VSIZE(Element.Bal));
  394. q := r;
  395. r := r^.Left;
  396. h := TRUE;
  397. END;
  398. END DeleteLeaf;
  399. PROCEDURE _Delete( VAR p : ElementPtr; VAR h : BOOLEAN );
  400. (* Main recursive deletion procedure *)
  401. BEGIN
  402. IF (p = NIL) THEN (* Not found *)
  403. h := FALSE;
  404. ELSIF (x.Compare(p) < 0) THEN (* 'THIS' < 'p' *)
  405. _Delete(p^.Left,h);
  406. IF h THEN
  407. r_Balance(p,h);
  408. END;
  409. ELSIF (x.Compare(p) > 0) THEN (* 'THIS' > 'p' *)
  410. _Delete(p^.Right,h);
  411. IF h THEN
  412. l_Balance(p,h);
  413. END;
  414. ELSE (* Found it! *)
  415. q := p;
  416. IF (q^.Right = NIL) THEN
  417. p := q^.Left;
  418. h := TRUE;
  419. ELSIF (q^.Left = NIL) THEN
  420. p := q^.Right;
  421. h := TRUE;
  422. ELSE
  423. DeleteLeaf(q^.Left,h);
  424. IF h THEN
  425. r_Balance(p,h);
  426. END;
  427. END;
  428. DISPOSE(q);
  429. END;
  430. END _Delete;
  431. VAR
  432. h : BOOLEAN;
  433. BEGIN
  434. IF (Root = NIL) THEN
  435. RETURN;
  436. END;
  437. IF (Root # NIL) AND (ADR(x.Compare) # ADR(Root^.Compare)) THEN
  438. (* 'x' is not the same type as tree members *)
  439. Lib.FatalError('object not compatible with table');
  440. END;
  441. _Delete(Root,h);
  442. END Delete;
  443. PROCEDURE Apply( p : Action );
  444. (* Apply a procedure to all table elements in order *)
  445. PROCEDURE ApplyToElement( s : ElementPtr );
  446. (* Apply 'p' to left sub-tree of s, then s, then the
  447. right sub-tree of s.
  448. *)
  449. BEGIN
  450. IF (s = NIL) THEN
  451. RETURN;
  452. ELSE
  453. ApplyToElement(s^.Left);
  454. p(s);
  455. ApplyToElement(s^.Right);
  456. END;
  457. END ApplyToElement;
  458. BEGIN
  459. ApplyToElement(Root);
  460. END Apply;
  461. PROCEDURE Init;
  462. (* Initialise a tree *)
  463. BEGIN
  464. Root := NIL;
  465. END Init;
  466. PROCEDURE Eq( t2 : TABLE ) : INTEGER;
  467. (* Compare 'THIS' to 't2'. Return values:
  468. <0 'THIS' is less than 't2'
  469. 0 'THIS' is equal to 't2'
  470. >0 'THIS' is greater than 't2'
  471. The trees are searched from the bottom up (i.e. in
  472. order) and the elements compared. The procedure
  473. returns immediately a difference is detected or
  474. when both trees are exhausted (and, therefore, they
  475. must be equal). This process is implemented iteratively
  476. rather than recursively.
  477. *)
  478. VAR
  479. S1,
  480. S2 : ARRAY [1..32] OF ElementPtr;
  481. r1,
  482. r2 : ElementPtr;
  483. sp1,
  484. sp2 : CARDINAL;
  485. res : INTEGER;
  486. BEGIN
  487. r1 := Root;
  488. r2 := t2.Root;
  489. IF (r1 # NIL) AND (r1 # r2) AND (ADR(r1^.Compare) # ADR(r2^.Compare)) THEN
  490. (* Both trees must contain the same sort of element *)
  491. Lib.FatalError(' not compareable ');
  492. END;
  493. sp1 := 0;
  494. sp2 := 0;
  495. LOOP
  496. WHILE (r1 # NIL) DO (* Build left edge array for 'THIS' *)
  497. INC(sp1);
  498. S1[sp1] := r1;
  499. r1 := r1^.Left;
  500. END;
  501. WHILE (r2 # NIL) DO (* Build left edge array for 't2' *)
  502. INC(sp2);
  503. S2[sp2] := r2;
  504. r2 := r2^.Left;
  505. END;
  506. IF (sp1 = 0) THEN (* No left sub-tree for 'THIS' *)
  507. IF (sp2 = 0) THEN (* No left sub-tree for 't2' *)
  508. RETURN 0; (* Implies they are equal *)
  509. ELSE
  510. RETURN -1; (* 'THIS' < 't2' *)
  511. END;
  512. ELSIF (sp2 = 0) THEN (* No left sub-tree for 't2' *)
  513. RETURN 1; (* 'THIS' > 't2' *)
  514. ELSE
  515. r1 := S1[sp1];
  516. DEC(sp1);
  517. r2 := S2[sp2];
  518. DEC(sp2);
  519. END;
  520. res := r1^.Compare(r2); (* Compare extreme left of both *)
  521. IF (res # 0) THEN (* These are different! *)
  522. RETURN res; (* Return how they are different *)
  523. END;
  524. r1 := r1^.Right;
  525. r2 := r2^.Right;
  526. END (* LOOP *);
  527. END Eq;
  528. PROCEDURE SubSet( t2 : TABLE ) : BOOLEAN;
  529. (* Are the elements of 'THIS' table a sub set of the elements
  530. of the table 't2'?
  531. The procedure scans scans the trees in order looking for
  532. an initial point of equality. Then 'THIS' is compared to
  533. this sub-tree of 't2' until either an element greater than
  534. the current 'THIS' element is found, or 'THIS' is exhuasted.
  535. The process is implemented iteratively rather than
  536. recursively.
  537. *)
  538. VAR
  539. S1,
  540. S2 : ARRAY [1..32] OF ElementPtr;
  541. r1,
  542. r2,
  543. cr : ElementPtr;
  544. sp1,
  545. sp2 : CARDINAL;
  546. res : INTEGER;
  547. BEGIN
  548. IF (Root # NIL) AND (t2.Root # Root) AND (ADR(Root^.Compare) # ADR(t2.Root^.Compare)) THEN
  549. (* Both trees must contain the same type of element *)
  550. Lib.FatalError('different types');
  551. END;
  552. r1 := Root;
  553. r2 := t2.Root;
  554. sp1 := 0;
  555. sp2 := 0;
  556. LOOP
  557. WHILE (r1 # NIL) DO
  558. INC(sp1);
  559. S1[sp1] := r1;
  560. r1 := r1^.Left;
  561. END;
  562. IF (sp1 = 0) THEN (* End of 'THIS' => is a sub-tree *)
  563. RETURN TRUE;
  564. END;
  565. r1 := S1[sp1];
  566. DEC(sp1);
  567. cr := r1;
  568. r1 := r1^.Right;
  569. LOOP
  570. WHILE (r2 # NIL) DO
  571. INC(sp2);
  572. S2[sp2] := r2;
  573. r2 := r2^.Left;
  574. END;
  575. IF (sp2 = 0) THEN (* End of 't2' => not a sub-tree *)
  576. RETURN FALSE;
  577. ELSE
  578. r2 := S2[sp2];
  579. DEC(sp2);
  580. END;
  581. res := cr^.Compare(r2);
  582. r2 := r2^.Right;
  583. IF (res < 0) THEN
  584. RETURN FALSE;
  585. ELSIF (res = 0) THEN
  586. EXIT;
  587. END;
  588. END (* LOOP *);
  589. END (* LOOP *);
  590. END SubSet;
  591. PROCEDURE Copy() : TABLE;
  592. (* Make a copy of 'THIS' *)
  593. PROCEDURE _Copy( r : ElementPtr ) : ElementPtr;
  594. (* Recursively generate a copy of 'r' *)
  595. VAR
  596. x : ElementPtr;
  597. BEGIN
  598. IF (r # NIL) THEN
  599. ALLOCATE(x,SIZE(r^));
  600. Lib.Move(r,x,SIZE(r^));
  601. x^.Left := _Copy(r^.Left);
  602. x^.Right := _Copy(r^.Right);
  603. RETURN x;
  604. ELSE
  605. RETURN r;
  606. END;
  607. END _Copy;
  608. VAR
  609. NewTree : TABLE;
  610. BEGIN
  611. NewTree.Root := _Copy(Root);
  612. RETURN NewTree;
  613. END Copy;
  614. PROCEDURE Incl( t2 : TABLE);
  615. (* Include 't2' in 'THIS' tree *)
  616. PROCEDURE _Incl( r : ElementPtr );
  617. (* Recursively insert 'r' into 'THIS' *)
  618. BEGIN
  619. IF (r # NIL) THEN
  620. _Incl(r^.Left);
  621. _Incl(r^.Right);
  622. Insert(r^);
  623. END;
  624. END _Incl;
  625. BEGIN
  626. IF (Root # NIL) AND (t2.Root # Root) AND (ADR(Root^.Compare) # ADR(t2.Root^.Compare)) THEN
  627. Lib.FatalError('different types');
  628. END;
  629. _Incl(t2.Root);
  630. END Incl;
  631. PROCEDURE Excl( t2 : TABLE);
  632. (* Exclude elements of 't2' from 'THIS' *)
  633. PROCEDURE _Excl( r: ElementPtr );
  634. (* Recursively exclude 'r' from 'THIS' *)
  635. BEGIN
  636. IF (r # NIL) THEN
  637. _Excl(r^.Left);
  638. _Excl(r^.Right);
  639. Delete(r^);
  640. END;
  641. END _Excl;
  642. BEGIN
  643. IF (Root # NIL) AND (t2.Root # Root) AND (ADR(Root^.Compare) # ADR(t2.Root^.Compare)) THEN
  644. Lib.FatalError('different types');
  645. END;
  646. _Excl(t2.Root);
  647. END Excl;
  648. PROCEDURE Empty() : BOOLEAN;
  649. (* Is 'THIS' empty? *)
  650. BEGIN
  651. RETURN (Root = NIL);
  652. END Empty;
  653. PROCEDURE Dispose;
  654. (* Dispose of entire tree *)
  655. PROCEDURE _Dispose( r : ElementPtr );
  656. (* Recursively dispose of each element of 'r' *)
  657. BEGIN
  658. IF (r # NIL) THEN
  659. _Dispose(r^.Left); (* Delete left sub-tree *)
  660. _Dispose(r^.Right); (* Delete right sub-tree *)
  661. DISPOSE(r);
  662. END;
  663. END _Dispose;
  664. BEGIN
  665. _Dispose(Root);
  666. END Dispose;
  667. BEGIN
  668. END TABLE ;
  669. END Table.