Parcourir la source

docs: OOP reference notes (CLASS syntax sketch + Table example)

Eric Streit il y a 3 semaines
Parent
commit
392ba67cd5
1 fichiers modifiés avec 757 ajouts et 0 suppressions
  1. 757 0
      docs/OOP.txt

+ 757 - 0
docs/OOP.txt

@@ -0,0 +1,757 @@
+ClassDecl ::=
+	CLASS Classidentifier['(' Name { ',' Name } ')'] ';'
+		[ClassFieldDefList]
+		[MethodDecList]
+	END Classidentifier ';'
+	
+ClassFieldDefList ::=
+	ClassFieldDef {';' ClassFieldDef }
+	
+ClassFieldDef ::=
+	IdentifierList ':' TypeDef |
+	Identifier '=' Name
+	
+MethodDecList ::=
+	MethodDec {',' MethodDec }
+	
+MethodDec ::=
+	[VIRTUAL] PEOCEDURE MethodIdentifier
+	[FormalList [':' Name ]]
+	
+
+
+Example:
+
+(* ========================================== *)
+(* (c) 1990-1992 Clarion Software Corporation *)
+(* ========================================== *)
+
+DEFINITION MODULE Table;
+
+(*
+
+   This module implements classes that allow the creation and maintenance
+   of homogeneous tables of ordered objects. The internal structure of the
+   table is an AVL Balanced Tree. The algorithms are based on an example
+   given in Niklaus Wirth's "Algorithms + Data Structures = Programs". That
+   book also gives a detailed description of AVL Balanced Trees.
+
+*)
+
+TYPE
+
+    BalanceFlag = SHORTINT [-1..1];
+
+    ElementPtr  = POINTER TO Element;
+
+    CLASS Element;
+
+        Right   : ElementPtr;   (* Pointer to right sub-tree *)
+        Left    : ElementPtr;   (* Pointer to left sub-tree  *)
+        Bal     : BalanceFlag;  (* Tree balance flag         *)
+
+        VIRTUAL PROCEDURE Compare( p : ElementPtr ) : INTEGER;
+                            (*
+                               Must be implemented by the client. This
+                               procedure should return one of the
+                               following integer values:
+
+                                <0   if 'THIS' is less than 'p'
+                                 0   if 'THIS' is equal to 'p'
+                                >0   if 'THIS' is greater than 'p'
+                            *)
+
+    END Element ;
+
+TYPE
+
+    Action      = PROCEDURE ( ElementPtr );
+                            (* This procedure type is used by 'Apply' *)
+
+    CLASS TABLE;
+
+        Root    : ElementPtr;       (* The root of this tree *)
+
+        PROCEDURE Insert( VAR x : Element );
+                            (* Insert the element 'x' into this table       *)
+        PROCEDURE Find( VAR p : Element ) : BOOLEAN;
+                            (* Search table for a element matching 'p'.
+                               Returns 'TRUE' and sets all fields of 'p' if
+                               found; otherwise returns 'FALSE'
+                            *)
+        PROCEDURE Delete( VAR x : Element );
+                            (* Delete the element matching 'p' from table   *)
+        PROCEDURE Apply( p : Action );
+                            (* Apply procedure 'p' to all elements in order *)
+        PROCEDURE Init;
+                            (* Initialize the table                         *)
+        PROCEDURE Eq( t2 : TABLE ) : INTEGER;
+                            (* Compare 'THIS' with 't2'. The return values
+                               are:
+
+                                <0  'THIS' is less than 't2'
+                                 0  'THIS' is equal to 't2'
+                                >0  'THIS' is greater than 't2'
+
+                                ** RESTRICTION : Table must not generate a
+                                   tree greater than 32 levels deep (around
+                                   2^32 elements
+                            *)
+        PROCEDURE SubSet( t2 : TABLE ) : BOOLEAN;
+                            (* Are the elements in this table a subset of
+                               the elememts in table 't2'?                  *)
+        PROCEDURE Copy() : TABLE;
+                            (* Make a copy this table                       *)
+        PROCEDURE Incl( t2 : TABLE );
+                            (* Include elements from table 't2' in this
+                               table                                        *)
+        PROCEDURE Excl( t2 : TABLE );
+                            (* Exclude elements from table 't2' from this
+                               table                                        *)
+        PROCEDURE Empty() : BOOLEAN;
+                            (* Is this table empty? *)
+        PROCEDURE Dispose;
+                            (* Dispose of all elements of this table        *)
+
+    END TABLE ;
+
+END Table.
+
+
+(* ==================================================== *)
+(* Copyright (C) 1990-1992 Clarion Software Corporation *)
+(* ==================================================== *)
+
+IMPLEMENTATION MODULE Table;
+
+    IMPORT Lib;
+    FROM Storage IMPORT ALLOCATE, DEALLOCATE;
+
+
+        CLASS IMPLEMENTATION Element;
+
+            VIRTUAL PROCEDURE Compare( p : ElementPtr ) : INTEGER;
+            (* It is an error not to supply an implementation of this
+               method. The client MUST supply a method to compare
+               'THIS' with 'p'.
+            *)
+            BEGIN
+                Lib.FatalError(' implemeted by client ');
+                RETURN 0;
+            END Compare;
+
+        BEGIN
+        END Element ;
+
+        CLASS GenElem (Element) ;
+            GenericData : CHAR;
+        END GenElem;
+
+        CLASS IMPLEMENTATION GenElem;
+        BEGIN
+        END GenElem;
+
+TYPE
+        GenElemPtr = POINTER TO GenElem;
+            (* The above definitions are a skeleton for all the
+               implementation of the 'Element' CLASS. This enables
+               the 'TABLE' class to successfully copy any client
+               implementation of 'Element'
+            *)
+
+
+        CLASS IMPLEMENTATION TABLE;
+
+            PROCEDURE Insert( VAR  x : Element );
+                (* Insert a new element 'x' in 'THIS' table *)
+
+                PROCEDURE Search( VAR p : ElementPtr; VAR h : BOOLEAN);
+                (* Searches a tree 'p' for the element 'x'. If it is found
+                   then the new value replaces the old. If 'x' is not
+                   in the tree, then 'x' becomes a new leaf of the tree.
+                *)
+                    VAR
+                        p1    : ElementPtr;
+                        p2    : ElementPtr;
+
+                BEGIN
+                    IF (p = NIL) THEN       (* Create new leaf *)
+                        ALLOCATE(p,SIZE(x));
+                        Lib.Move(ADR(x),p,SIZE(x));
+                        p^.Bal := 0;
+                        p^.Left := NIL;
+                        p^.Right := NIL;
+                        h := TRUE;          (* Tree requires balancing *)
+                    ELSE
+                        IF (x.Compare(p) < 0) THEN (* 'THIS' is < 'p' *)
+                            (* Search the 'Left' branch of 'p' recursively
+                               until 'x' is either found or created.
+                            *)
+                            Search(p^.Left,h);
+                            IF h THEN        (* i.e. requires balancing *)
+                                CASE p^.Bal OF
+                                |  1 :
+                                    p^.Bal := 0;
+                                    h      := FALSE;
+                                |  0 :
+                                    p^.Bal := -1;
+                                | -1 :
+                                    p1 := p^.Left;
+                                    IF (p1^.Bal = -1) THEN
+                                        p^.Left   := p1^.Right;
+                                        p1^.Right := p;
+                                        p^.Bal    := 0;
+                                        p         := p1;
+                                    ELSE
+                                        p2        := p1^.Right;
+                                        p1^.Right := p2^.Left;
+                                        p2^.Left  := p1;
+                                        p^.Left   := p2^.Right;
+                                        p2^.Right := p;
+                                        IF (p2^.Bal = -1) THEN
+                                            p^.Bal  :=  1;
+                                        ELSE
+                                            p^.Bal  :=  0;
+                                        END;
+                                        IF (p2^.Bal = 1) THEN
+                                            p1^.Bal := -1;
+                                        ELSE
+                                            p1^.Bal :=  0;
+                                        END;
+                                        p := p2;
+                                    END;
+                                    p^.Bal := 0;
+                                    h      := FALSE; (* Balancing done *)
+                                END (* CASE *);
+                            END (* of balancing 'Left' sub-tree *);
+                        ELSIF (x.Compare(p) > 0) THEN (* 'THIS' > 'p' *)
+                            (* Search the 'Right' branch of 'p' recursively
+                               until 'x' is either found or created.
+                            *)
+                            Search( p^.Right,h);
+                            IF h THEN          (* i.e. tree needs balancing *)
+                                CASE p^.Bal OF
+                                | -1 :
+                                    p^.Bal := 0;
+                                    h      := FALSE;
+                                |  0 :
+                                    p^.Bal := 1;
+                                |  1 :
+                                    p1 := p^.Right;
+                                    IF (p1^.Bal = 1) THEN
+                                        p^.Right := p1^.Left;
+                                        p1^.Left := p;
+                                        p^.Bal   := 0;
+                                        p        := p1;
+                                    ELSE
+                                        p2        := p1^.Left;
+                                        p1^.Left  := p2^.Right;
+                                        p2^.Right := p1;
+                                        p^.Right  := p2^.Left;
+                                        p2^.Left  := p;
+                                        IF (p2^.Bal = 1) THEN
+                                            p^.Bal  := -1;
+                                        ELSE
+                                            p^.Bal  :=  0;
+                                        END;
+                                        IF (p2^.Bal = -1) THEN
+                                            p1^.Bal :=  1;
+                                        ELSE
+                                            p1^.Bal :=  0;
+                                        END;
+                                        p := p2;
+                                    END;
+                                    p^.Bal := 0;
+                                    h      := FALSE; (* Tree balanced *)
+                                END (* CASE *);
+                            END (* Balancing 'Right' sub-tree *);
+                        ELSE (* 'THIS' and 'p' are the same *)
+                           h := FALSE;
+                           Lib.Move(ADR(GenElemPtr(ADR(x))^.GenericData),
+                                    ADR(GenElemPtr(p)^.GenericData),
+                                    SIZE(x)-VSIZE(Element.Bal));
+                        END (* Possible comaprison results *);
+                    END;
+                END Search;
+
+                VAR
+                    h : BOOLEAN;
+
+            BEGIN
+                IF (Root # NIL) AND (ADR(Root^.Compare) # ADR(x.Compare)) THEN
+                    (* All table elements must be homogeneous; i.e. they must be of
+                       the same CLASS
+                    *)
+                    Lib.FatalError('object not compatible with table');
+                END;
+                Search(Root,h);
+            END Insert;
+
+            PROCEDURE Find( VAR x : Element ) : BOOLEAN;
+                (* Search for 'x' in 'THIS' tree; if 'x' is found in
+                   'THIS' tree then the function returns 'TRUE' and 'x'
+                   is set to the mathing element. Otherwise the
+                   method returns 'FALSE'.
+                *)
+
+                PROCEDURE _Find( r : ElementPtr ) : ElementPtr;
+                    (* Implements the search algorithm *)
+                BEGIN
+                    LOOP
+                        IF (r = NIL) THEN             (* No match *)
+                            RETURN r;
+                        ELSIF (x.Compare(r) < 0) THEN (* 'THIS' < r *)
+                            r := r^.Left;
+                        ELSIF (x.Compare(r) > 0) THEN (* 'THIS' > r *)
+                            r := r^.Right;
+                        ELSE                          (* FOUND IT! *)
+                            RETURN r;
+                        END;
+                   END (* LOOP *);
+                END _Find;
+
+                VAR
+                    p : ElementPtr;
+
+            BEGIN
+                p := _Find(Root);
+                IF (p # NIL) THEN (* Element Located *)
+                    Lib.Move(p,ADR(x),SIZE(x));
+                    RETURN TRUE;
+                ELSE
+                    RETURN FALSE;
+                END;
+            END Find;
+
+            PROCEDURE Delete( VAR x : Element );
+                (* Locate the element 'x' in 'THIS' tree and delete it *)
+                VAR
+                   q : ElementPtr;
+
+                PROCEDURE r_Balance( VAR p : ElementPtr; VAR h : BOOLEAN);
+                    (* Blance a right sub-tree *)
+                    VAR
+                        p1 : ElementPtr;
+                        p2 : ElementPtr;
+                        b1 : BalanceFlag;
+                        b2 : BalanceFlag;
+                BEGIN
+                    CASE p^.Bal OF
+                    | -1 :
+                        p^.Bal := 0;
+                    |  0 :
+                        p^.Bal := 1;
+                        h      := FALSE;
+                    |  1 :
+                        p1 := p^.Right;
+                        b1 := p1^.Bal;
+                        IF (b1 >= 0) THEN
+                            p^.Right := p1^.Left;
+                            p1^.Left := p;
+                            IF (b1 = 0) THEN
+                                p^.Bal  := 1;
+                                p1^.Bal := -1;
+                                h       := FALSE
+                            ELSE
+                                p^.Bal  := 0;
+                                p1^.Bal := 0;
+                            END;
+                            p := p1;
+                        ELSE
+                            p2 := p1^.Left;
+                            b2 := p2^.Bal;
+                            p1^.Left  := p2^.Right;
+                            p2^.Right := p1;
+                            p^.Right  := p2^.Left;
+                            p2^.Left  := p;
+                            IF (b2 = 1) THEN
+                                p^.Bal  := -1;
+                            ELSE
+                                p^.Bal  :=  0;
+                            END;
+                            IF (b2 = -1) THEN
+                                p1^.Bal :=  1;
+                            ELSE
+                                p1^.Bal :=  0;
+                            END;
+                            p       := p2;
+                            p2^.Bal := 0;
+                        END;
+                    END (* CASE *);
+                END r_Balance;
+
+                PROCEDURE l_Balance( VAR p : ElementPtr; VAR h : BOOLEAN);
+                    (* Balance a left sub-tree *)
+                    VAR
+                       p1 : ElementPtr;
+                       p2 : ElementPtr;
+                       b1 : BalanceFlag;
+                       b2 : BalanceFlag;
+                BEGIN
+                    CASE p^.Bal OF
+                    |  1 :
+                        p^.Bal := 0;
+                    |  0 :
+                        p^.Bal := -1;
+                        h      := FALSE;
+                    | -1 :
+                        p1 := p^.Left;
+                        b1 := p1^.Bal;
+                        IF (b1 <= 0) THEN
+                            p^.Left   := p1^.Right;
+                            p1^.Right := p;
+                            IF (b1 = 0) THEN
+                                p^.Bal  := -1;
+                                p1^.Bal := 1;
+                                h       := FALSE
+                            ELSE
+                                p^.Bal  := 0;
+                                p1^.Bal := 0;
+                            END;
+                            p := p1;
+                        ELSE
+                            p2        := p1^.Right;
+                            b2        := p2^.Bal;
+                            p1^.Right := p2^.Left;
+                            p2^.Left  := p1;
+                            p^.Left   := p2^.Right;
+                            p2^.Right := p;
+                            IF (b2 = -1) THEN
+                                p^.Bal  :=  1;
+                            ELSE
+                                p^.Bal  :=  0;
+                            END;
+                            IF (b2 = 1) THEN
+                                p1^.Bal := -1;
+                            ELSE
+                                p1^.Bal :=  0;
+                            END;
+                            p       := p2;
+                            p2^.Bal := 0;
+                        END;
+                    END (* CASE *);
+                END l_Balance;
+
+                PROCEDURE DeleteLeaf( VAR r : ElementPtr; VAR h : BOOLEAN );
+                    (* Recursively search for extreme right-hand node of
+                       the sub-tree 'r' and move data into 'q'
+                    *)
+                BEGIN
+                    IF (r^.Right # NIL) THEN
+                        DeleteLeaf(r^.Right,h);
+                        IF h THEN
+                            l_Balance(r,h);
+                        END;
+                    ELSE
+                        Lib.Move(ADR(GenElemPtr(r)^.GenericData),
+                                 ADR(GenElemPtr(q)^.GenericData),
+                                 SIZE(x)-VSIZE(Element.Bal));
+                        q := r;
+                        r := r^.Left;
+                        h := TRUE;
+                     END;
+                END DeleteLeaf;
+
+                PROCEDURE _Delete( VAR p : ElementPtr; VAR h : BOOLEAN );
+                    (* Main recursive deletion procedure *)
+                BEGIN
+                    IF (p = NIL) THEN                (* Not found *)
+                        h := FALSE;
+                    ELSIF (x.Compare(p) < 0) THEN    (* 'THIS' < 'p' *)
+                        _Delete(p^.Left,h);
+                        IF h THEN
+                            r_Balance(p,h);
+                        END;
+                    ELSIF (x.Compare(p) > 0) THEN    (* 'THIS' > 'p' *)
+                        _Delete(p^.Right,h);
+                        IF h THEN
+                            l_Balance(p,h);
+                        END;
+                    ELSE                             (* Found it! *)
+                        q := p;
+                        IF (q^.Right = NIL) THEN
+                            p := q^.Left;
+                            h := TRUE;
+                        ELSIF (q^.Left = NIL) THEN
+                            p := q^.Right;
+                            h := TRUE;
+                        ELSE
+                            DeleteLeaf(q^.Left,h);
+                            IF h THEN
+                                r_Balance(p,h);
+                            END;
+                        END;
+                        DISPOSE(q);
+                    END;
+                END _Delete;
+
+                VAR
+                   h : BOOLEAN;
+
+            BEGIN
+                IF (Root = NIL) THEN
+                    RETURN;
+                END;
+                IF (Root # NIL) AND (ADR(x.Compare) # ADR(Root^.Compare)) THEN
+                    (* 'x' is not the same type as tree members *)
+                    Lib.FatalError('object not compatible with table');
+                END;
+                _Delete(Root,h);
+            END Delete;
+
+            PROCEDURE Apply( p : Action );
+                (* Apply a procedure to all table elements in order *)
+
+                PROCEDURE ApplyToElement( s : ElementPtr );
+                    (* Apply 'p' to left sub-tree of s, then s, then the
+                       right sub-tree of s.
+                    *)
+                BEGIN
+                    IF (s = NIL) THEN
+                        RETURN;
+                    ELSE
+                        ApplyToElement(s^.Left);
+                        p(s);
+                        ApplyToElement(s^.Right);
+                    END;
+                END ApplyToElement;
+
+            BEGIN
+                ApplyToElement(Root);
+            END Apply;
+
+            PROCEDURE Init;
+                (* Initialise a tree *)
+            BEGIN
+                Root := NIL;
+            END Init;
+
+
+            PROCEDURE Eq( t2 : TABLE ) : INTEGER;
+                (* Compare 'THIS' to 't2'. Return values:
+
+                    <0  'THIS' is less than 't2'
+                     0  'THIS' is equal to 't2'
+                    >0  'THIS' is greater than 't2'
+
+                   The trees are searched from the bottom up (i.e. in
+                   order) and the elements compared. The procedure
+                   returns immediately a difference is detected or
+                   when both trees are exhausted (and, therefore, they
+                   must be equal). This process is implemented iteratively
+                   rather than recursively.
+                *)
+
+                VAR
+                  S1,
+                  S2    : ARRAY [1..32] OF ElementPtr;
+                  r1,
+                  r2    : ElementPtr;
+                  sp1,
+                  sp2   : CARDINAL;
+                  res   : INTEGER;
+
+            BEGIN
+                r1 := Root;
+                r2 := t2.Root;
+                IF (r1 # NIL) AND (r1 # r2) AND (ADR(r1^.Compare) # ADR(r2^.Compare)) THEN
+                    (* Both trees must contain the same sort of element *)
+                    Lib.FatalError(' not compareable ');
+                END;
+                sp1 := 0;
+                sp2 := 0;
+                LOOP
+                    WHILE (r1 # NIL) DO (* Build left edge array for 'THIS' *)
+                        INC(sp1);
+                        S1[sp1] := r1;
+                        r1 := r1^.Left;
+                    END;
+                    WHILE (r2 # NIL) DO (* Build left edge array for 't2' *)
+                        INC(sp2);
+                        S2[sp2] := r2;
+                        r2 := r2^.Left;
+                    END;
+                    IF (sp1 = 0) THEN (* No left sub-tree for 'THIS' *)
+                        IF (sp2 = 0) THEN (* No left sub-tree for 't2' *)
+                            RETURN 0; (* Implies they are equal *)
+                        ELSE
+                            RETURN -1; (* 'THIS' < 't2' *)
+                        END;
+                    ELSIF (sp2 = 0) THEN (* No left sub-tree for 't2' *)
+                        RETURN 1; (* 'THIS' > 't2' *)
+                    ELSE
+                        r1 := S1[sp1];
+                        DEC(sp1);
+                        r2 := S2[sp2];
+                        DEC(sp2);
+                    END;
+                    res := r1^.Compare(r2); (* Compare extreme left of both *)
+                    IF (res # 0) THEN (* These are different! *)
+                        RETURN res; (* Return how they are different *)
+                    END;
+                    r1 := r1^.Right;
+                    r2 := r2^.Right;
+                END (* LOOP *);
+            END Eq;
+
+            PROCEDURE SubSet( t2 : TABLE ) : BOOLEAN;
+                (* Are the elements of 'THIS' table a sub set of the elements
+                   of the table 't2'?
+                   The procedure scans scans the trees in order looking for
+                   an initial point of equality. Then 'THIS' is compared to
+                   this sub-tree of 't2' until either an element greater than
+                   the current 'THIS' element is found, or 'THIS' is exhuasted.
+                   The process is implemented iteratively rather than
+                   recursively.
+                *)
+                VAR
+                    S1,
+                    S2    : ARRAY [1..32] OF ElementPtr;
+                    r1,
+                    r2,
+                    cr    : ElementPtr;
+                    sp1,
+                    sp2   : CARDINAL;
+                    res   : INTEGER;
+            BEGIN
+                IF (Root # NIL) AND (t2.Root # Root) AND (ADR(Root^.Compare) # ADR(t2.Root^.Compare)) THEN
+                    (* Both trees must contain the same type of element *)
+                    Lib.FatalError('different types');
+                END;
+                r1 := Root;
+                r2 := t2.Root;
+                sp1 := 0;
+                sp2 := 0;
+                LOOP
+                    WHILE (r1 # NIL) DO
+                        INC(sp1);
+                        S1[sp1] := r1;
+                        r1 := r1^.Left;
+                    END;
+                    IF (sp1 = 0) THEN       (* End of 'THIS' => is a sub-tree *)
+                        RETURN TRUE;
+                    END;
+                    r1 := S1[sp1];
+                    DEC(sp1);
+                    cr := r1;
+                    r1 := r1^.Right;
+                    LOOP
+                        WHILE (r2 # NIL) DO
+                            INC(sp2);
+                            S2[sp2] := r2;
+                            r2 := r2^.Left;
+                        END;
+                        IF (sp2 = 0) THEN    (* End of 't2' => not a sub-tree *)
+                            RETURN FALSE;
+                        ELSE
+                            r2 := S2[sp2];
+                            DEC(sp2);
+                        END;
+                        res := cr^.Compare(r2);
+                        r2 := r2^.Right;
+                        IF (res < 0) THEN
+                            RETURN FALSE;
+                        ELSIF (res = 0) THEN
+                            EXIT;
+                        END;
+                    END (* LOOP *);
+                END (* LOOP *);
+            END SubSet;
+
+            PROCEDURE Copy() : TABLE;
+                (* Make a copy of 'THIS' *)
+
+                PROCEDURE _Copy( r : ElementPtr ) : ElementPtr;
+                    (* Recursively generate a copy of 'r' *)
+                    VAR
+                        x : ElementPtr;
+                BEGIN
+                    IF (r # NIL) THEN
+                        ALLOCATE(x,SIZE(r^));
+                        Lib.Move(r,x,SIZE(r^));
+                        x^.Left  := _Copy(r^.Left);
+                        x^.Right := _Copy(r^.Right);
+                        RETURN x;
+                    ELSE
+                        RETURN r;
+                    END;
+                END _Copy;
+
+            VAR
+                NewTree : TABLE;
+            BEGIN
+                NewTree.Root := _Copy(Root);
+               RETURN NewTree;
+            END Copy;
+
+            PROCEDURE Incl( t2 : TABLE);
+               (* Include 't2' in 'THIS' tree *)
+
+               PROCEDURE _Incl( r : ElementPtr );
+                   (* Recursively insert 'r' into 'THIS' *)
+               BEGIN
+                   IF (r # NIL) THEN
+                       _Incl(r^.Left);
+                       _Incl(r^.Right);
+                       Insert(r^);
+                   END;
+               END _Incl;
+
+            BEGIN
+                IF (Root # NIL) AND (t2.Root # Root) AND (ADR(Root^.Compare) # ADR(t2.Root^.Compare)) THEN
+                    Lib.FatalError('different types');
+                END;
+                _Incl(t2.Root);
+            END Incl;
+
+
+            PROCEDURE Excl( t2 : TABLE);
+                (* Exclude elements of 't2' from 'THIS' *)
+
+                PROCEDURE _Excl( r: ElementPtr );
+                    (* Recursively exclude 'r' from 'THIS' *)
+                BEGIN
+                    IF (r # NIL) THEN
+                        _Excl(r^.Left);
+                        _Excl(r^.Right);
+                        Delete(r^);
+                    END;
+                END _Excl;
+
+            BEGIN
+                IF (Root # NIL) AND (t2.Root # Root) AND (ADR(Root^.Compare) # ADR(t2.Root^.Compare)) THEN
+                    Lib.FatalError('different types');
+                END;
+                _Excl(t2.Root);
+            END Excl;
+
+            PROCEDURE Empty() : BOOLEAN;
+                (* Is 'THIS' empty? *)
+            BEGIN
+                RETURN (Root = NIL);
+            END Empty;
+
+            PROCEDURE Dispose;
+                (* Dispose of entire tree *)
+
+               PROCEDURE _Dispose( r : ElementPtr );
+                   (* Recursively dispose of each element of 'r' *)
+               BEGIN
+                   IF (r # NIL) THEN
+                       _Dispose(r^.Left);   (* Delete left sub-tree *)
+                       _Dispose(r^.Right);  (* Delete right sub-tree *)
+                       DISPOSE(r);
+                   END;
+               END _Dispose;
+
+            BEGIN
+                _Dispose(Root);
+            END Dispose;
+
+        BEGIN
+
+        END TABLE ;
+
+
+END Table.
+