]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/m2/gm2-compiler/SymbolKey.mod
Update copyright years.
[thirdparty/gcc.git] / gcc / m2 / gm2-compiler / SymbolKey.mod
CommitLineData
1eee94d3
GM
1(* SymbolKey.mod binary tree operations for storing symbols.
2
a945c346 3Copyright (C) 2001-2024 Free Software Foundation, Inc.
1eee94d3
GM
4Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
5
6This file is part of GNU Modula-2.
7
8GNU Modula-2 is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation; either version 3, or (at your option)
11any later version.
12
13GNU Modula-2 is distributed in the hope that it will be useful, but
14WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with GNU Modula-2; see the file COPYING3. If not see
20<http://www.gnu.org/licenses/>. *)
21
22IMPLEMENTATION MODULE SymbolKey ;
23
24
25FROM Storage IMPORT ALLOCATE, DEALLOCATE ;
26FROM StrIO IMPORT WriteString, WriteLn ;
27FROM NumberIO IMPORT WriteCard ;
28FROM NameKey IMPORT WriteKey ;
29FROM Assertion IMPORT Assert ;
30FROM Debug IMPORT Halt ;
31
32
33TYPE
34 SymbolTree = POINTER TO Node ;
35 Node = RECORD
36 KeyName : Name ; (* The sorted entity *)
37 KeySym : WORD ; (* The value entity *)
38 Left : SymbolTree ;
39 Right : SymbolTree ;
40 END ;
41
42
43PROCEDURE InitTree (VAR t: SymbolTree) ;
44BEGIN
45 NEW(t) ;
46 WITH t^ DO
47 Left := NIL ;
48 Right := NIL
49 END
50END InitTree ;
51
52
53(*
54 we used to get problems compiling KillTree below - so it was split
55 into the two procedures below.
56
57
58PROCEDURE KillTree (VAR t: SymbolTree) ;
59BEGIN
60 IF t#NIL
61 THEN
62 Kill(t) ; (* Would like to place Kill in here but the compiler *)
63 (* gives a type incompatible error... so i've split *)
64 (* the procedure into two. - Problem i think with *)
65 (* VAR t at the top? *)
66 t := NIL
67 END
68END KillTree ;
69
70
71PROCEDURE Kill (t: SymbolTree) ;
72BEGIN
73 IF t#NIL
74 THEN
75 Kill(t^.Left) ;
76 Kill(t^.Right) ;
77 DISPOSE(t)
78 END
79END Kill ;
80*)
81
82
83PROCEDURE KillTree (VAR t: SymbolTree) ;
84BEGIN
85 IF t#NIL
86 THEN
87 KillTree(t^.Left) ;
88 KillTree(t^.Right) ;
89 DISPOSE(t) ;
90 t := NIL
91 END
92END KillTree ;
93
94
95(*
96 ContainsSymKey - return TRUE if tree, t, contains an entry for, NameKey.
97*)
98
99PROCEDURE ContainsSymKey (t: SymbolTree; NameKey: Name) : BOOLEAN ;
100VAR
101 father,
102 child : SymbolTree ;
103BEGIN
104 FindNodeParentInTree(t, NameKey, child, father) ;
105 RETURN child#NIL
106END ContainsSymKey ;
107
108
109PROCEDURE GetSymKey (t: SymbolTree; NameKey: Name) : WORD ;
110VAR
111 father,
112 child : SymbolTree ;
113BEGIN
114 FindNodeParentInTree(t, NameKey, child, father) ;
115 IF child=NIL
116 THEN
117 RETURN NulKey
118 ELSE
119 RETURN child^.KeySym
120 END
121END GetSymKey ;
122
123
124PROCEDURE PutSymKey (t: SymbolTree; NameKey: Name; SymKey: WORD) ;
125VAR
126 father,
127 child : SymbolTree ;
128BEGIN
129 FindNodeParentInTree(t, NameKey, child, father) ;
130 IF child=NIL
131 THEN
132 (* no child found, now is NameKey less than father or greater? *)
133 IF father=t
134 THEN
135 (* empty tree, add it to the left branch of t *)
136 NEW(child) ;
137 father^.Left := child
138 ELSE
139 IF NameKey<father^.KeyName
140 THEN
141 NEW(child) ;
142 father^.Left := child
143 ELSIF NameKey>father^.KeyName
144 THEN
145 NEW(child) ;
146 father^.Right := child
147 END
148 END ;
149 WITH child^ DO
150 Right := NIL ;
151 Left := NIL ;
152 KeySym := SymKey ;
153 KeyName := NameKey
154 END
155 ELSE
77924dff 156 Halt('symbol already stored', __FILE__, __FUNCTION__, __LINE__)
1eee94d3
GM
157 END
158END PutSymKey ;
159
160
161(*
162 DelSymKey - deletes an entry in the binary tree.
163
164 NB in order for this to work we must ensure that the InitTree sets
165 both Left and Right to NIL.
166*)
167
168PROCEDURE DelSymKey (t: SymbolTree; NameKey: Name) ;
169VAR
170 i, child, father: SymbolTree ;
171BEGIN
172 FindNodeParentInTree(t, NameKey, child, father) ; (* find father and child of the node *)
173 IF (child#NIL) AND (child^.KeyName=NameKey)
174 THEN
175 (* Have found the node to be deleted *)
176 IF father^.Right=child
177 THEN
178 (* Node is child and this is greater than the father. *)
179 (* Greater being on the right. *)
180 (* Connect child^.Left onto the father^.Right. *)
181 (* Connect child^.Right onto the end of the right *)
182 (* most branch of child^.Left. *)
183 IF child^.Left#NIL
184 THEN
185 (* Scan for Right most node of child^.Left *)
186 i := child^.Left ;
187 WHILE i^.Right#NIL DO
188 i := i^.Right
189 END ;
190 i^.Right := child^.Right ;
191 father^.Right := child^.Left
192 ELSE
193 (* No child^.Left node therefore link over child *)
194 (* (as in a single linked list) to child^.Right *)
195 father^.Right := child^.Right
196 END ;
197 DISPOSE(child)
198 ELSE
199 (* Assert that father^.Left=child will always be true *)
200 (* Perform exactly the mirror image of the above code *)
201
202 (* Connect child^.Right onto the father^.Left. *)
203 (* Connect child^.Left onto the end of the Left most *)
204 (* branch of child^.Right *)
205 IF child^.Right#NIL
206 THEN
207 (* Scan for Left most node of child^.Right *)
208 i := child^.Right ;
209 WHILE i^.Left#NIL DO
210 i := i^.Left
211 END ;
212 i^.Left := child^.Left ;
213 father^.Left := child^.Right
214 ELSE
215 (* No child^.Right node therefore link over c *)
216 (* (as in a single linked list) to child^.Left. *)
217 father^.Left := child^.Left
218 END ;
219 DISPOSE(child)
220 END
221 ELSE
222 Halt('trying to delete a symbol that is not in the tree - the compiler never expects this to occur',
77924dff 223 __FILE__, __FUNCTION__, __LINE__)
1eee94d3
GM
224 END
225END DelSymKey ;
226
227
228(*
229 FindNodeParentInTree - find a node, child, in a binary tree, t, with name equal to n.
230 if an entry is found, parent is set to the node above child.
231*)
232
233PROCEDURE FindNodeParentInTree (t: SymbolTree; n: Name;
234 VAR child, parent: SymbolTree) ;
235BEGIN
236 (* remember to skip the sentinal value and assign parent and child *)
237 parent := t ;
238 IF t=NIL
239 THEN
77924dff
GM
240 Halt('parameter t should never be NIL',
241 __FILE__, __FUNCTION__, __LINE__)
1eee94d3
GM
242 END ;
243 Assert (t^.Right = NIL) ;
244 child := t^.Left ;
245 IF child#NIL
246 THEN
247 REPEAT
248 IF n<child^.KeyName
249 THEN
250 parent := child ;
251 child := child^.Left
252 ELSIF n>child^.KeyName
253 THEN
254 parent := child ;
255 child := child^.Right
256 END
257 UNTIL (child=NIL) OR (n=child^.KeyName)
258 END
259END FindNodeParentInTree ;
260
261
262(*
263 IsEmptyTree - returns true if SymbolTree, t, is empty.
264*)
265
266PROCEDURE IsEmptyTree (t: SymbolTree) : BOOLEAN ;
267BEGIN
268 RETURN t^.Left = NIL
269END IsEmptyTree ;
270
271
272(*
273 DoesTreeContainAny - returns true if SymbolTree, t, contains any
274 symbols which in turn return true when procedure,
275 P, is called with a symbol as its parameter.
276 The SymbolTree root is empty apart from the field,
277 Left, hence we need two procedures.
278*)
279
280PROCEDURE DoesTreeContainAny (t: SymbolTree; P: IsSymbol) : BOOLEAN ;
281BEGIN
282 RETURN SearchForAny (t^.Left, P)
283END DoesTreeContainAny ;
284
285
286(*
287 SearchForAny - performs the search required for DoesTreeContainAny.
288 The root node always contains a nul data value,
289 therefore we must skip over it.
290*)
291
292PROCEDURE SearchForAny (t: SymbolTree; P: IsSymbol) : BOOLEAN ;
293BEGIN
294 IF t=NIL
295 THEN
296 RETURN FALSE
297 ELSE
298 RETURN( P (t^.KeySym) OR
299 SearchForAny (t^.Left, P) OR
300 SearchForAny(t^.Right, P)
301 )
302 END
303END SearchForAny ;
304
305
306(*
307 ForeachNodeDo - for each node in SymbolTree, t, a procedure, P,
308 is called with the node symbol as its parameter.
309 The tree root node only contains a legal Left pointer,
310 therefore we need two procedures to examine this tree.
311*)
312
313PROCEDURE ForeachNodeDo (t: SymbolTree; P: PerformOperation) ;
314BEGIN
29c82c6c 315 SearchAndDo (t^.Left, P)
1eee94d3
GM
316END ForeachNodeDo ;
317
318
319(*
320 SearchAndDo - searches all the nodes in SymbolTree, t, and
321 calls procedure, P, with a node as its parameter.
322 It traverse the tree in order.
323*)
324
325PROCEDURE SearchAndDo (t: SymbolTree; P: PerformOperation) ;
326BEGIN
327 IF t#NIL
328 THEN
329 WITH t^ DO
29c82c6c
GM
330 SearchAndDo (Right, P) ;
331 P (KeySym) ;
332 SearchAndDo (Left, P)
1eee94d3
GM
333 END
334 END
335END SearchAndDo ;
336
337
338(*
339 CountNodes - wrapper for NoOfNodes.
340*)
341
342PROCEDURE CountNodes (t: SymbolTree; condition: IsSymbol; count: CARDINAL) : CARDINAL ;
343BEGIN
344 IF t # NIL
345 THEN
346 WITH t^ DO
347 IF condition (KeySym)
348 THEN
349 INC (count)
350 END ;
351 count := CountNodes (Left, condition, count) ;
352 count := CountNodes (Right, condition, count)
353 END
354 END ;
355 RETURN count
356END CountNodes ;
357
358
359(*
360 NoOfNodes - returns the number of nodes in the tree t.
361*)
362
363PROCEDURE NoOfNodes (t: SymbolTree; condition: IsSymbol) : CARDINAL ;
364BEGIN
365 RETURN CountNodes (t^.Left, condition, 0)
366END NoOfNodes ;
367
368
369(*
370 SearchConditional - wrapper for ForeachNodeConditionDo.
371*)
372
373PROCEDURE SearchConditional (t: SymbolTree; condition: IsSymbol; P: PerformOperation) ;
374BEGIN
375 IF t#NIL
376 THEN
377 WITH t^ DO
378 SearchConditional (Right, condition, P) ;
379 IF (KeySym # 0) AND condition (KeySym)
380 THEN
381 P (KeySym)
382 END ;
383 SearchConditional (Left, condition, P)
384 END
385 END
386END SearchConditional ;
387
388
389(*
390 ForeachNodeConditionDo - traverse the tree t and for any node which satisfied
391 condition call P.
392*)
393
394PROCEDURE ForeachNodeConditionDo (t: SymbolTree;
395 condition: IsSymbol;
396 P: PerformOperation) ;
397BEGIN
398 IF t#NIL
399 THEN
400 WITH t^ DO
401 Assert (Right = NIL) ;
402 SearchConditional (Left, condition, P)
403 END
404 END
405END ForeachNodeConditionDo ;
406
407
408END SymbolKey.