1 (* symbolKey.mod provides binary tree operations for storing symbols.
3 Copyright (C) 2015-2024 Free Software Foundation, Inc.
4 Contributed by Gaius Mulley <gaius@glam.ac.uk>.
6 This file is part of GNU Modula-2.
8 GNU Modula-2 is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
13 GNU Modula-2 is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Modula-2; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. *)
22 IMPLEMENTATION MODULE symbolKey
;
25 FROM Storage
IMPORT ALLOCATE
, DEALLOCATE
;
26 FROM StrIO
IMPORT WriteString
, WriteLn
;
27 FROM NumberIO
IMPORT WriteCard
;
28 FROM Debug
IMPORT Halt
;
30 FROM nameKey
IMPORT writeKey
;
34 symbolTree
= POINTER TO RECORD
35 name
: Name
; (* The sorted entity *)
36 key
: ADDRESS
; (* The value entity *)
42 PROCEDURE initTree () : symbolTree
;
55 PROCEDURE killTree (VAR t
: symbolTree
) ;
67 PROCEDURE getSymKey (t
: symbolTree
; name
: Name
) : ADDRESS
;
76 findNodeAndParentInTree (t
, name
, child
, father
) ;
87 PROCEDURE putSymKey (t
: symbolTree
; name
: Name
; key
: ADDRESS
) ;
92 findNodeAndParentInTree (t
, name
, child
, father
) ;
95 (* no child found, now is name less than father or greater? *)
98 (* empty tree, add it to the left branch of t *)
100 father^.left
:= child
105 father^.left
:= child
106 ELSIF name
>father^.name
109 father^.right
:= child
119 Halt ('symbol already stored', __FILE__
, __FUNCTION__
, __LINE__
)
125 delSymKey - deletes an entry in the binary tree.
127 NB in order for this to work we must ensure that the InitTree sets
128 both left and right to NIL.
131 PROCEDURE delSymKey (t
: symbolTree
; name
: Name
) ;
133 i
, child
, father
: symbolTree
;
135 findNodeAndParentInTree (t
, name
, child
, father
) ; (* find father and child of the node *)
136 IF (child#
NIL) AND (child^.name
=name
)
138 (* Have found the node to be deleted *)
139 IF father^.right
=child
141 (* Node is child and this is greater than the father. *)
142 (* Greater being on the right. *)
143 (* Connect child^.left onto the father^.right. *)
144 (* Connect child^.right onto the end of the right *)
145 (* most branch of child^.left. *)
148 (* Scan for right most node of child^.left *)
150 WHILE i^.right#
NIL DO
153 i^.right
:= child^.right
;
154 father^.right
:= child^.left
156 (* No child^.left node therefore link over child *)
157 (* (as in a single linked list) to child^.right *)
158 father^.right
:= child^.right
162 (* Assert that father^.left=child will always be true *)
163 (* Perform exactly the mirror image of the above code *)
165 (* Connect child^.right onto the father^.left. *)
166 (* Connect child^.left onto the end of the left most *)
167 (* branch of child^.right *)
170 (* Scan for left most node of child^.right *)
175 i^.left
:= child^.left
;
176 father^.left
:= child^.right
178 (* No child^.right node therefore link over c *)
179 (* (as in a single linked list) to child^.left. *)
180 father^.left
:= child^.left
185 Halt ('trying to delete a symbol that is not in the tree - the compiler never expects this to occur',
186 __FILE__
, __FUNCTION__
, __LINE__
)
192 findNodeAndParentInTree - find a node, child, in a binary tree, t, with name equal to n.
193 if an entry is found, father is set to the node above child.
196 PROCEDURE findNodeAndParentInTree (t
: symbolTree
; n
: Name
;
197 VAR child
, father
: symbolTree
) ;
199 (* remember to skip the sentinal value and assign father and child *)
203 Halt ('parameter t should never be NIL', __FILE__
, __FUNCTION__
, __LINE__
)
216 child
:= child^.right
218 UNTIL (child
=NIL) OR (n
=child^.name
)
220 END findNodeAndParentInTree
;
224 isEmptyTree - returns true if symbolTree, t, is empty.
227 PROCEDURE isEmptyTree (t
: symbolTree
) : BOOLEAN ;
234 doesTreeContainAny - returns true if symbolTree, t, contains any
235 symbols which in turn return true when procedure,
236 p, is called with a symbol as its parameter.
237 The symbolTree root is empty apart from the field,
238 left, hence we need two procedures.
241 PROCEDURE doesTreeContainAny (t
: symbolTree
; p
: isSymbol
) : BOOLEAN ;
243 RETURN searchForAny (t^.left
, p
)
244 END doesTreeContainAny
;
248 searchForAny - performs the search required for doesTreeContainAny.
249 The root node always contains a nul data value,
250 therefore we must skip over it.
253 PROCEDURE searchForAny (t
: symbolTree
; p
: isSymbol
) : BOOLEAN ;
260 searchForAny (t^.left
, p
) OR
261 searchForAny (t^.right
, p
)
267 foreachNodeDo - for each node in symbolTree, t, a procedure, p,
268 is called with the node symbol as its parameter.
269 The tree root node only contains a legal left pointer,
270 therefore we need two procedures to examine this tree.
273 PROCEDURE foreachNodeDo (t
: symbolTree
; p
: performOperation
) ;
275 searchAndDo (t^.left
, p
)
280 searchAndDo - searches all the nodes in symbolTree, t, and
281 calls procedure, p, with a node as its parameter.
282 It traverse the tree in order.
285 PROCEDURE searchAndDo (t
: symbolTree
; p
: performOperation
) ;
290 searchAndDo (right
, p
) ;
292 searchAndDo (left
, p
)