mirror of
https://forge.sourceware.org/marek/gcc.git
synced 2026-02-22 03:47:02 -05:00
451 lines
10 KiB
Modula-2
451 lines
10 KiB
Modula-2
(* NameKey.mod provides a dynamic binary tree name to key.
|
|
|
|
Copyright (C) 2001-2026 Free Software Foundation, Inc.
|
|
Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
|
|
|
|
This file is part of GNU Modula-2.
|
|
|
|
GNU Modula-2 is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3, or (at your option)
|
|
any later version.
|
|
|
|
GNU Modula-2 is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with GNU Modula-2; see the file COPYING3. If not see
|
|
<http://www.gnu.org/licenses/>. *)
|
|
|
|
IMPLEMENTATION MODULE NameKey ;
|
|
|
|
|
|
FROM SYSTEM IMPORT ADR ;
|
|
FROM Storage IMPORT ALLOCATE, DEALLOCATE ;
|
|
FROM Indexing IMPORT Index, InitIndex, GetIndice, PutIndice, InBounds ;
|
|
FROM StrIO IMPORT WriteString, WriteLn ;
|
|
FROM StdIO IMPORT Write ;
|
|
FROM NumberIO IMPORT WriteCard ;
|
|
FROM StrLib IMPORT StrLen ;
|
|
FROM libc IMPORT strlen ;
|
|
FROM ASCII IMPORT nul ;
|
|
(* FROM M2Diagnostic IMPORT Diagnostic, InitMemDiagnostic, MemIncr, MemDecr, MemSet ; *)
|
|
|
|
|
|
TYPE
|
|
PtrToChar = POINTER TO CHAR ;
|
|
|
|
NameNode = POINTER TO Node ;
|
|
Node = RECORD
|
|
Data : PtrToChar ;
|
|
Key : Name ;
|
|
Left,
|
|
Right: NameNode ;
|
|
END ;
|
|
|
|
Comparison = (less, equal, greater) ;
|
|
|
|
VAR
|
|
BinaryTree: NameNode ;
|
|
KeyIndex : Index ;
|
|
LastIndice: CARDINAL ;
|
|
(*
|
|
NameKeyTreeMemDiag,
|
|
NameKeyWordMemDiag: Diagnostic ;
|
|
*)
|
|
|
|
|
|
(*
|
|
GetKey - returns the name, a, of the key, Key.
|
|
*)
|
|
|
|
PROCEDURE GetKey (key: Name; VAR a: ARRAY OF CHAR) ;
|
|
VAR
|
|
p : PtrToChar ;
|
|
i, higha: CARDINAL ;
|
|
BEGIN
|
|
p := KeyToCharStar(key) ;
|
|
i := 0 ;
|
|
higha := HIGH(a) ;
|
|
WHILE (p#NIL) AND (i<=higha) AND (p^#nul) DO
|
|
a[i] := p^ ;
|
|
INC(p) ;
|
|
INC(i)
|
|
END ;
|
|
IF i<=higha
|
|
THEN
|
|
a[i] := nul
|
|
END
|
|
END GetKey ;
|
|
|
|
|
|
(*
|
|
IsKey - returns TRUE if string, a, is currently a key.
|
|
We dont use the Compare function, we inline it and avoid
|
|
converting, a, into a String, for speed.
|
|
*)
|
|
|
|
PROCEDURE IsKey (a: ARRAY OF CHAR) : BOOLEAN ;
|
|
VAR
|
|
child : NameNode ;
|
|
p : PtrToChar ;
|
|
i,
|
|
higha : CARDINAL ;
|
|
BEGIN
|
|
(* firstly set up the initial values of child, using sentinal node *)
|
|
child := BinaryTree^.Left ;
|
|
IF child#NIL
|
|
THEN
|
|
REPEAT
|
|
i := 0 ;
|
|
higha := HIGH(a) ;
|
|
p := KeyToCharStar(child^.Key) ;
|
|
WHILE (i<=higha) AND (a[i]#nul) DO
|
|
IF a[i]<p^
|
|
THEN
|
|
child := child^.Left ;
|
|
i := higha
|
|
ELSIF a[i]>p^
|
|
THEN
|
|
child := child^.Right ;
|
|
i := higha
|
|
ELSE
|
|
IF (a[i]=nul) OR (i=higha)
|
|
THEN
|
|
IF p^=nul
|
|
THEN
|
|
RETURN( TRUE )
|
|
ELSE
|
|
child := child^.Left
|
|
END
|
|
END ;
|
|
INC(p)
|
|
END ;
|
|
INC(i)
|
|
END ;
|
|
UNTIL child=NIL
|
|
END ;
|
|
RETURN( FALSE ) ;
|
|
END IsKey ;
|
|
|
|
|
|
(*
|
|
DoMakeKey - finds the name, n, in the tree or else create a name.
|
|
If a name is found then the string, n, is deallocated.
|
|
*)
|
|
|
|
PROCEDURE DoMakeKey (n: PtrToChar; higha: CARDINAL) : Name ;
|
|
VAR
|
|
result: Comparison ;
|
|
father,
|
|
child : NameNode ;
|
|
k : Name ;
|
|
BEGIN
|
|
result := FindNodeAndParentInTree(n, child, father) ;
|
|
IF child=NIL
|
|
THEN
|
|
IF result=less
|
|
THEN
|
|
NEW(child) ;
|
|
father^.Left := child ;
|
|
(*
|
|
MemIncr (NameKeyTreeMemDiag, 1, 1) ;
|
|
MemIncr (NameKeyTreeMemDiag, 2, SIZE (child^))
|
|
*)
|
|
ELSIF result=greater
|
|
THEN
|
|
NEW(child) ;
|
|
father^.Right := child ;
|
|
(*
|
|
MemIncr (NameKeyTreeMemDiag, 1, 1) ;
|
|
MemIncr (NameKeyTreeMemDiag, 2, SIZE (child^))
|
|
*)
|
|
END ;
|
|
WITH child^ DO
|
|
Right := NIL ;
|
|
Left := NIL ;
|
|
INC(LastIndice) ;
|
|
Key := LastIndice ;
|
|
Data := n ;
|
|
PutIndice(KeyIndex, Key, n)
|
|
END ;
|
|
k := LastIndice
|
|
ELSE
|
|
DEALLOCATE(n, higha+1) ;
|
|
k := child^.Key ;
|
|
(*
|
|
MemDecr (NameKeyWordMemDiag, 1, 1) ;
|
|
MemDecr (NameKeyWordMemDiag, 2, higha + 1)
|
|
*)
|
|
END ;
|
|
RETURN( k )
|
|
END DoMakeKey ;
|
|
|
|
|
|
(*
|
|
MakeKey - returns the Key of the symbol, a. If a is not in the
|
|
name table then it is added, otherwise the Key of a is returned
|
|
directly. Note that the name table has no scope - it merely
|
|
presents a more convienient way of expressing strings. By a Key.
|
|
*)
|
|
|
|
PROCEDURE MakeKey (a: ARRAY OF CHAR) : Name ;
|
|
VAR
|
|
n, p : PtrToChar ;
|
|
i,
|
|
higha : CARDINAL ;
|
|
BEGIN
|
|
higha := StrLen(a) ;
|
|
ALLOCATE(p, higha+1) ;
|
|
(*
|
|
MemIncr (NameKeyWordMemDiag, 1, 1) ;
|
|
MemIncr (NameKeyWordMemDiag, 2, higha + 1) ;
|
|
*)
|
|
IF p=NIL
|
|
THEN
|
|
HALT (* Out of memory error. *)
|
|
ELSE
|
|
n := p ;
|
|
i := 0 ;
|
|
WHILE i<higha DO
|
|
p^ := a[i] ;
|
|
INC(i) ;
|
|
INC(p)
|
|
END ;
|
|
p^ := nul ;
|
|
RETURN( DoMakeKey(n, higha) )
|
|
END
|
|
END MakeKey ;
|
|
|
|
|
|
(*
|
|
makekey - returns the Key of the symbol, a. If a is not in the
|
|
name table then it is added, otherwise the Key of a is returned
|
|
directly. Note that the name table has no scope - it merely
|
|
presents a more convienient way of expressing strings. By a Key.
|
|
These keys last for the duration of compilation.
|
|
*)
|
|
|
|
PROCEDURE makekey (a: ADDRESS) : Name ;
|
|
VAR
|
|
n,
|
|
p, pa : PtrToChar ;
|
|
i,
|
|
higha : CARDINAL ;
|
|
BEGIN
|
|
IF a=NIL
|
|
THEN
|
|
RETURN( NulName )
|
|
ELSE
|
|
higha := strlen(a) ;
|
|
ALLOCATE(p, higha+1) ;
|
|
IF p=NIL
|
|
THEN
|
|
HALT (* Out of memory error. *)
|
|
ELSE
|
|
n := p ;
|
|
pa := a ;
|
|
i := 0 ;
|
|
WHILE i<higha DO
|
|
p^ := pa^ ;
|
|
INC(i) ;
|
|
INC(p) ;
|
|
INC(pa)
|
|
END ;
|
|
p^ := nul ;
|
|
|
|
RETURN( DoMakeKey(n, higha) )
|
|
END
|
|
END
|
|
END makekey ;
|
|
|
|
|
|
(*
|
|
LengthKey - returns the StrLen of Key.
|
|
*)
|
|
|
|
PROCEDURE LengthKey (Key: Name) : CARDINAL ;
|
|
VAR
|
|
i: CARDINAL ;
|
|
p: PtrToChar ;
|
|
BEGIN
|
|
i := 0 ;
|
|
IF Key # NulName
|
|
THEN
|
|
p := KeyToCharStar (Key) ;
|
|
WHILE p^ # nul DO
|
|
INC (i) ;
|
|
INC (p)
|
|
END
|
|
END ;
|
|
RETURN i
|
|
END LengthKey ;
|
|
|
|
|
|
(*
|
|
Compare - return the result of Names[i] with Names[j]
|
|
*)
|
|
|
|
PROCEDURE Compare (pi: PtrToChar; j: Name) : Comparison ;
|
|
VAR
|
|
pj: PtrToChar ;
|
|
c1, c2: CHAR ;
|
|
BEGIN
|
|
pj := KeyToCharStar(j) ;
|
|
c1 := pi^ ;
|
|
c2 := pj^ ;
|
|
WHILE (c1#nul) OR (c2#nul) DO
|
|
IF c1<c2
|
|
THEN
|
|
RETURN( less )
|
|
ELSIF c1>c2
|
|
THEN
|
|
RETURN( greater )
|
|
ELSE
|
|
INC(pi) ;
|
|
INC(pj) ;
|
|
c1 := pi^ ;
|
|
c2 := pj^
|
|
END
|
|
END ;
|
|
RETURN( equal )
|
|
END Compare ;
|
|
|
|
|
|
(*
|
|
FindNodeAndParentInTree - search BinaryTree for a name.
|
|
If this name is found in the BinaryTree then
|
|
child is set to this name and father is set to the node above.
|
|
A comparison is returned to assist adding entries into this tree.
|
|
*)
|
|
|
|
PROCEDURE FindNodeAndParentInTree (n: PtrToChar; VAR child, father: NameNode) : Comparison ;
|
|
VAR
|
|
result: Comparison ;
|
|
BEGIN
|
|
(* firstly set up the initial values of child and father, using sentinal node *)
|
|
father := BinaryTree ;
|
|
child := BinaryTree^.Left ;
|
|
IF child=NIL
|
|
THEN
|
|
RETURN( less )
|
|
ELSE
|
|
REPEAT
|
|
result := Compare(n, child^.Key) ;
|
|
IF result=less
|
|
THEN
|
|
father := child ;
|
|
child := child^.Left
|
|
ELSIF result=greater
|
|
THEN
|
|
father := child ;
|
|
child := child^.Right
|
|
END
|
|
UNTIL (child=NIL) OR (result=equal) ;
|
|
RETURN( result )
|
|
END
|
|
END FindNodeAndParentInTree ;
|
|
|
|
|
|
(*
|
|
IsSameExcludingCase - returns TRUE if key1 and key2 are
|
|
the same. It is case insensitive.
|
|
This function deliberately inlines CAP for speed.
|
|
*)
|
|
|
|
PROCEDURE IsSameExcludingCase (key1, key2: Name) : BOOLEAN ;
|
|
VAR
|
|
pi, pj: PtrToChar ;
|
|
c1, c2: CHAR ;
|
|
BEGIN
|
|
IF key1=key2
|
|
THEN
|
|
RETURN( TRUE )
|
|
ELSE
|
|
pi := KeyToCharStar(key1) ;
|
|
pj := KeyToCharStar(key2) ;
|
|
c1 := pi^ ;
|
|
c2 := pj^ ;
|
|
WHILE (c1#nul) AND (c2#nul) DO
|
|
IF (c1=c2) OR
|
|
(((c1>='A') AND (c1<='Z')) AND (c2=CHR(ORD(c1)-ORD('A')+ORD('a')))) OR
|
|
(((c2>='A') AND (c2<='Z')) AND (c1=CHR(ORD(c2)-ORD('A')+ORD('a'))))
|
|
THEN
|
|
INC(pi) ;
|
|
INC(pj) ;
|
|
c1 := pi^ ;
|
|
c2 := pj^
|
|
ELSE
|
|
(* difference found *)
|
|
RETURN( FALSE )
|
|
END
|
|
END ;
|
|
RETURN( c1=c2 )
|
|
END
|
|
END IsSameExcludingCase ;
|
|
|
|
|
|
(*
|
|
KeyToCharStar - returns the C char * string equivalent for, key.
|
|
*)
|
|
|
|
PROCEDURE KeyToCharStar (key: Name) : ADDRESS ;
|
|
BEGIN
|
|
IF (key=NulName) OR (NOT InBounds(KeyIndex, key))
|
|
THEN
|
|
RETURN( NIL )
|
|
ELSE
|
|
RETURN( GetIndice(KeyIndex, key) )
|
|
END
|
|
END KeyToCharStar ;
|
|
|
|
|
|
PROCEDURE WriteKey (key: Name) ;
|
|
VAR
|
|
s: PtrToChar ;
|
|
BEGIN
|
|
s := KeyToCharStar(key) ;
|
|
WHILE (s#NIL) AND (s^#nul) DO
|
|
Write(s^) ;
|
|
INC(s)
|
|
END
|
|
END WriteKey ;
|
|
|
|
|
|
(*
|
|
CharKey - returns the key[i] character.
|
|
*)
|
|
|
|
PROCEDURE CharKey (key: Name; i: CARDINAL) : CHAR ;
|
|
VAR
|
|
p: PtrToChar ;
|
|
BEGIN
|
|
IF i >= LengthKey (key)
|
|
THEN
|
|
HALT
|
|
END ;
|
|
p := KeyToCharStar (key) ;
|
|
INC (p, i) ;
|
|
RETURN p^
|
|
END CharKey ;
|
|
|
|
|
|
BEGIN
|
|
(*
|
|
NameKeyWordMemDiag
|
|
:= InitMemDiagnostic
|
|
('NameKey:Words',
|
|
'{0N} total words {1d} consuming {2M} ({2P})') ;
|
|
NameKeyTreeMemDiag
|
|
:= InitMemDiagnostic
|
|
('NameKey:Tree',
|
|
'{0N} total tree nodes {1d} consuming {2M} ({2P})') ;
|
|
*)
|
|
LastIndice := 0 ;
|
|
KeyIndex := InitIndex(1) ;
|
|
NEW(BinaryTree) ;
|
|
BinaryTree^.Left := NIL ;
|
|
END NameKey.
|