home *** CD-ROM | disk | FTP | other *** search
/ CD PowerPlay 6 / TheCompleteAdventureCollection1995 / CDPP6.ISO / utility / agtsrc / parse.pa4 < prev    next >
Encoding:
Text File  |  1989-12-20  |  20.7 KB  |  562 lines

  1.  
  2.   {PARSE.PA2}
  3.  
  4.   {Parse Sentence}
  5.  
  6.   PROCEDURE Parse(VAR sentence : s;
  7.                   VAR verb, noun, prep, object_word : words;
  8.                   VAR syntax_error : Boolean);
  9.  
  10.   CONST
  11.     max_words = 12;               {max words allowed in sentence}
  12.   TYPE
  13.     wordlists = ARRAY[1..max_words] OF words;
  14.   VAR
  15.     i : Integer;                  {index to s}
  16.     k : Integer;                  {a spare index variable}
  17.     l : Integer;                  {length of s}
  18.     num_words : Integer;
  19.     w : wordlists;
  20.     OK_Verb, OK_Noun : Boolean;
  21.     adj, NextPrep, NextObject : words;
  22.     Ch : Char;
  23.   LABEL Exit;
  24.  
  25.     { Close_Up }
  26.     {Remove the specified word from the}
  27.     {array of words. }
  28.     PROCEDURE close_up(VAR w : wordlists;
  29.                        VAR num_words : Integer;
  30.                        N : Integer);
  31.     VAR i : Integer;
  32.     BEGIN
  33.       FOR i := N TO num_words-1 DO
  34.         w[i] := w[i+1];
  35.       w[num_words] := '';
  36.       num_words := num_words-1;
  37.     END;
  38.  
  39.     { Is_Extra }
  40.     {Returns 'true' if the word is}
  41.     {considered 'unimportant.' }
  42.     FUNCTION Is_Extra(w : words) : Boolean;
  43.     BEGIN
  44.       IF (w = 'THE') OR (w = 'PLEASE') OR (w = 'NOW')
  45.       OR (w = 'A') OR (w = 'AN') OR (w = 'ITS') OR (w = 'MY')
  46.       THEN Is_Extra := True
  47.       ELSE Is_Extra := False;
  48.     END;                          {Is_Extra}
  49.  
  50.     { Verb_Needs_Prep }
  51.     {Checks word against hard-coded list of verbs that need preps.}
  52.     FUNCTION Verb_Needs_Prep(w : words) : Boolean;
  53.     BEGIN
  54.       Verb_Needs_Prep := ((w = 'FIRE')
  55.                           OR (w = 'PUT')
  56.                           OR (w = 'TELL')
  57.                           OR (w = 'ASK')
  58.                           OR (w = 'LOCK')
  59.                           OR (w = 'UNLOCK'));
  60.     END;                          {Verb_Needs_Prep}
  61.  
  62.     { Is_Valid_Noun }
  63.     {Returns TRUE if noun or creature and FALSE otherwise}
  64.     FUNCTION Is_Valid_Noun(w : words) : Boolean;
  65.     VAR
  66.       match : Boolean;
  67.     BEGIN
  68.       match := Is_Noun(w);
  69.       IF NOT match THEN match := Is_Creature(w);
  70.       Is_Valid_Noun := match;
  71.     END;                          {Is_Valid_Noun}
  72.  
  73.     { Handle Duplicates in Room}
  74.     PROCEDURE HandleDuplicates(NorO : Integer);
  75.       {If NorO is 0 then gets NounNumber of duplicate otherwise get ObjectNumber}
  76.     VAR Answer : s;
  77.       PickedOne : Boolean;
  78.       i : Integer;
  79.       Dword : words;
  80.     BEGIN
  81.       PickedOne := False;
  82.       Duplicate := False;
  83.       IF NorO = 0
  84.       THEN Dword := noun
  85.       ELSE Dword := object_word;
  86.       IF NumberInRoom <= MaxDupsInRoom
  87.       THEN BEGIN
  88.         Write(IO, 'Which "', Dword, '", the ', DuplicatesInRoom[1].adj, ' ', DuplicatesInRoom[1].name);
  89.         FOR i := 2 TO NumberInRoom DO
  90.           Write(IO, ' or the ', DuplicatesInRoom[i].adj, ' ', DuplicatesInRoom[i].name);
  91.         WriteLn(IO, '?');
  92.         Answer := GetInputString;
  93.         WriteLn(IO, ' ');
  94.         FOR i := 1 TO NumberInRoom DO
  95.           IF POS(DuplicatesInRoom[i].adj, Answer) <> 0 THEN
  96.             BEGIN                 {found it}
  97.               PickedOne := True;
  98.               IF NorO = 0
  99.               THEN NounNumber := DuplicatesInRoom[i].num
  100.               ELSE ObjectNumber := DuplicatesInRoom[i].num;
  101.             END;
  102.       END;                        {NumberInRoom <= Max}
  103.       IF NOT PickedOne
  104.       THEN BEGIN
  105.         WriteLn(IO, 'Please repeat your command again and this time try to');
  106.         WriteLn(IO, 'be more specific about which "', noun, '" you mean.');
  107.         syntax_error := True;
  108.       END;                        {too many to cope with or picking error}
  109.     END;                          {HandleDuplicates}
  110.  
  111.     { Massage_Noun }
  112.     {Takes care of any adjective-noun pairs}
  113.     {by replacing them with the noun alone.}
  114.     PROCEDURE Massage_Noun(VAR w : wordlists;
  115.                            VAR num_words : Integer;
  116.                            P : Integer);
  117.     VAR i : Integer;              {index to verbs array}
  118.       match : Boolean;
  119.     BEGIN
  120.       adj := '';
  121.       IF w[P+1] <> '' THEN
  122.         BEGIN
  123.           match := False;
  124.           i := First_noun;
  125.           WHILE (i <= MaxNoun) AND
  126.           (NOT match) DO
  127.             BEGIN
  128.               IF N[i]^.Has_Synonyms
  129.               THEN match := ((w[P] = N[i]^.adj) AND (POS(' '+w[P+1]+' ', N[i]^.synonyms) <> 0))
  130.               ELSE match := ((w[P] = N[i]^.adj) AND (N[i]^.name = w[P+1]));
  131.               IF match THEN
  132.                 BEGIN
  133.                   adj := w[P];    {get adj for this noun -- if input}
  134.                   close_up(w, num_words, P);
  135.                 END;
  136.               i := i+1;
  137.             END;                  {exits if match found}
  138.           IF NOT match THEN
  139.             BEGIN
  140.               i := First_creature;
  141.               WHILE (i <= MaxCreature) AND
  142.               (NOT match) DO
  143.                 BEGIN
  144.                   IF M[i]^.Has_Synonyms
  145.                   THEN match := ((w[P] = M[i]^.adj) AND (POS(' '+w[P+1]+' ', M[i]^.synonyms) <> 0))
  146.                   ELSE match := ((w[P] = M[i]^.adj) AND (M[i]^.name = w[P+1]));
  147.                   IF match THEN
  148.                     BEGIN
  149.                       adj := w[P]; {get adj for this noun -- if input}
  150.                       close_up(w, num_words, P);
  151.                     END;
  152.                   i := i+1;
  153.                 END;              {exits if match found}
  154.             END;                  {IF NOT Match}
  155.         END;                      {IF w[p+1] <> ''}
  156.     END;                          {Massage_Noun}
  157.  
  158.     { Massage_Verb }
  159.     {Deals with compound verbs, by }
  160.     {converting them to single word 'verbs.'}
  161.     {Also handles SYNONYMS }
  162.     PROCEDURE Massage_Verb(VAR w : wordlists;
  163.                            VAR num_words : Integer);
  164.     VAR i : Integer;
  165.       FirstCut : words;
  166.     BEGIN
  167.       Original_Verb := ' ';       {to begin with}
  168.       IF Length(w[1]) = 1 THEN
  169.         BEGIN
  170.           IF (w[1] = 'E') THEN w[1] := 'EAST';
  171.           IF (w[1] = 'S') THEN w[1] := 'SOUTH';
  172.           IF (w[1] = 'N') THEN w[1] := 'NORTH';
  173.           IF (w[1] = 'W') THEN w[1] := 'WEST';
  174.           IF (w[1] = 'U') THEN w[1] := 'UP';
  175.           IF (w[1] = 'D') THEN w[1] := 'DOWN';
  176.           IF (w[1] = 'L') THEN w[1] := 'LOOK';
  177.           IF (w[1] = 'I') THEN w[1] := 'INVENTORY';
  178.           IF (w[1] = 'H') THEN w[1] := 'HELP';
  179.           IF (w[1] = 'Q') THEN w[1] := 'QUIT';
  180.         END;
  181.       IF Length(w[1]) = 2 THEN
  182.         BEGIN
  183.           IF (w[1] = 'EX') THEN w[1] := 'EXAMINE';
  184.           IF (w[1] = 'NE') THEN w[1] := 'NORTHEAST';
  185.           IF (w[1] = 'SE') THEN w[1] := 'SOUTHEAST';
  186.           IF (w[1] = 'NW') THEN w[1] := 'NORTHWEST';
  187.           IF (w[1] = 'SW') THEN w[1] := 'SOUTHWEST';
  188.         END;
  189.       IF (w[1] = 'EXT') THEN w[1] := 'EXTINGUISH';
  190.       IF (w[1] = 'LEAVE') THEN w[1] := 'EXIT';
  191.       IF (w[1] = 'PICK') AND (w[2] = 'UP')
  192.       THEN BEGIN
  193.         Original_Verb := 'PICK UP';
  194.         w[1] := 'GET';
  195.         close_up(w, num_words, 2);
  196.       END
  197.       ELSE IF (w[1] = 'TAKE') AND (w[2] = 'OFF')
  198.       THEN BEGIN
  199.         Original_Verb := 'TAKE OFF';
  200.         w[1] := 'REMOVE';
  201.         close_up(w, num_words, 2);
  202.       END
  203.       ELSE IF ((w[1] = 'TAKE') OR (w[1] = 'GET'))
  204.       THEN BEGIN
  205.         Original_Verb := w[1];
  206.         w[1] := 'GET';
  207.       END
  208.       ELSE IF ((w[1] = 'THROW') OR (w[1] = 'CAST') OR (w[1] = 'DUMP'))
  209.       THEN BEGIN
  210.         Original_Verb := w[1];
  211.         w[1] := 'THROW';
  212.       END
  213.       ELSE IF ((w[1] = 'SCREAM') OR (w[1] = 'YELL') OR (w[1] = 'SHOUT'))
  214.       THEN BEGIN
  215.         Original_Verb := w[1];
  216.         w[1] := 'YELL';
  217.       END
  218.       ELSE IF ((w[1] = 'EXAMINE') OR (w[1] = 'INSPECT') OR (w[1] = 'CHECK'))
  219.       THEN BEGIN
  220.         Original_Verb := w[1];
  221.         w[1] := 'EXAMINE';
  222.       END
  223.       ELSE IF ((w[1] = 'KILL') OR (w[1] = 'ATTACK') OR (w[1] = 'HIT') OR (w[1] = 'FIGHT'))
  224.       THEN BEGIN
  225.         Original_Verb := w[1];
  226.         w[1] := 'ATTACK';
  227.       END
  228.       ELSE IF ((w[1] = 'PUSH') OR (w[1] = 'TOUCH'))
  229.       THEN BEGIN
  230.         Original_Verb := w[1];
  231.         w[1] := 'PUSH';
  232.       END
  233.       ELSE IF ((w[1] = 'SHOOT') OR (w[1] = 'FIRE'))
  234.       THEN BEGIN
  235.         Original_Verb := w[1];
  236.         w[1] := 'FIRE';
  237.       END
  238.       ELSE IF ((w[1] = 'CLOSE') OR (w[1] = 'SHUT'))
  239.       THEN BEGIN
  240.         Original_Verb := w[1];
  241.         w[1] := 'CLOSE';
  242.       END
  243.       ELSE IF ((w[1] = 'LOOK') AND ((w[2] = 'AT') OR (w[2] = 'IN')))
  244.       THEN BEGIN
  245.         Original_Verb := 'LOOK AT';
  246.         w[1] := 'EXAMINE';
  247.         close_up(w, num_words, 2);
  248.       END
  249.       ELSE IF ((w[1] = 'GO') AND ((w[2] = 'IN') OR (w[2] = 'INTO')))
  250.       THEN BEGIN
  251.         Original_Verb := 'GO INTO';
  252.         w[1] := 'ENTER';
  253.         close_up(w, num_words, 2);
  254.       END
  255.       ELSE IF (w[1] = 'TALK') AND (w[2] = 'TO')
  256.       THEN BEGIN
  257.         Original_Verb := 'TALK TO';
  258.         w[1] := 'TELL';
  259.         close_up(w, num_words, 2);
  260.       END
  261.       ELSE IF (w[1] = 'TALK') AND (w[2] = 'WITH')
  262.       THEN BEGIN
  263.         Original_Verb := 'TALK WITH';
  264.         w[1] := 'TELL';
  265.         close_up(w, num_words, 2);
  266.       END
  267.       ELSE IF (w[1] = 'PUT') AND (w[2] = 'DOWN')
  268.       THEN BEGIN
  269.         Original_Verb := 'PUT DOWN';
  270.         w[1] := 'DROP';
  271.         close_up(w, num_words, 2);
  272.       END
  273.       ELSE IF (w[1] = 'PUT') AND (w[2] = 'ON')
  274.       THEN BEGIN
  275.         Original_Verb := 'PUT ON';
  276.         w[1] := 'WEAR';
  277.         close_up(w, num_words, 2);
  278.       END
  279.       ELSE IF (w[1] = 'PUT') AND (w[2] = 'OUT')
  280.       THEN BEGIN
  281.         Original_Verb := 'PUT OUT';
  282.         w[1] := 'EXTINGUISH';
  283.         close_up(w, num_words, 2);
  284.       END
  285.       ELSE IF ((w[1] = 'PUT') OR (w[1] = 'PLACE'))
  286.       THEN BEGIN
  287.         Original_Verb := w[1];
  288.         w[1] := 'PUT';
  289.       END;
  290.       FirstCut := w[1];
  291.       {Now do global synonyms -- they take precedent over normal verbs}
  292.       FOR i := 1 TO Num_Verbs DO
  293.         IF POS(' '+FirstCut+' ', SYN[i]) <> 0
  294.         THEN BEGIN
  295.           Original_Verb := FirstCut;
  296.           w[1] := V[i];           {substitute "Global" synonyms}
  297.         END;
  298.       {Now do room synonyms -- they take precedent over global synonyms}
  299.       IF Skip_A_Line THEN IF POS(' '+FirstCut+' ', Room[Current_room]^.Replacing_Words) <> 0
  300.         THEN BEGIN
  301.           Original_Verb := FirstCut;
  302.           w[1] := Room[Current_room]^.Replaced_Word;
  303.           {Swap for ROOM SYNONYMS}
  304.         END;
  305.       IF w[1] = 'CHANGE_LOCATION' THEN w[1] := 'CHANGE_LOCATIONS';
  306.       IF Is_Verb(w[1]) THEN
  307.         BEGIN
  308.           OK_Verb := True;
  309.           IF (Original_Verb = ' ') THEN Original_Verb := w[1];
  310.         END
  311.       ELSE Original_Verb := LastVerb;
  312.       Normalize(Original_Verb);
  313.     END;                          {Massage_Verb}
  314.  
  315.     PROCEDURE Make_Into_Words(VAR sentence : s; VAR w : wordlists; VAR num_words : Integer);
  316.     VAR k : Integer;
  317.     BEGIN
  318.       FOR k := 1 TO max_words DO
  319.         w[k] := '';               {initialize word_list to avoid run-time crash}
  320.       l := Length(sentence);
  321.       i := 1;
  322.       num_words := 0;
  323.       Skip_spaces(sentence, i, l);
  324.       WHILE ((i <= l) AND (num_words < max_words)) DO
  325.         BEGIN
  326.           num_words := num_words+1; {we've found another word}
  327.           REPEAT
  328.             w[num_words] := w[num_words]+sentence[i];
  329.             i := i+1;
  330.             Ch := sentence[i];
  331.           UNTIL ((Ch > 'z') OR ((Ch < '0') AND (Ch <> '-') AND (Ch <> Chr(39))) OR (i > l));
  332.           Skip_spaces(sentence, i, l);
  333.         END;                      {while more characters to process}
  334.       IF ((num_words = max_words) AND (i <= l))
  335.       THEN
  336.         BEGIN
  337.           WriteLn(IO, 'Too many words in sentence');
  338.           syntax_error := True;
  339.         END;
  340.       { The words in the sentence are now }
  341.       { broken out into separate words in the }
  342.       { array of words "w", where they can be }
  343.       { examined individually. }
  344.       {Now let's delete any obviously extraneous words}
  345.       k := 1;
  346.       REPEAT
  347.         IF Is_Extra(w[k])         {if word adds no meaning to the}
  348.         THEN close_up(w, num_words, k) {sentence, then eliminate it }
  349.         ELSE k := k+1;
  350.       UNTIL k > num_words;        {loop exit is guaranteed because every time}
  351.       {either k increases or num_words decreases}
  352.     END;                          {Make_Into_Words}
  353.  
  354.     PROCEDURE Scan_For_Prep_Object(LastPart : s; VAR NextPrep, NextObject : words;
  355.                                    VAR syntax_error : Boolean);
  356.     VAR wd : wordlists; num, P : Integer; Finished : Boolean;
  357.     BEGIN
  358.       Make_Into_Words(LastPart, wd, num);
  359.       P := 0;
  360.       Finished := False;
  361.       NextPrep := '';
  362.       NextObject := '';
  363.       syntax_error := False;
  364.       REPEAT                      {scan for next prep in last part of sentence}
  365.         P := P+1;
  366.         IF Is_Prep(wd[P]) THEN
  367.           BEGIN                   {found it}
  368.             NextPrep := wd[P];
  369.             Finished := True;
  370.           END;
  371.       UNTIL Finished OR (P = num);
  372.       Massage_Noun(wd, num, P+1); {check next word(s) for noun}
  373.       IF Is_Valid_Noun(wd[P+1]) THEN NextObject := wd[P+1];
  374.       IF (NextPrep = '') OR (NextObject = '') THEN syntax_error := True;
  375.     END;                          {Scan_For_Prep_Object}
  376.  
  377.   VAR kkk : Integer;
  378.  
  379.   BEGIN                           {Parse(sentence)}
  380.     OK_Verb := False;
  381.     OK_Noun := False;
  382.     Duplicate := False;
  383.     verb := '';
  384.     noun := '';
  385.     prep := '';
  386.     object_word := '';
  387.     noun_adj := '';
  388.     object_adj := '';
  389.     NounNumber := 0;
  390.     ObjectNumber := 0;
  391.     syntax_error := False;
  392.     IF Skip_A_Line THEN WriteLn(IO, ' ');
  393.     IF sentence = '' THEN
  394.       BEGIN
  395.         WriteLn(IO, 'Eh?');
  396.         syntax_error := True;
  397.       END
  398.     ELSE
  399.       BEGIN
  400.         syntax_error := False;
  401.         Make_Into_Words(sentence, w, num_words);
  402.         Massage_Verb(w, num_words); {Now that unnecessary words are removed}
  403.         {let's massage the first word in case it's a compound verb }
  404.         IF NOT OK_Verb
  405.         THEN IF (DoingCompoundCommands OR PreviousCompoundCommands) THEN
  406.             BEGIN
  407.               Massage_Noun(w, num_words, 1); {Is it another noun?}
  408.               noun_adj := adj;
  409.               {now, check to see if it's a recognized noun}
  410.               OK_Noun := Is_Valid_Noun(w[1]);
  411.               IF OK_Noun THEN
  412.                 IF NOT Verb_Needs_Prep(LastVerb) THEN
  413.                   BEGIN           {simple verbs, like GET, DROP, etc}
  414.                     FOR i := num_words DOWNTO 1 DO w[i+1] := w[i];
  415.                     w[1] := LastVerb; {move last verb to w[1]}
  416.                     num_words := num_words+1;
  417.                   END
  418.                 ELSE
  419.                   BEGIN           {Complex Verbs like SHOOT MONSTER WITH LASER}
  420.                     Scan_For_Prep_Object(LastPart, NextPrep, NextObject, syntax_error);
  421.                     IF syntax_error THEN
  422.                       WriteLn(IO, 'You need a preposition and object whenever you try to "', LastVerb, ' ', w[1]
  423.                               , '"!')
  424.                     ELSE BEGIN
  425.                       w[2] := w[1];
  426.                       w[1] := LastVerb;
  427.                       w[3] := NextPrep;
  428.                       w[4] := NextObject;
  429.                     END
  430.                   END
  431.               ELSE                {NOT OK_Noun}
  432.                 BEGIN
  433.                   WriteLn(IO, 'I don''t understand ', w[1], ' as either a verb or a noun.');
  434.                   syntax_error := True;
  435.                 END;
  436.             END                   {DoingCompoundCommands}
  437.           ELSE BEGIN
  438.             WriteLn(IO, 'I don''t understand ', w[1], ' as a verb.');
  439.             syntax_error := True;
  440.           END
  441.           { If the second word is '' or shouldn't exist, let's exit.}
  442.         ELSE IF NOT((num_words = 1) OR (Is_Direction(w[1])))
  443.         THEN                      {check the word/phrase following the verb}
  444.           BEGIN
  445.             {first, massage nouns in case they're compound nouns}
  446.             Massage_Noun(w, num_words, 2);
  447.             noun_adj := adj;
  448.             {now, check to see if it's a recognized noun}
  449.             OK_Noun := Is_Valid_Noun(w[2]);
  450.             IF NOT OK_Noun
  451.             THEN IF Is_Prep(w[2])
  452.               THEN
  453.                 BEGIN
  454.                   Massage_Noun(w, num_words, 3);
  455.                   IF NOT Is_Valid_Noun(w[3])
  456.                   THEN
  457.                     BEGIN
  458.                       WriteLn(IO, 'I don''t understand ', w[3],
  459.                               ' as the object of a preposition.');
  460.                       syntax_error := True;
  461.                     END
  462.                   ELSE
  463.                     BEGIN
  464.                       w[4] := w[3];
  465.                       w[3] := w[2];
  466.                       w[2] := w[4]; {object of prep = noun}
  467.                       noun_adj := adj;
  468.                       object_adj := adj;
  469.                     END
  470.                 END
  471.               ELSE
  472.                 IF ((w[1] = 'EXAMINE') AND Skip_A_Line) THEN
  473.                   BEGIN
  474.                     WriteLn(IO, 'You see nothing unusual.');
  475.                     syntax_error := True;
  476.                   END
  477.                 ELSE BEGIN
  478.                   WriteLn(IO, 'I don''t understand ', w[2], ' as a noun.');
  479.                   syntax_error := True;
  480.                 END
  481.             ELSE IF num_words > 2 THEN {let's continue parsing}
  482.               IF NOT Is_Prep(w[3])
  483.               THEN
  484.                 BEGIN
  485.                   WriteLn(IO, 'I don''t understand ', w[3], ' as a preposition');
  486.                   syntax_error := True;
  487.                 END
  488.               ELSE                {make sure the last word is a noun, too}
  489.                 BEGIN
  490.                   Massage_Noun(w, num_words, 4);
  491.                   object_adj := adj;
  492.                   IF NOT Is_Valid_Noun(w[4])
  493.                   THEN IF w[4] <> '' THEN {allow missing obj. of prep}
  494.                       BEGIN
  495.                         WriteLn(IO, 'I don''t understand ', w[4],
  496.                                 ' as the object of a preposition.');
  497.                         syntax_error := True;
  498.                       END;
  499.                 END;
  500.           END;
  501.         verb := w[1];
  502.         noun := w[2];
  503.         prep := w[3];
  504.         object_word := w[4];
  505.         IF (DoingCompoundCommands OR PreviousCompoundCommands) THEN
  506.           IF ((prep = '') AND (Verb_Needs_Prep(verb))) THEN
  507.             BEGIN                 {Complex Verbs like SHOOT MONSTER WITH LASER}
  508.               Scan_For_Prep_Object(LastPart, NextPrep, NextObject, syntax_error);
  509.               IF syntax_error THEN
  510.                 WriteLn(IO, 'You need a preposition and object whenever you try to "', verb, ' ', noun, '"!')
  511.               ELSE BEGIN
  512.                 prep := NextPrep;
  513.                 object_word := NextObject;
  514.               END
  515.             END;
  516.         IF syntax_error THEN GOTO Exit;
  517.         IF (object_word = 'IT') OR (object_word = 'THEM') {Allows 'IT' or 'THEM'}
  518.         OR (object_word = 'HIM') OR (object_word = 'HER') {Allows 'HIM' or 'HER'}
  519.         THEN BEGIN
  520.           object_word := last_noun_used;
  521.           object_adj := last_adj_used;
  522.         END;
  523.         IF (noun = 'IT') OR (noun = 'THEM')
  524.         OR (noun = 'HIM') OR (noun = 'HER') {Allows 'HIM' or 'HER'}
  525.         THEN BEGIN
  526.           noun := last_noun_used;
  527.           noun_adj := last_adj_used;
  528.         END
  529.         ELSE BEGIN
  530.           last_noun_used := noun;
  531.           last_adj_used := noun_adj;
  532.         END;
  533.         {check for duplicate names and pick one that is visible}
  534.         Adjective := noun_adj;
  535.         IF noun <> '' THEN NounNumber := Noun_Number(noun);
  536.         IF Duplicate AND Skip_A_Line {I.E., two or more are visible}
  537.         THEN HandleDuplicates(0); {0 for NounNumber selection}
  538.         Adjective := object_adj;
  539.         IF ((object_word <> '') AND (NOT syntax_error)) THEN ObjectNumber := Noun_Number(object_word);
  540.         IF Duplicate AND Skip_A_Line {I.E., two or more are visible}
  541.         THEN HandleDuplicates(1); {1 for Object selection}
  542.       END;                        {if sentence=''...else}
  543.     IF (NOT syntax_error) AND (noun <> '') THEN
  544.       BEGIN                       {make sure we use the "official" form of noun}
  545.         i := NounNumber;
  546.         IF (i >= First_noun) AND (i <= MaxNoun)
  547.         THEN noun := N[i]^.name;
  548.         IF (i >= First_creature) AND (i <= MaxCreature)
  549.         THEN noun := M[i]^.name;
  550.       END;
  551.     IF (NOT syntax_error) AND (object_word <> '') THEN
  552.       BEGIN                       {make sure we use the "official" form of object}
  553.         i := ObjectNumber;
  554.         IF (i >= First_noun) AND (i <= MaxNoun)
  555.         THEN object_word := N[i]^.name;
  556.         IF (i >= First_creature) AND (i <= MaxCreature)
  557.         THEN object_word := M[i]^.name;
  558.       END;
  559. Exit: 
  560.   END;                            {Parse(sentence)}
  561.  
  562.