OOP.txt 32 KB

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