<> <> <> <> <> <> DIRECTORY SpellingWordMap, Rope USING [ROPE, Size], RopeReader USING [Create, SetPosition, Get, Ref, Backwards]; SpellingWordMapImpl: CEDAR MONITOR IMPORTS Rope, RopeReader EXPORTS SpellingWordMap = BEGIN ROPE: TYPE = Rope.ROPE; reader: RopeReader.Ref ¬ RopeReader.Create[]; -- To make word parsing efficient. MapWordsInRope: PUBLIC ENTRY PROC [words: ROPE, alphabetic: SpellingWordMap.CharSet, buffer: REF TEXT, f: PROC [REF TEXT, REF ANY, INT] RETURNS [BOOL], data: REF ANY, offset: INT] RETURNS [premature: BOOLEAN ¬ FALSE, wordStart, wordEnd: INT ¬ 0, newBuffer: REF TEXT] = { <> HandleExpansion: PROC [] = INLINE { IF wp >= buffer.maxLength THEN { newBuffer ¬ NEW[TEXT[2*buffer.maxLength + 1]]; newBuffer.length ¬ newBuffer.maxLength; FOR j: NAT IN [0..wp) DO newBuffer[j] ¬ buffer[j]; ENDLOOP; buffer ¬ newBuffer; }; }; ParseState: TYPE = {InWord, InJunk, Embeddable}; state: ParseState ¬ InJunk; wp: NAT ¬ 0; size: INT ¬ words.Size[]; c, e: CHAR ¬ 0C; newBuffer ¬ buffer; buffer.length ¬ buffer.maxLength; RopeReader.SetPosition[reader, words, 0]; FOR pos: INT IN [0..size) DO c ¬ reader.Get[]; IF alphabetic[c] THEN { IF state = InJunk THEN { wordStart ¬ pos; wp ¬ 0; } ELSE IF state = Embeddable THEN { HandleExpansion[]; buffer[wp] ¬ e; wp ¬ wp + 1; }; state ¬ InWord; HandleExpansion[]; buffer[wp] ¬ c; wp ¬ wp + 1; } ELSE { IF state = InWord THEN { IF c = '' THEN { state ¬ Embeddable; e ¬ c; } ELSE { buffer.length ¬ wp; wordEnd ¬ pos; premature ¬ f[buffer, data, wordStart+offset]; IF premature THEN RETURN; state ¬ InJunk; }; } ELSE IF state = Embeddable THEN { buffer.length ¬ wp; wordEnd ¬ pos-1; premature ¬ f[buffer, data, wordStart+offset]; IF premature THEN RETURN; state ¬ InJunk; }; }; ENDLOOP; IF state = InWord THEN { buffer.length ¬ wp; wordEnd ¬ size; premature ¬ f[buffer, data, wordStart+offset]; } ELSE IF state = Embeddable THEN { buffer.length ¬ wp; wordEnd ¬ size-1; premature ¬ f[buffer, data, wordStart+offset]; }; }; MapWordsInRopeBackward: PUBLIC ENTRY PROC [words: ROPE, alphabetic: SpellingWordMap.CharSet, buffer: REF TEXT, f: PROC [REF TEXT, REF ANY, INT] RETURNS [BOOL], data: REF ANY, offset: INT] RETURNS [premature: BOOLEAN ¬ FALSE, wordStart, wordEnd: INT ¬ 0, newBuffer: REF TEXT] = { <> HandleExpansion: PROC [] = INLINE { IF wp >= buffer.maxLength THEN { newBuffer ¬ NEW[TEXT[2*buffer.maxLength + 1]]; newBuffer.length ¬ newBuffer.maxLength; FOR j: NAT IN [0..wp) DO newBuffer[j] ¬ buffer[j]; ENDLOOP; buffer ¬ newBuffer; }; }; ReverseWord: PROC [] = INLINE { j: NAT ¬ buffer.length; c: CHAR; FOR i: NAT IN [0..j/2) DO j ¬ j - 1; c ¬ buffer[i]; buffer[i] ¬ buffer[j]; buffer[j] ¬ c; ENDLOOP; }; ParseState: TYPE = {InWord, InJunk, Embeddable}; state: ParseState ¬ InJunk; wp: NAT ¬ 0; size: INT ¬ words.Size[]; c, e: CHAR ¬ 0C; newBuffer ¬ buffer; buffer.length ¬ buffer.maxLength; RopeReader.SetPosition[reader, words, words.Size[]]; FOR pos: INT DECREASING IN [0..size) DO c ¬ reader.Backwards[]; IF alphabetic[c] THEN { IF state = InJunk THEN { wordEnd ¬ pos+1; wp ¬ 0; } ELSE IF state = Embeddable THEN { HandleExpansion[]; buffer[wp] ¬ e; wp ¬ wp + 1; }; state ¬ InWord; HandleExpansion[]; buffer[wp] ¬ c; wp ¬ wp + 1; } ELSE { IF state = InWord THEN { IF c = '' THEN { state ¬ Embeddable; e ¬ c; } ELSE { buffer.length ¬ wp; wordStart ¬ pos+1; ReverseWord[]; premature ¬ f[buffer, data, wordStart+offset]; IF premature THEN RETURN; state ¬ InJunk; }; } ELSE IF state = Embeddable THEN { buffer.length ¬ wp; wordStart ¬ pos+2; ReverseWord[]; premature ¬ f[buffer, data, wordStart+offset]; IF premature THEN RETURN; state ¬ InJunk; }; }; ENDLOOP; IF state = InWord THEN { buffer.length ¬ wp; wordStart ¬ 0; ReverseWord[]; premature ¬ f[buffer, data, wordStart+offset]; } ELSE IF state = Embeddable THEN { buffer.length ¬ wp; wordStart ¬ 1; ReverseWord[]; premature ¬ f[buffer, data, wordStart+offset]; }; }; END. CHANGE LOG Created by Nix on May 1, 1987 10:41:54 am PDT, END <> <> <> <<>>