-- File CIFExtDict.mesa
-- Written by Dan Fitzpatrick and Martin Newell, June 1980
-- Last updated: December 1, 1980 1:58 PM

DIRECTORY


CIFExtDictDefs: FROM "CIFExtDictDefs",
CIFExtIODefs: FROM "CIFExtIODefs" USING[WriteLong],
InlineDefs: FROM "InlineDefs" USING[BITSHIFT, BITOR,
BITXOR, LongDivMod],
IODefs: FROM "IODefs" USING[GetOutputStream, WriteString, WriteLine],
SystemDefs: FROM "SystemDefs" USING[AllocateHeapNode, FreeHeapNode, AllocateHeapString, FreeHeapString],
StringDefs: FROM "StringDefs" USING[AppendString, EquivalentString];

CIFExtDict: PROGRAM
IMPORTS CIFExtIODefs, InlineDefs, IODefs, SystemDefs, StringDefs
EXPORTS CIFExtDictDefs =

BEGIN OPEN CIFExtIODefs, InlineDefs, IODefs, SystemDefs, StringDefs;

InitDictionary: PUBLIC PROCEDURE =
BEGIN
i: CARDINAL;
ptr: Entry;
FOR i ← 0, i+1 WHILE i < TableSize DO
FOR ptr ← NumberTable[i], NumberTable[i] UNTIL ptr = NIL DO
NumberTable[i] ← ptr.nextNumber;
FreeHeapString[ptr.name];
FreeEntry[ptr];
ENDLOOP;
ENDLOOP;
NameTable ← NumberTable ← ALL[NIL];
END;

Remember: PUBLIC PROCEDURE [name: STRING, number: LONG UNSPECIFIED] =
BEGIN
ptr: Entry ← AllocateEntry[];
i: CARDINAL ← HashName[name];
ptr.name ← AllocateHeapString[name.length];
AppendString[ptr.name,name];
ptr.number ← number;
ptr.nextName ← NameTable[i];
NameTable[i] ← ptr;
i ← HashNumber[number];
ptr.nextNumber ← NumberTable[i];
NumberTable[i] ← ptr;
END;

KnownName: PUBLIC PROCEDURE [name: STRING] RETURNS [BOOLEAN] =
BEGIN
ptr: Entry;
FOR ptr ← NameTable[HashName[name]],ptr.nextName UNTIL ptr = NIL DO
IF EquivalentString[name,ptr.name] THEN RETURN[TRUE];
ENDLOOP;
RETURN[FALSE];
END;

KnownNumber: PUBLIC PROCEDURE [number: LONG UNSPECIFIED] RETURNS [BOOLEAN] =
BEGIN
ptr: Entry;
FOR ptr ← NumberTable[HashNumber[number]],ptr.nextNumber UNTIL ptr = NIL DO
IF number = ptr.number THEN RETURN[TRUE];
ENDLOOP;
RETURN[FALSE];
END;

FindName: PUBLIC PROCEDURE [name: STRING] RETURNS [LONG UNSPECIFIED] =
BEGIN
ptr: Entry;
FOR ptr ← NameTable[HashName[name]],ptr.nextName UNTIL ptr = NIL DO
IF EquivalentString[name,ptr.name] THEN RETURN[ptr.number];
ENDLOOP;
WriteString["ERROR: FindName called with no entry for "];
WriteLine[name];
RETURN[LONG[0]];
END;

FindNumber: PUBLIC PROCEDURE [number: LONG UNSPECIFIED] RETURNS [STRING] =
BEGIN
ptr: Entry;
FOR ptr ← NumberTable[HashNumber[number]],ptr.nextNumber UNTIL ptr = NIL DO
IF number = ptr.number THEN RETURN[ptr.name];
ENDLOOP;
WriteString["ERROR: FindNumber called with no entry for "];
WriteLong[number, GetOutputStream[]];
RETURN["NULL"];
END;

HashName: PROCEDURE [str: STRING] RETURNS [total: CARDINAL] =
BEGIN
i: CARDINAL;
total ← 0;
--total ← ABS[total];
FOR i IN [0..str.length) DO
total ← BITXOR[BITSHIFT[total,1],BITOR[str[i],40B]];
ENDLOOP; --BITOR[str[i],40B] is to equate upper and lower case
total ← total MOD TableSize;
--total ← ABS[total];
END;

HashNumber: PROCEDURE [number: LONG UNSPECIFIED] RETURNS [total: CARDINAL] =
BEGIN
dummy: CARDINAL;
--total ← number MOD TableSize;
[dummy,total] ← LongDivMod[number,256];
--total ← ABS[total];
END;

AllocateEntry: PROCEDURE RETURNS [Entry] =
BEGIN
RETURN[AllocateHeapNode[SIZE[EntryRecord]]];
END;

FreeEntry: PROCEDURE [x: Entry] =
BEGIN
FreeHeapNode[x];
END;

TableSize: CARDINAL = 256;

NameTable: ARRAY [0..(TableSize - 1)] OF Entry ← ALL[NIL];
NumberTable: ARRAY [0..(TableSize - 1)] OF Entry ← ALL[NIL];
Entry: TYPE = POINTER TO EntryRecord;
EntryRecord: TYPE = RECORD [
nextName: Entry,
nextNumber: Entry,
name: STRING,
number: LONG UNSPECIFIED
];

END.