MODULE Latin; (* Title : Latin.MOD LastEdit: 07/20/88 Author : Kim Moser System : JPI's TopSpeed Modula-2 with PMI's Repertoire 1.5 Descrip : Reads standard input and writes Pig Latin or Egg Latin equivalent to standard output. *) (* JPI *) FROM IO IMPORT WrStr, WrLn; (* Other M-2 compilers: FROM InOut IMPORT WriteString, WriteLn *) (* Repertoire *) IMPORT InitJPI; FROM M2Strings IMPORT Length; FROM StrEdit IMPORT Append; FROM StringIO IMPORT inp, outp, WriteStr, ErrorMessage; FROM FileIO IMPORT EndReached, BlockRead; FROM EnvironUtils IMPORT ParsedParam; TYPE CharSet = SET OF CHAR; CONST LetterSet = CharSet { 'A'..'Z', "'" }; VowelSet = CharSet { 'A', 'E', 'I', 'O', 'U', 'Y' }; UpperSet = CharSet { 'A'..'Z' }; VAR ch: CHAR; Language: (PigLatin, EggLatin, Unknown); Word, Word2: ARRAY [0..128] OF CHAR; (* Longest allowed word *) CmdLine: ARRAY [0..3] OF CHAR; PROCEDURE WrStrLn( s: ARRAY OF CHAR ); BEGIN WrStr( s ); WrLn; END WrStrLn; PROCEDURE Lower( c: CHAR ): CHAR; (* If 'c' is uppercase, returns its lowercase equivalent, else returns 'c'. *) BEGIN IF c IN UpperSet THEN RETURN CHR( ORD(c) - ORD('A') + ORD('a') ); ELSE RETURN c; END; END Lower; PROCEDURE ReadCh( f: CARDINAL; VAR ch: CHAR ); BEGIN IF BlockRead( f, ADR(ch), 1 ) = NoError THEN END; (* Ignore result [for now] *) END ReadCh; PROCEDURE ReadWord( VAR w: ARRAY OF CHAR ): BOOLEAN; (* Parses a "word" [any sequence of alpha chars, delimited by leading and/or trailing blanks] from standard input into 'w'. Returns TRUE if length of word is > 0, else returns FALSE. *) VAR i: CARDINAL; (* Index into 'w' *) BEGIN i := 0; (* Find beginning of word: *) WHILE (NOT EndReached(inp)) AND (NOT(CAP(ch) IN LetterSet)) DO WriteStr( outp, ch ); ReadCh( inp, ch ); END; (* Parse until end of word: *) WHILE (NOT (EndReached(inp)) AND (CAP(ch) IN LetterSet)) DO w[i] := ch; INC( i ); ReadCh( inp, ch ); END; w[i] := CHR(0); (* Properly terminate word *) RETURN (i > 0); END ReadWord; PROCEDURE ShowUsage(); BEGIN WrStrLn( 'LATIN v1.0 (c) Copyright 1988 Kim Moser All Rights Reserved' ); WrStrLn( 'Translates standard input to either Pig Latin or Egg Latin,' ); WrStrLn( 'depending on command line switch used.' ); WrLn; WrStrLn( 'Usage: LATIN -p | -e' ); END ShowUsage; PROCEDURE Translate( VAR in, out: ARRAY OF CHAR ); VAR i: CARDINAL; TempWord: ARRAY [0..128] OF CHAR; VowelCount: CARDINAL; (* How many vowels found in word [for Egg Latin] *) BEGIN i := 0; (* Index into 'in' *) out[0] := CHR(0); (* Properly initialize string *) CASE Language OF PigLatin: TempWord[0] := CHR(0); (* Properly initialize string *) LOOP (* Find first vowel ['Y' does NOT count if it's the first letter of the word]: *) WHILE (in[i] <> CHR(0)) AND (NOT(CAP(in[i]) IN VowelSet)) DO Append( TempWord, Lower(in[i]) ); INC(i); END; IF ((CAP(in[i])='Y') AND (i=0)) THEN (* Leading 'Y' does NOT count as a vowel *) Append( TempWord, Lower(in[i]) ); (* Will always be 'y' *) INC(i); ELSE EXIT; END; END; (* LOOP *) (* Put rest of 'word' in 'out': *) WHILE (in[i] <> CHR(0)) DO Append(out, in[i]); INC(i); END; Append( out, TempWord ); Append( out, 'ay' ); | EggLatin: VowelCount := 0; (* No vowels found [yet] *) out[0] := CHR(0); (* Properly initialize string *) REPEAT (* Process all vowels: *) (* Find next vowel: *) WHILE (in[i] <> CHR(0)) AND ( (NOT(CAP(in[i]) IN VowelSet)) OR (* Leading 'Y' does NOT count as a vowel: *) ((CAP(in[i])='Y') AND (i=0)) OR (* Trailing vowel does NOT count as vowel IFF there were previous vowels: *) ((CAP(in[i]) IN VowelSet) AND (in[i+1]=CHR(0)) AND (VowelCount > 0)) OR (* Ignore vowel if previous char was vowel, too: *) ((i>1) AND (CAP(in[i-1]) IN VowelSet)) ) DO Append(out, in[i]); INC(i); END; IF in[i] <> CHR(0) THEN (* Vowel was found [we're not at end of word] *) INC( VowelCount ); Append( out, 'egg' ); Append( out, in[i] ); INC(i); END; UNTIL (in[i] = CHR(0)); ELSE WrStrLn( 'LATIN: Internal error; unknown language to translate to.' ); HALT(); END; END Translate; BEGIN (* MAIN *) IF (NOT ParsedParam( 1, CmdLine )) OR EndReached( inp ) THEN ShowUsage(); ELSE CASE CAP(CmdLine[1]) OF 'P': Language := PigLatin; | 'E': Language := EggLatin; ELSE Language := Unknown; END; IF Language = Unknown THEN ShowUsage(); ELSE ReadCh( inp, ch ); WHILE NOT EndReached( inp ) DO IF ReadWord( Word ) THEN Translate( Word, Word2 ); (* Capitalize first letter, if supposed to be: *) IF CAP(Word[0])=Word[0] THEN Word2[0] := CAP(Word2[0]); END; WriteStr( outp, Word2 ); END; END; END; END; END Latin.