<> <> 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, buffer: REF TEXT, f: PROC [REF TEXT] RETURNS [BOOL]] 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, Apostrophe}; state: ParseState _ InJunk; wp: NAT _ 0; size: INT _ words.Size[]; c: CHAR; newBuffer _ buffer; buffer.length _ buffer.maxLength; RopeReader.SetPosition[reader, words, 0]; FOR pos: INT IN [0..size) DO c _ reader.Get[]; IF c IN ['a..'z] OR c IN ['A..'Z] THEN { IF state = InJunk THEN { wordStart _ pos; wp _ 0; } ELSE IF state = Apostrophe THEN { HandleExpansion[]; buffer[wp] _ '\'; wp _ wp + 1; }; state _ InWord; HandleExpansion[]; buffer[wp] _ c; wp _ wp + 1; } ELSE { IF state = InWord THEN { IF c = '\' THEN { state _ Apostrophe; } ELSE { buffer.length _ wp; wordEnd _ pos; premature _ f[buffer]; IF premature THEN RETURN; state _ InJunk; }; } ELSE IF state = Apostrophe THEN { buffer.length _ wp; wordEnd _ pos-1; premature _ f[buffer]; IF premature THEN RETURN; state _ InJunk; }; }; ENDLOOP; IF state = InWord THEN { buffer.length _ wp; wordEnd _ size; premature _ f[buffer]; } ELSE IF state = Apostrophe THEN { buffer.length _ wp; wordEnd _ size-1; premature _ f[buffer]; }; }; MapWordsInRopeBackward: PUBLIC ENTRY PROC [words: ROPE, buffer: REF TEXT, f: PROC [REF TEXT] RETURNS [BOOL]] 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, Apostrophe}; state: ParseState _ InJunk; wp: NAT _ 0; size: INT _ words.Size[]; c: CHAR; newBuffer _ buffer; buffer.length _ buffer.maxLength; RopeReader.SetPosition[reader, words, words.Size[]]; FOR pos: INT DECREASING IN [0..size) DO c _ reader.Backwards[]; IF c IN ['a..'z] OR c IN ['A..'Z] THEN { IF state = InJunk THEN { wordEnd _ pos+1; wp _ 0; } ELSE IF state = Apostrophe THEN { HandleExpansion[]; buffer[wp] _ '\'; wp _ wp + 1; }; state _ InWord; HandleExpansion[]; buffer[wp] _ c; wp _ wp + 1; } ELSE { IF state = InWord THEN { IF c = '\' THEN { state _ Apostrophe; } ELSE { buffer.length _ wp; wordStart _ pos+1; ReverseWord[]; premature _ f[buffer]; IF premature THEN RETURN; state _ InJunk; }; } ELSE IF state = Apostrophe THEN { buffer.length _ wp; wordStart _ pos+2; ReverseWord[]; premature _ f[buffer]; IF premature THEN RETURN; state _ InJunk; }; }; ENDLOOP; IF state = InWord THEN { buffer.length _ wp; wordStart _ 0; ReverseWord[]; premature _ f[buffer]; } ELSE IF state = Apostrophe THEN { buffer.length _ wp; wordStart _ 1; ReverseWord[]; premature _ f[buffer]; }; }; END. CHANGE LOG Created by Nix on October 7, 1983 2:22 pm