]>
Commit | Line | Data |
---|---|---|
1eee94d3 GM |
1 | (* NameKey.mod provides a dynamic binary tree name to key. |
2 | ||
83ffe9cd | 3 | Copyright (C) 2001-2023 Free Software Foundation, Inc. |
1eee94d3 GM |
4 | Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>. |
5 | ||
6 | This file is part of GNU Modula-2. | |
7 | ||
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) | |
11 | any later version. | |
12 | ||
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. | |
17 | ||
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/>. *) | |
21 | ||
22 | IMPLEMENTATION MODULE NameKey ; | |
23 | ||
24 | ||
25 | FROM SYSTEM IMPORT ADR ; | |
26 | FROM Storage IMPORT ALLOCATE, DEALLOCATE ; | |
27 | FROM Indexing IMPORT Index, InitIndex, GetIndice, PutIndice, InBounds ; | |
28 | FROM StrIO IMPORT WriteString, WriteLn ; | |
29 | FROM StdIO IMPORT Write ; | |
30 | FROM NumberIO IMPORT WriteCard ; | |
31 | FROM StrLib IMPORT StrLen ; | |
32 | FROM libc IMPORT strlen ; | |
33 | FROM ASCII IMPORT nul ; | |
34 | ||
35 | ||
36 | TYPE | |
37 | PtrToChar = POINTER TO CHAR ; | |
38 | ||
39 | NameNode = POINTER TO Node ; | |
40 | Node = RECORD | |
41 | Data : PtrToChar ; | |
42 | Key : Name ; | |
43 | Left, | |
44 | Right: NameNode ; | |
45 | END ; | |
46 | ||
47 | Comparison = (less, equal, greater) ; | |
48 | ||
49 | VAR | |
50 | BinaryTree: NameNode ; | |
51 | KeyIndex : Index ; | |
52 | LastIndice: CARDINAL ; | |
53 | ||
54 | ||
55 | (* | |
56 | GetKey - returns the name, a, of the key, Key. | |
57 | *) | |
58 | ||
59 | PROCEDURE GetKey (key: Name; VAR a: ARRAY OF CHAR) ; | |
60 | VAR | |
61 | p : PtrToChar ; | |
62 | i, higha: CARDINAL ; | |
63 | BEGIN | |
64 | p := KeyToCharStar(key) ; | |
65 | i := 0 ; | |
66 | higha := HIGH(a) ; | |
67 | WHILE (p#NIL) AND (i<=higha) AND (p^#nul) DO | |
68 | a[i] := p^ ; | |
69 | INC(p) ; | |
70 | INC(i) | |
71 | END ; | |
72 | IF i<=higha | |
73 | THEN | |
74 | a[i] := nul | |
75 | END | |
76 | END GetKey ; | |
77 | ||
78 | ||
79 | (* | |
80 | IsKey - returns TRUE if string, a, is currently a key. | |
81 | We dont use the Compare function, we inline it and avoid | |
82 | converting, a, into a String, for speed. | |
83 | *) | |
84 | ||
85 | PROCEDURE IsKey (a: ARRAY OF CHAR) : BOOLEAN ; | |
86 | VAR | |
87 | child : NameNode ; | |
88 | p : PtrToChar ; | |
89 | i, | |
90 | higha : CARDINAL ; | |
91 | BEGIN | |
92 | (* firstly set up the initial values of child, using sentinal node *) | |
93 | child := BinaryTree^.Left ; | |
94 | IF child#NIL | |
95 | THEN | |
96 | REPEAT | |
97 | i := 0 ; | |
98 | higha := HIGH(a) ; | |
99 | p := KeyToCharStar(child^.Key) ; | |
100 | WHILE (i<=higha) AND (a[i]#nul) DO | |
101 | IF a[i]<p^ | |
102 | THEN | |
103 | child := child^.Left ; | |
104 | i := higha | |
105 | ELSIF a[i]>p^ | |
106 | THEN | |
107 | child := child^.Right ; | |
108 | i := higha | |
109 | ELSE | |
110 | IF (a[i]=nul) OR (i=higha) | |
111 | THEN | |
112 | IF p^=nul | |
113 | THEN | |
114 | RETURN( TRUE ) | |
115 | ELSE | |
116 | child := child^.Left | |
117 | END | |
118 | END ; | |
119 | INC(p) | |
120 | END ; | |
121 | INC(i) | |
122 | END ; | |
123 | UNTIL child=NIL | |
124 | END ; | |
125 | RETURN( FALSE ) ; | |
126 | END IsKey ; | |
127 | ||
128 | ||
129 | (* | |
130 | DoMakeKey - finds the name, n, in the tree or else create a name. | |
131 | If a name is found then the string, n, is deallocated. | |
132 | *) | |
133 | ||
134 | PROCEDURE DoMakeKey (n: PtrToChar; higha: CARDINAL) : Name ; | |
135 | VAR | |
136 | result: Comparison ; | |
137 | father, | |
138 | child : NameNode ; | |
139 | k : Name ; | |
140 | BEGIN | |
141 | result := FindNodeAndParentInTree(n, child, father) ; | |
142 | IF child=NIL | |
143 | THEN | |
144 | IF result=less | |
145 | THEN | |
146 | NEW(child) ; | |
147 | father^.Left := child | |
148 | ELSIF result=greater | |
149 | THEN | |
150 | NEW(child) ; | |
151 | father^.Right := child | |
152 | END ; | |
153 | WITH child^ DO | |
154 | Right := NIL ; | |
155 | Left := NIL ; | |
156 | INC(LastIndice) ; | |
157 | Key := LastIndice ; | |
158 | Data := n ; | |
159 | PutIndice(KeyIndex, Key, n) | |
160 | END ; | |
161 | k := LastIndice | |
162 | ELSE | |
163 | DEALLOCATE(n, higha+1) ; | |
164 | k := child^.Key | |
165 | END ; | |
166 | RETURN( k ) | |
167 | END DoMakeKey ; | |
168 | ||
169 | ||
170 | (* | |
171 | MakeKey - returns the Key of the symbol, a. If a is not in the | |
172 | name table then it is added, otherwise the Key of a is returned | |
173 | directly. Note that the name table has no scope - it merely | |
174 | presents a more convienient way of expressing strings. By a Key. | |
175 | *) | |
176 | ||
177 | PROCEDURE MakeKey (a: ARRAY OF CHAR) : Name ; | |
178 | VAR | |
179 | n, p : PtrToChar ; | |
180 | i, | |
181 | higha : CARDINAL ; | |
182 | BEGIN | |
183 | higha := StrLen(a) ; | |
184 | ALLOCATE(p, higha+1) ; | |
185 | IF p=NIL | |
186 | THEN | |
187 | HALT (* out of memory error *) | |
188 | ELSE | |
189 | n := p ; | |
190 | i := 0 ; | |
191 | WHILE i<higha DO | |
192 | p^ := a[i] ; | |
193 | INC(i) ; | |
194 | INC(p) | |
195 | END ; | |
196 | p^ := nul ; | |
197 | ||
198 | RETURN( DoMakeKey(n, higha) ) | |
199 | END | |
200 | END MakeKey ; | |
201 | ||
202 | ||
203 | (* | |
204 | makekey - returns the Key of the symbol, a. If a is not in the | |
205 | name table then it is added, otherwise the Key of a is returned | |
206 | directly. Note that the name table has no scope - it merely | |
207 | presents a more convienient way of expressing strings. By a Key. | |
208 | These keys last for the duration of compilation. | |
209 | *) | |
210 | ||
211 | PROCEDURE makekey (a: ADDRESS) : Name ; | |
212 | VAR | |
213 | n, | |
214 | p, pa : PtrToChar ; | |
215 | i, | |
216 | higha : CARDINAL ; | |
217 | BEGIN | |
218 | IF a=NIL | |
219 | THEN | |
220 | RETURN( NulName ) | |
221 | ELSE | |
222 | higha := strlen(a) ; | |
223 | ALLOCATE(p, higha+1) ; | |
224 | IF p=NIL | |
225 | THEN | |
226 | HALT (* out of memory error *) | |
227 | ELSE | |
228 | n := p ; | |
229 | pa := a ; | |
230 | i := 0 ; | |
231 | WHILE i<higha DO | |
232 | p^ := pa^ ; | |
233 | INC(i) ; | |
234 | INC(p) ; | |
235 | INC(pa) | |
236 | END ; | |
237 | p^ := nul ; | |
238 | ||
239 | RETURN( DoMakeKey(n, higha) ) | |
240 | END | |
241 | END | |
242 | END makekey ; | |
243 | ||
244 | ||
245 | (* | |
246 | LengthKey - returns the StrLen of Key. | |
247 | *) | |
248 | ||
249 | PROCEDURE LengthKey (Key: Name) : CARDINAL ; | |
250 | VAR | |
251 | i: CARDINAL ; | |
252 | p: PtrToChar ; | |
253 | BEGIN | |
254 | p := KeyToCharStar(Key) ; | |
255 | i := 0 ; | |
256 | WHILE p^#nul DO | |
257 | INC(i) ; | |
258 | INC(p) | |
259 | END ; | |
260 | RETURN( i ) | |
261 | END LengthKey ; | |
262 | ||
263 | ||
264 | (* | |
265 | Compare - return the result of Names[i] with Names[j] | |
266 | *) | |
267 | ||
268 | PROCEDURE Compare (pi: PtrToChar; j: Name) : Comparison ; | |
269 | VAR | |
270 | pj: PtrToChar ; | |
271 | c1, c2: CHAR ; | |
272 | BEGIN | |
273 | pj := KeyToCharStar(j) ; | |
274 | c1 := pi^ ; | |
275 | c2 := pj^ ; | |
276 | WHILE (c1#nul) OR (c2#nul) DO | |
277 | IF c1<c2 | |
278 | THEN | |
279 | RETURN( less ) | |
280 | ELSIF c1>c2 | |
281 | THEN | |
282 | RETURN( greater ) | |
283 | ELSE | |
284 | INC(pi) ; | |
285 | INC(pj) ; | |
286 | c1 := pi^ ; | |
287 | c2 := pj^ | |
288 | END | |
289 | END ; | |
290 | RETURN( equal ) | |
291 | END Compare ; | |
292 | ||
293 | ||
294 | (* | |
295 | FindNodeAndParentInTree - search BinaryTree for a name. | |
296 | If this name is found in the BinaryTree then | |
297 | child is set to this name and father is set to the node above. | |
298 | A comparison is returned to assist adding entries into this tree. | |
299 | *) | |
300 | ||
301 | PROCEDURE FindNodeAndParentInTree (n: PtrToChar; VAR child, father: NameNode) : Comparison ; | |
302 | VAR | |
303 | result: Comparison ; | |
304 | BEGIN | |
305 | (* firstly set up the initial values of child and father, using sentinal node *) | |
306 | father := BinaryTree ; | |
307 | child := BinaryTree^.Left ; | |
308 | IF child=NIL | |
309 | THEN | |
310 | RETURN( less ) | |
311 | ELSE | |
312 | REPEAT | |
313 | result := Compare(n, child^.Key) ; | |
314 | IF result=less | |
315 | THEN | |
316 | father := child ; | |
317 | child := child^.Left | |
318 | ELSIF result=greater | |
319 | THEN | |
320 | father := child ; | |
321 | child := child^.Right | |
322 | END | |
323 | UNTIL (child=NIL) OR (result=equal) ; | |
324 | RETURN( result ) | |
325 | END | |
326 | END FindNodeAndParentInTree ; | |
327 | ||
328 | ||
329 | (* | |
330 | IsSameExcludingCase - returns TRUE if key1 and key2 are | |
331 | the same. It is case insensitive. | |
332 | This function deliberately inlines CAP for speed. | |
333 | *) | |
334 | ||
335 | PROCEDURE IsSameExcludingCase (key1, key2: Name) : BOOLEAN ; | |
336 | VAR | |
337 | pi, pj: PtrToChar ; | |
338 | c1, c2: CHAR ; | |
339 | BEGIN | |
340 | IF key1=key2 | |
341 | THEN | |
342 | RETURN( TRUE ) | |
343 | ELSE | |
344 | pi := KeyToCharStar(key1) ; | |
345 | pj := KeyToCharStar(key2) ; | |
346 | c1 := pi^ ; | |
347 | c2 := pj^ ; | |
348 | WHILE (c1#nul) AND (c2#nul) DO | |
349 | IF (c1=c2) OR | |
350 | (((c1>='A') AND (c1<='Z')) AND (c2=CHR(ORD(c1)-ORD('A')+ORD('a')))) OR | |
351 | (((c2>='A') AND (c2<='Z')) AND (c1=CHR(ORD(c2)-ORD('A')+ORD('a')))) | |
352 | THEN | |
353 | INC(pi) ; | |
354 | INC(pj) ; | |
355 | c1 := pi^ ; | |
356 | c2 := pj^ | |
357 | ELSE | |
358 | (* difference found *) | |
359 | RETURN( FALSE ) | |
360 | END | |
361 | END ; | |
362 | RETURN( c1=c2 ) | |
363 | END | |
364 | END IsSameExcludingCase ; | |
365 | ||
366 | ||
367 | (* | |
368 | KeyToCharStar - returns the C char * string equivalent for, key. | |
369 | *) | |
370 | ||
371 | PROCEDURE KeyToCharStar (key: Name) : ADDRESS ; | |
372 | BEGIN | |
373 | IF (key=NulName) OR (NOT InBounds(KeyIndex, key)) | |
374 | THEN | |
375 | RETURN( NIL ) | |
376 | ELSE | |
377 | RETURN( GetIndice(KeyIndex, key) ) | |
378 | END | |
379 | END KeyToCharStar ; | |
380 | ||
381 | ||
382 | PROCEDURE WriteKey (key: Name) ; | |
383 | VAR | |
384 | s: PtrToChar ; | |
385 | BEGIN | |
386 | s := KeyToCharStar(key) ; | |
387 | WHILE (s#NIL) AND (s^#nul) DO | |
388 | Write(s^) ; | |
389 | INC(s) | |
390 | END | |
391 | END WriteKey ; | |
392 | ||
393 | ||
394 | (* | |
395 | CharKey - returns the key[i] character. | |
396 | *) | |
397 | ||
398 | PROCEDURE CharKey (key: Name; i: CARDINAL) : CHAR ; | |
399 | VAR | |
400 | p: PtrToChar ; | |
401 | BEGIN | |
402 | IF i >= LengthKey (key) | |
403 | THEN | |
404 | HALT | |
405 | END ; | |
406 | p := KeyToCharStar (key) ; | |
407 | INC (p, i) ; | |
408 | RETURN p^ | |
409 | END CharKey ; | |
410 | ||
411 | ||
412 | BEGIN | |
413 | LastIndice := 0 ; | |
414 | KeyIndex := InitIndex(1) ; | |
415 | NEW(BinaryTree) ; | |
416 | BinaryTree^.Left := NIL | |
417 | END NameKey. |