--Lexicon.mesa DIRECTORY SystemDefs: FROM "systemdefs" USING [AllocateHeapNode, AllocateHeapString], IODefs: FROM "iodefs" USING [WriteLine], LexiconDefs: FROM "lexicondefs", StringDefs: FROM "stringdefs" USING [AppendString]; Lexicon: PROGRAM IMPORTS SystemDefs, IODefs, StringDefs EXPORTS LexiconDefs = BEGIN Node: TYPE = RECORD[llink, rlink: NodePtr, string: STRING]; NodePtr: TYPE = POINTER TO Node; Comparative: TYPE = {lessThan, equalTo, greaterThan}; root: NodePtr _ NIL; FindString: PUBLIC PROCEDURE [s: STRING] RETURNS [BOOLEAN] = BEGIN RETURN[SearchForString[root, s]]; END; SearchForString: PROCEDURE [n: NodePtr, s: STRING] RETURNS [found: BOOLEAN] = BEGIN IF n = NIL THEN RETURN[FALSE]; SELECT LexicalCompare[s, n.string] FROM lessThan => found _ SearchForString[n.llink, s]; equalTo => found _ TRUE; greaterThan => found _ SearchForString[n.rlink, s]; ENDCASE; RETURN[found]; END; AddString: PUBLIC PROCEDURE [s: STRING] = BEGIN InsertString[root, s]; END; InsertString: PROCEDURE [n: NodePtr, s: STRING] = BEGIN NewNode: PROCEDURE RETURNS [n: NodePtr] = BEGIN OPEN SystemDefs; n _ AllocateHeapNode[SIZE[Node]]; n^ _ Node[string: AllocateHeapString[s.length], llink: NIL, rlink: NIL]; StringDefs.AppendString[n.string, s]; RETURN; END; IF n = NIL THEN root _ NewNode[] -- then just return ELSE SELECT LexicalCompare[s, n.string] FROM lessThan => IF n.llink # NIL THEN InsertString[n.llink, s] ELSE n.llink _ NewNode[]; equalTo => NULL; -- already there; just return greaterThan => IF n.rlink # NIL THEN InsertString[n.rlink, s] ELSE n.rlink _ NewNode[]; ENDCASE; END; LexicalCompare: PROCEDURE [s1, s2: STRING] RETURNS [c: Comparative] = BEGIN n: CARDINAL = MIN[s1.length, s2.length]; i: CARDINAL; FOR i IN [0..n) DO SELECT LowerCase[s1[i]] FROM RETURN[lessThan]; >LowerCase[s2[i]] => RETURN[greaterThan]; ENDCASE; ENDLOOP; c _ SELECT s1.length FROM lessThan, -- s1 is shorter than s2 >s2.length => greaterThan, -- s1 is longer than s2 ENDCASE => equalTo; -- lengths are the same RETURN[c]; END; lower: PACKED ARRAY CHARACTER['A .. 'Z] OF CHARACTER = ['a,'b,'c,'d,'e,'f,'g,'h,'i,'j,'k,'l,'m,'n,'o,'p,'q,'r,'s,'t,'u,'v,'w,'x,'y,'z]; LowerCase: PROCEDURE [c: CHARACTER] RETURNS [CHARACTER] = BEGIN RETURN[IF c IN ['A..'Z] THEN lower[c] ELSE c]; END; PrintLexicon: PUBLIC PROCEDURE = BEGIN PrintNode[root] END; PrintNode: PROCEDURE[n: NodePtr] = BEGIN IF n = NIL THEN RETURN; PrintNode[n.llink]; IODefs.WriteLine[n.string]; PrintNode[n.rlink]; END; END.