home *** CD-ROM | disk | FTP | other *** search
-
- {PARSE.PA2}
-
- {Parse Sentence}
-
- PROCEDURE Parse(VAR sentence : s;
- VAR verb, noun, prep, object_word : words;
- VAR syntax_error : Boolean);
-
- CONST
- max_words = 12; {max words allowed in sentence}
- TYPE
- wordlists = ARRAY[1..max_words] OF words;
- VAR
- i : Integer; {index to s}
- k : Integer; {a spare index variable}
- l : Integer; {length of s}
- num_words : Integer;
- w : wordlists;
- OK_Verb, OK_Noun : Boolean;
- adj, NextPrep, NextObject : words;
- Ch : Char;
- LABEL Exit;
-
- { Close_Up }
- {Remove the specified word from the}
- {array of words. }
- PROCEDURE close_up(VAR w : wordlists;
- VAR num_words : Integer;
- N : Integer);
- VAR i : Integer;
- BEGIN
- FOR i := N TO num_words-1 DO
- w[i] := w[i+1];
- w[num_words] := '';
- num_words := num_words-1;
- END;
-
- { Is_Extra }
- {Returns 'true' if the word is}
- {considered 'unimportant.' }
- FUNCTION Is_Extra(w : words) : Boolean;
- BEGIN
- IF (w = 'THE') OR (w = 'PLEASE') OR (w = 'NOW')
- OR (w = 'A') OR (w = 'AN') OR (w = 'ITS') OR (w = 'MY')
- THEN Is_Extra := True
- ELSE Is_Extra := False;
- END; {Is_Extra}
-
- { Verb_Needs_Prep }
- {Checks word against hard-coded list of verbs that need preps.}
- FUNCTION Verb_Needs_Prep(w : words) : Boolean;
- BEGIN
- Verb_Needs_Prep := ((w = 'FIRE')
- OR (w = 'PUT')
- OR (w = 'TELL')
- OR (w = 'ASK')
- OR (w = 'LOCK')
- OR (w = 'UNLOCK'));
- END; {Verb_Needs_Prep}
-
- { Is_Valid_Noun }
- {Returns TRUE if noun or creature and FALSE otherwise}
- FUNCTION Is_Valid_Noun(w : words) : Boolean;
- VAR
- match : Boolean;
- BEGIN
- match := Is_Noun(w);
- IF NOT match THEN match := Is_Creature(w);
- Is_Valid_Noun := match;
- END; {Is_Valid_Noun}
-
- { Handle Duplicates in Room}
- PROCEDURE HandleDuplicates(NorO : Integer);
- {If NorO is 0 then gets NounNumber of duplicate otherwise get ObjectNumber}
- VAR Answer : s;
- PickedOne : Boolean;
- i : Integer;
- Dword : words;
- BEGIN
- PickedOne := False;
- Duplicate := False;
- IF NorO = 0
- THEN Dword := noun
- ELSE Dword := object_word;
- IF NumberInRoom <= MaxDupsInRoom
- THEN BEGIN
- Write(IO, 'Which "', Dword, '", the ', DuplicatesInRoom[1].adj, ' ', DuplicatesInRoom[1].name);
- FOR i := 2 TO NumberInRoom DO
- Write(IO, ' or the ', DuplicatesInRoom[i].adj, ' ', DuplicatesInRoom[i].name);
- WriteLn(IO, '?');
- Answer := GetInputString;
- WriteLn(IO, ' ');
- FOR i := 1 TO NumberInRoom DO
- IF POS(DuplicatesInRoom[i].adj, Answer) <> 0 THEN
- BEGIN {found it}
- PickedOne := True;
- IF NorO = 0
- THEN NounNumber := DuplicatesInRoom[i].num
- ELSE ObjectNumber := DuplicatesInRoom[i].num;
- END;
- END; {NumberInRoom <= Max}
- IF NOT PickedOne
- THEN BEGIN
- WriteLn(IO, 'Please repeat your command again and this time try to');
- WriteLn(IO, 'be more specific about which "', noun, '" you mean.');
- syntax_error := True;
- END; {too many to cope with or picking error}
- END; {HandleDuplicates}
-
- { Massage_Noun }
- {Takes care of any adjective-noun pairs}
- {by replacing them with the noun alone.}
- PROCEDURE Massage_Noun(VAR w : wordlists;
- VAR num_words : Integer;
- P : Integer);
- VAR i : Integer; {index to verbs array}
- match : Boolean;
- BEGIN
- adj := '';
- IF w[P+1] <> '' THEN
- BEGIN
- match := False;
- i := First_noun;
- WHILE (i <= MaxNoun) AND
- (NOT match) DO
- BEGIN
- IF N[i]^.Has_Synonyms
- THEN match := ((w[P] = N[i]^.adj) AND (POS(' '+w[P+1]+' ', N[i]^.synonyms) <> 0))
- ELSE match := ((w[P] = N[i]^.adj) AND (N[i]^.name = w[P+1]));
- IF match THEN
- BEGIN
- adj := w[P]; {get adj for this noun -- if input}
- close_up(w, num_words, P);
- END;
- i := i+1;
- END; {exits if match found}
- IF NOT match THEN
- BEGIN
- i := First_creature;
- WHILE (i <= MaxCreature) AND
- (NOT match) DO
- BEGIN
- IF M[i]^.Has_Synonyms
- THEN match := ((w[P] = M[i]^.adj) AND (POS(' '+w[P+1]+' ', M[i]^.synonyms) <> 0))
- ELSE match := ((w[P] = M[i]^.adj) AND (M[i]^.name = w[P+1]));
- IF match THEN
- BEGIN
- adj := w[P]; {get adj for this noun -- if input}
- close_up(w, num_words, P);
- END;
- i := i+1;
- END; {exits if match found}
- END; {IF NOT Match}
- END; {IF w[p+1] <> ''}
- END; {Massage_Noun}
-
- { Massage_Verb }
- {Deals with compound verbs, by }
- {converting them to single word 'verbs.'}
- {Also handles SYNONYMS }
- PROCEDURE Massage_Verb(VAR w : wordlists;
- VAR num_words : Integer);
- VAR i : Integer;
- FirstCut : words;
- BEGIN
- Original_Verb := ' '; {to begin with}
- IF Length(w[1]) = 1 THEN
- BEGIN
- IF (w[1] = 'E') THEN w[1] := 'EAST';
- IF (w[1] = 'S') THEN w[1] := 'SOUTH';
- IF (w[1] = 'N') THEN w[1] := 'NORTH';
- IF (w[1] = 'W') THEN w[1] := 'WEST';
- IF (w[1] = 'U') THEN w[1] := 'UP';
- IF (w[1] = 'D') THEN w[1] := 'DOWN';
- IF (w[1] = 'L') THEN w[1] := 'LOOK';
- IF (w[1] = 'I') THEN w[1] := 'INVENTORY';
- IF (w[1] = 'H') THEN w[1] := 'HELP';
- IF (w[1] = 'Q') THEN w[1] := 'QUIT';
- END;
- IF Length(w[1]) = 2 THEN
- BEGIN
- IF (w[1] = 'EX') THEN w[1] := 'EXAMINE';
- IF (w[1] = 'NE') THEN w[1] := 'NORTHEAST';
- IF (w[1] = 'SE') THEN w[1] := 'SOUTHEAST';
- IF (w[1] = 'NW') THEN w[1] := 'NORTHWEST';
- IF (w[1] = 'SW') THEN w[1] := 'SOUTHWEST';
- END;
- IF (w[1] = 'EXT') THEN w[1] := 'EXTINGUISH';
- IF (w[1] = 'LEAVE') THEN w[1] := 'EXIT';
- IF (w[1] = 'PICK') AND (w[2] = 'UP')
- THEN BEGIN
- Original_Verb := 'PICK UP';
- w[1] := 'GET';
- close_up(w, num_words, 2);
- END
- ELSE IF (w[1] = 'TAKE') AND (w[2] = 'OFF')
- THEN BEGIN
- Original_Verb := 'TAKE OFF';
- w[1] := 'REMOVE';
- close_up(w, num_words, 2);
- END
- ELSE IF ((w[1] = 'TAKE') OR (w[1] = 'GET'))
- THEN BEGIN
- Original_Verb := w[1];
- w[1] := 'GET';
- END
- ELSE IF ((w[1] = 'THROW') OR (w[1] = 'CAST') OR (w[1] = 'DUMP'))
- THEN BEGIN
- Original_Verb := w[1];
- w[1] := 'THROW';
- END
- ELSE IF ((w[1] = 'SCREAM') OR (w[1] = 'YELL') OR (w[1] = 'SHOUT'))
- THEN BEGIN
- Original_Verb := w[1];
- w[1] := 'YELL';
- END
- ELSE IF ((w[1] = 'EXAMINE') OR (w[1] = 'INSPECT') OR (w[1] = 'CHECK'))
- THEN BEGIN
- Original_Verb := w[1];
- w[1] := 'EXAMINE';
- END
- ELSE IF ((w[1] = 'KILL') OR (w[1] = 'ATTACK') OR (w[1] = 'HIT') OR (w[1] = 'FIGHT'))
- THEN BEGIN
- Original_Verb := w[1];
- w[1] := 'ATTACK';
- END
- ELSE IF ((w[1] = 'PUSH') OR (w[1] = 'TOUCH'))
- THEN BEGIN
- Original_Verb := w[1];
- w[1] := 'PUSH';
- END
- ELSE IF ((w[1] = 'SHOOT') OR (w[1] = 'FIRE'))
- THEN BEGIN
- Original_Verb := w[1];
- w[1] := 'FIRE';
- END
- ELSE IF ((w[1] = 'CLOSE') OR (w[1] = 'SHUT'))
- THEN BEGIN
- Original_Verb := w[1];
- w[1] := 'CLOSE';
- END
- ELSE IF ((w[1] = 'LOOK') AND ((w[2] = 'AT') OR (w[2] = 'IN')))
- THEN BEGIN
- Original_Verb := 'LOOK AT';
- w[1] := 'EXAMINE';
- close_up(w, num_words, 2);
- END
- ELSE IF ((w[1] = 'GO') AND ((w[2] = 'IN') OR (w[2] = 'INTO')))
- THEN BEGIN
- Original_Verb := 'GO INTO';
- w[1] := 'ENTER';
- close_up(w, num_words, 2);
- END
- ELSE IF (w[1] = 'TALK') AND (w[2] = 'TO')
- THEN BEGIN
- Original_Verb := 'TALK TO';
- w[1] := 'TELL';
- close_up(w, num_words, 2);
- END
- ELSE IF (w[1] = 'TALK') AND (w[2] = 'WITH')
- THEN BEGIN
- Original_Verb := 'TALK WITH';
- w[1] := 'TELL';
- close_up(w, num_words, 2);
- END
- ELSE IF (w[1] = 'PUT') AND (w[2] = 'DOWN')
- THEN BEGIN
- Original_Verb := 'PUT DOWN';
- w[1] := 'DROP';
- close_up(w, num_words, 2);
- END
- ELSE IF (w[1] = 'PUT') AND (w[2] = 'ON')
- THEN BEGIN
- Original_Verb := 'PUT ON';
- w[1] := 'WEAR';
- close_up(w, num_words, 2);
- END
- ELSE IF (w[1] = 'PUT') AND (w[2] = 'OUT')
- THEN BEGIN
- Original_Verb := 'PUT OUT';
- w[1] := 'EXTINGUISH';
- close_up(w, num_words, 2);
- END
- ELSE IF ((w[1] = 'PUT') OR (w[1] = 'PLACE'))
- THEN BEGIN
- Original_Verb := w[1];
- w[1] := 'PUT';
- END;
- FirstCut := w[1];
- {Now do global synonyms -- they take precedent over normal verbs}
- FOR i := 1 TO Num_Verbs DO
- IF POS(' '+FirstCut+' ', SYN[i]) <> 0
- THEN BEGIN
- Original_Verb := FirstCut;
- w[1] := V[i]; {substitute "Global" synonyms}
- END;
- {Now do room synonyms -- they take precedent over global synonyms}
- IF Skip_A_Line THEN IF POS(' '+FirstCut+' ', Room[Current_room]^.Replacing_Words) <> 0
- THEN BEGIN
- Original_Verb := FirstCut;
- w[1] := Room[Current_room]^.Replaced_Word;
- {Swap for ROOM SYNONYMS}
- END;
- IF w[1] = 'CHANGE_LOCATION' THEN w[1] := 'CHANGE_LOCATIONS';
- IF Is_Verb(w[1]) THEN
- BEGIN
- OK_Verb := True;
- IF (Original_Verb = ' ') THEN Original_Verb := w[1];
- END
- ELSE Original_Verb := LastVerb;
- Normalize(Original_Verb);
- END; {Massage_Verb}
-
- PROCEDURE Make_Into_Words(VAR sentence : s; VAR w : wordlists; VAR num_words : Integer);
- VAR k : Integer;
- BEGIN
- FOR k := 1 TO max_words DO
- w[k] := ''; {initialize word_list to avoid run-time crash}
- l := Length(sentence);
- i := 1;
- num_words := 0;
- Skip_spaces(sentence, i, l);
- WHILE ((i <= l) AND (num_words < max_words)) DO
- BEGIN
- num_words := num_words+1; {we've found another word}
- REPEAT
- w[num_words] := w[num_words]+sentence[i];
- i := i+1;
- Ch := sentence[i];
- UNTIL ((Ch > 'z') OR ((Ch < '0') AND (Ch <> '-') AND (Ch <> Chr(39))) OR (i > l));
- Skip_spaces(sentence, i, l);
- END; {while more characters to process}
- IF ((num_words = max_words) AND (i <= l))
- THEN
- BEGIN
- WriteLn(IO, 'Too many words in sentence');
- syntax_error := True;
- END;
- { The words in the sentence are now }
- { broken out into separate words in the }
- { array of words "w", where they can be }
- { examined individually. }
- {Now let's delete any obviously extraneous words}
- k := 1;
- REPEAT
- IF Is_Extra(w[k]) {if word adds no meaning to the}
- THEN close_up(w, num_words, k) {sentence, then eliminate it }
- ELSE k := k+1;
- UNTIL k > num_words; {loop exit is guaranteed because every time}
- {either k increases or num_words decreases}
- END; {Make_Into_Words}
-
- PROCEDURE Scan_For_Prep_Object(LastPart : s; VAR NextPrep, NextObject : words;
- VAR syntax_error : Boolean);
- VAR wd : wordlists; num, P : Integer; Finished : Boolean;
- BEGIN
- Make_Into_Words(LastPart, wd, num);
- P := 0;
- Finished := False;
- NextPrep := '';
- NextObject := '';
- syntax_error := False;
- REPEAT {scan for next prep in last part of sentence}
- P := P+1;
- IF Is_Prep(wd[P]) THEN
- BEGIN {found it}
- NextPrep := wd[P];
- Finished := True;
- END;
- UNTIL Finished OR (P = num);
- Massage_Noun(wd, num, P+1); {check next word(s) for noun}
- IF Is_Valid_Noun(wd[P+1]) THEN NextObject := wd[P+1];
- IF (NextPrep = '') OR (NextObject = '') THEN syntax_error := True;
- END; {Scan_For_Prep_Object}
-
- VAR kkk : Integer;
-
- BEGIN {Parse(sentence)}
- OK_Verb := False;
- OK_Noun := False;
- Duplicate := False;
- verb := '';
- noun := '';
- prep := '';
- object_word := '';
- noun_adj := '';
- object_adj := '';
- NounNumber := 0;
- ObjectNumber := 0;
- syntax_error := False;
- IF Skip_A_Line THEN WriteLn(IO, ' ');
- IF sentence = '' THEN
- BEGIN
- WriteLn(IO, 'Eh?');
- syntax_error := True;
- END
- ELSE
- BEGIN
- syntax_error := False;
- Make_Into_Words(sentence, w, num_words);
- Massage_Verb(w, num_words); {Now that unnecessary words are removed}
- {let's massage the first word in case it's a compound verb }
- IF NOT OK_Verb
- THEN IF (DoingCompoundCommands OR PreviousCompoundCommands) THEN
- BEGIN
- Massage_Noun(w, num_words, 1); {Is it another noun?}
- noun_adj := adj;
- {now, check to see if it's a recognized noun}
- OK_Noun := Is_Valid_Noun(w[1]);
- IF OK_Noun THEN
- IF NOT Verb_Needs_Prep(LastVerb) THEN
- BEGIN {simple verbs, like GET, DROP, etc}
- FOR i := num_words DOWNTO 1 DO w[i+1] := w[i];
- w[1] := LastVerb; {move last verb to w[1]}
- num_words := num_words+1;
- END
- ELSE
- BEGIN {Complex Verbs like SHOOT MONSTER WITH LASER}
- Scan_For_Prep_Object(LastPart, NextPrep, NextObject, syntax_error);
- IF syntax_error THEN
- WriteLn(IO, 'You need a preposition and object whenever you try to "', LastVerb, ' ', w[1]
- , '"!')
- ELSE BEGIN
- w[2] := w[1];
- w[1] := LastVerb;
- w[3] := NextPrep;
- w[4] := NextObject;
- END
- END
- ELSE {NOT OK_Noun}
- BEGIN
- WriteLn(IO, 'I don''t understand ', w[1], ' as either a verb or a noun.');
- syntax_error := True;
- END;
- END {DoingCompoundCommands}
- ELSE BEGIN
- WriteLn(IO, 'I don''t understand ', w[1], ' as a verb.');
- syntax_error := True;
- END
- { If the second word is '' or shouldn't exist, let's exit.}
- ELSE IF NOT((num_words = 1) OR (Is_Direction(w[1])))
- THEN {check the word/phrase following the verb}
- BEGIN
- {first, massage nouns in case they're compound nouns}
- Massage_Noun(w, num_words, 2);
- noun_adj := adj;
- {now, check to see if it's a recognized noun}
- OK_Noun := Is_Valid_Noun(w[2]);
- IF NOT OK_Noun
- THEN IF Is_Prep(w[2])
- THEN
- BEGIN
- Massage_Noun(w, num_words, 3);
- IF NOT Is_Valid_Noun(w[3])
- THEN
- BEGIN
- WriteLn(IO, 'I don''t understand ', w[3],
- ' as the object of a preposition.');
- syntax_error := True;
- END
- ELSE
- BEGIN
- w[4] := w[3];
- w[3] := w[2];
- w[2] := w[4]; {object of prep = noun}
- noun_adj := adj;
- object_adj := adj;
- END
- END
- ELSE
- IF ((w[1] = 'EXAMINE') AND Skip_A_Line) THEN
- BEGIN
- WriteLn(IO, 'You see nothing unusual.');
- syntax_error := True;
- END
- ELSE BEGIN
- WriteLn(IO, 'I don''t understand ', w[2], ' as a noun.');
- syntax_error := True;
- END
- ELSE IF num_words > 2 THEN {let's continue parsing}
- IF NOT Is_Prep(w[3])
- THEN
- BEGIN
- WriteLn(IO, 'I don''t understand ', w[3], ' as a preposition');
- syntax_error := True;
- END
- ELSE {make sure the last word is a noun, too}
- BEGIN
- Massage_Noun(w, num_words, 4);
- object_adj := adj;
- IF NOT Is_Valid_Noun(w[4])
- THEN IF w[4] <> '' THEN {allow missing obj. of prep}
- BEGIN
- WriteLn(IO, 'I don''t understand ', w[4],
- ' as the object of a preposition.');
- syntax_error := True;
- END;
- END;
- END;
- verb := w[1];
- noun := w[2];
- prep := w[3];
- object_word := w[4];
- IF (DoingCompoundCommands OR PreviousCompoundCommands) THEN
- IF ((prep = '') AND (Verb_Needs_Prep(verb))) THEN
- BEGIN {Complex Verbs like SHOOT MONSTER WITH LASER}
- Scan_For_Prep_Object(LastPart, NextPrep, NextObject, syntax_error);
- IF syntax_error THEN
- WriteLn(IO, 'You need a preposition and object whenever you try to "', verb, ' ', noun, '"!')
- ELSE BEGIN
- prep := NextPrep;
- object_word := NextObject;
- END
- END;
- IF syntax_error THEN GOTO Exit;
- IF (object_word = 'IT') OR (object_word = 'THEM') {Allows 'IT' or 'THEM'}
- OR (object_word = 'HIM') OR (object_word = 'HER') {Allows 'HIM' or 'HER'}
- THEN BEGIN
- object_word := last_noun_used;
- object_adj := last_adj_used;
- END;
- IF (noun = 'IT') OR (noun = 'THEM')
- OR (noun = 'HIM') OR (noun = 'HER') {Allows 'HIM' or 'HER'}
- THEN BEGIN
- noun := last_noun_used;
- noun_adj := last_adj_used;
- END
- ELSE BEGIN
- last_noun_used := noun;
- last_adj_used := noun_adj;
- END;
- {check for duplicate names and pick one that is visible}
- Adjective := noun_adj;
- IF noun <> '' THEN NounNumber := Noun_Number(noun);
- IF Duplicate AND Skip_A_Line {I.E., two or more are visible}
- THEN HandleDuplicates(0); {0 for NounNumber selection}
- Adjective := object_adj;
- IF ((object_word <> '') AND (NOT syntax_error)) THEN ObjectNumber := Noun_Number(object_word);
- IF Duplicate AND Skip_A_Line {I.E., two or more are visible}
- THEN HandleDuplicates(1); {1 for Object selection}
- END; {if sentence=''...else}
- IF (NOT syntax_error) AND (noun <> '') THEN
- BEGIN {make sure we use the "official" form of noun}
- i := NounNumber;
- IF (i >= First_noun) AND (i <= MaxNoun)
- THEN noun := N[i]^.name;
- IF (i >= First_creature) AND (i <= MaxCreature)
- THEN noun := M[i]^.name;
- END;
- IF (NOT syntax_error) AND (object_word <> '') THEN
- BEGIN {make sure we use the "official" form of object}
- i := ObjectNumber;
- IF (i >= First_noun) AND (i <= MaxNoun)
- THEN object_word := N[i]^.name;
- IF (i >= First_creature) AND (i <= MaxCreature)
- THEN object_word := M[i]^.name;
- END;
- Exit:
- END; {Parse(sentence)}
-