Listing 1 The expansion code for tense and number

/* Copyright (c) 1993 Russell Suereth */

#include "natural.h"
void check_aux_verb(void);
void check_number(void);
void make_response(void);
void make_answer(int);
void get_verb(char, char, char);
int  match_verb(char, char, char);
char response[200];
unsigned char verb_tense[5];
unsigned char verb_number[5];
unsigned char verb_usage;
unsigned char aux_tense[5];
unsigned char aux_number[5];
unsigned char aux_usage;
unsigned char subject_number;
unsigned char tenses[20];
unsigned char numbers[20];
unsigned char usages[20];
unsigned char subjects_type[20];
unsigned char aux_meaning[20] [5];
char auxiliaries[20][25];


/*****************************************************/
/* Compare the passed word with the word in the      */
/* current dictionary record. If they are the same,  */
/* then extract the type (NOUN, VERB, etc.). If the  */
/* type is PRON, then extract pronoun information.   */
/* If the type is VERB, then extract verb            */
/* information.                                      */
/*****************************************************/
int match_record(char *pass_word, int types)
{
   int i, j;
   char *root;
   char *dic_word;
   dic_word = extract_word();
   /* Check if passed word equals dictionary word     */
   if (strcmpi(pass_word, dic_word) != 0) return(1);

   /* Word found, get the type                        */
   for (i=24,j=0; i<28; i++) {
     if (isspace(dic_record[i])) break;
     type_array [word_ct] [types] [j++] = dic_record [i];
   }
   /* Trim the type                                    */
   type_array[word_ct] [types][j] = '\0';

   if (strcmp(type_array[word_ct][types],
             "PRON") == 0)
     subject_number = dic_record[41];

   if (strcmp(type_array[word_ct][types],
             "VERB") == 0) {
     root = extract_root();
     strcpy(root_array[word_ct], root);
     verb_usage = dic_record[29];
     for (i=30,j=0; i<34; i++,j++) {
       if (isspace(dic_record[i])) break;
       verb_tense[j] = dic_record[i];
     }
     verb_tense[j] = '\0';
     for (i=41,j=0; i<43; i++,j++) {
       if (isspace(dic_record[i])) break;
       verb_number[j] = dic_record[i];
     }
     verb_number[j] = '\0';
   }
   return(0);
}

/*****************************************************/
/* Determine if the input sentence contains a known, */
/* underlying structure. If it does, then assign the */
/* correct types and phrases for the words.          */
/*****************************************************/
int check_underlying()
{
   int i = 0;

   /* Structure WH-AUX-PRON-VERB                    */
   if ( (check_type("WH",     i) == 0) &&
       (check_type("AUX",  i+1) == 0) &&
       (check_type("PRON", i+2) == 0) &&
       (check_type("VERB", i+3) == 0) ) {
      strcpy(prime_types[i],   "WH");
      strcpy(prime_types[i+1], "AUX");
      strcpy(prime_types[i+2], "PRON");
      strcpy(prime_types[i+3], "VERB");
      strcpy(phrases[i],   "WHQUESTION");
      strcpy(phrases[i+1], "VERBPHRASE");
      strcpy(phrases[i+2], "NOUNPHRASE");
      strcpy(phrases[i+3], "VERBPHRASE");
      strcpy(auxiliaries[sentence], word_array[i+1]);
      get_aux();
      return(0);
   }

   /* Structure PRON-AUX-VERB-PREP-DET-NOUN         */
   if ( (check_type("PRON",   i) == 0) &&
       (check_type("AUX",  i+1) == 0) &&
       (check_type("VERB", i+2) == 0) &&
       (check_type("PREP", i+3) == 0) &&
       (check_type("DET",  i+4) == 0) &&
       (check_type("NOUN", i+5) == 0) ) {
      strcpy(prime_types[i],   "PRON");
      strcpy(prime_types[i+1], "AUX");
      strcpy(prime_types[i+2], "VERB");
      strcpy(prime_types[i+3], "PREP");
      strcpy(prime_types[i+4], "DET");
      strcpy(prime_types[i+5], "NOUN");
      strcpy(phrases[i],   "NOUNPHRASE");
      strcpy(phrases[i+1], "VERBPHRASE");
      strcpy(phrases[i+2], "VERBPHRASE");
      strcpy(phrases[i+3], "PREPPHRASE");
      strcpy(phrases[i+4], "PREPPHRASE");
      strcpy(phrases[i+5], "PREPPHRASE");
      strcpy(auxiliaries[sentence], word_array[i+1]);
      get_aux();
      return(0);
   }

   /* Structure WH-AUX-NAME-VERB                    */
   if ( (check_type("WH",     i) == 0) &&
       (check_type("AUX",  i+1) == 0) &&
       (check_type("NAME", i+2) == 0) &&
       (check_type("VERB", i+3) == 0) ) {
      strcpy(prime_types[i],    "WH");
      strcpy(prime_types[i+1], "AUX");
      strcpy(prime_types[i+2], "NAME");
      strcpy(prime_types[i+3], "VERB");
      strcpy(phrases[i],   "WHQUESTION");
      strcpy(phrases[i+1], "VERBPHRASE");
      strcpy(phrases[i+2], "NOUNPHRASE");
      strcpy(phrases[i+3], "VERBPHRASE");
      strcpy(auxiliaries[sentence], word_array[i+1]);
      get_aux();
      return (0);
   }

   /* Structure NAME-AUX-AUX-AUX-VERB-PREP-DET-NOUN */
   if ( (check_type("NAME",   i) == 0) &&
       (check_type("AUX",  i+1) == 0) &&
       (check_type("AUX",  i+2) == 0) &&
       (check_type("AUX",  i+3) == 0) &&
       (check_type("VERB", i+4) == 0) &&
       (check_type("PREP", i+5) == 0) &&
       (check_type("DET",  i+6) == 0) &&
       (check_type("NOUN", i+7) == 0) ) {
      strcpy(prime_types[i],   "NAME");
      strcpy(prime_types[i+l], "AUX");
      strcpy(prime_types[i+2], "AUX");
      strcpy(prime_types[i+3], "AUX");
      strcpy(prime_types[i+4], "VERB");
      strcpy(prime_types[i+5], "PREP");
      strcpy(prime_types[i+6], "DET");
      strcpy(prime_types[i+7], "NOUN");
      strcpy(phrases [i],  "NOUNPHRASE");
      strcpy(phrases[i+1], "VERBPHRASE");
      strcpy(phrases[i+2], "VERBPHRASE");
      strcpy(phrases[i+3], "VERBPHRASE");
      strcpy(phrases[i+4], "VERBPHRASE");
      strcpy(phrases[i+5], "PREPPHRASE");
      strcpy(phrases[i+6], "PREPPHRASE");
      strcpy(phrases[i+7], "PREPPHRASE");
      strcpy(auxiliaries[sentence], word_array[i+1]);
      strcat(auxiliaries[sentence], " ");
      strcat(auxiliaries[sentence], word_array[i+2]);
      strcat(auxiliaries[sentence], " ");
      strcat(auxiliaries[sentence], word_array[i+3]);
      get_aux();
      return(0);
   }

   /* Structure NAME-AUX-AUX-VERB-PREP-DET-NOUN  */
   if ( (check_type("NAME",   i) == 0) &&
       (check_type("AUX",  i+1) == 0) &&
       (check_type("AUX",  i+2) == 0) &&
       (check_type("VERB", i+3) == 0) &&
       (check_type("PREP", i+4) == 0) &&
       (check_type("DET",  i+5) == 0) &&
       (check_type("NOUN", i+6) == 0) ) {
      strcpy(prime_types[i],   "NAME");
      strcpy(prime_types[i+1], "AUX");
      strcpy(prime_types[i+2], "AUX");
      strcpy(prime_types[i+3], "VERB");
      strcpy(prime_types[i+4], "PREP");
      strcpy(prime_types[i+5], "DET");
      strcpy(prime_types[i+6], "NOUN");
      strcpy(phrases[i],   "NOUNPHRASE");
      strcpy(phrases[i+1], "VERBPHRASE");
      strcpy(phrases[i+2], "VERBPHRASE");
      strcpy(phrases[i+3], "VERBPHRASE");
      strcpy(phrases[i+4], "PREPPHRASE");
      strcpy(phrases[i+5], "PREPPHRASE");
      strcpy(phrases[i+6], "PREPPHRASE");
      strcpy(auxiliaries[sentence], word_array[i+1]);
      strcat(auxiliaries[sentence], " ");
      strcat(auxiliaries[sentence], word_array[i+2]);
      get_aux();
      return(0);
   }

   /* Structure NAME-AUX-VERB-PREP-DET-NOUN     */
   if ( (check_type("NAME",   i) == 0) &&
       (check_type("AUX",  i+1) == 0) &&
       (check_type("VERB", i+2) == 0) &&
       (check_type("PREP", i+3) == 0) &&
       (check_type("DET",  i+4) == 0) &&
       (check_type("NOUN", i+5) == 0) ) {
      strcpy(prime_types[i],   "NAME");
      strcpy(prime_types[i+1], "AUX");
      strcpy(prime_types[i+2], "VERB");
      strcpy(prime_types[i+3], "PREP");
      strcpy(prima_types[i+4], "DET");
      strcpy(prime_types[i+5], "NOUN");
      strcpy(phrases[i],   "NOUNPHRASE");
      strcpy(phrases[i+1], "VERBPHRASE");
      strcpy(phrases[i+2], "VERBPHRASE");
      strcpy(phrases[i+3], "PREPPHRASE");
      strcpy(phrases[i+4], "PREPPHRASE");
      strcpy(phrases[i+5], "PREPPHRASE");
      strcpy(auxiliaries[sentence], word_array [i +1]);
      get_aux ();
      return(0);
   }

   /* Structure NAME-VERB-PREP-DET-NOUN           */
   if ( (check_type("NAME",   i) == 0) &&
       (check_type("VERB", i+1) == 0) &&
       (check_type("PREP", i+2) == 0) &&
       (check_type("DET",  i+3) == 0) &&
       (check_type("NOUN", i+4) == 0) ) {
      strcpy(prime_types[i],   "NAME");
      strcpy(prime_types[i+1], "VERB");
      strcpy(prime_types[i+2], "PREP");
      strcpy(prime_types[i+3], "DET");
      strcpy(prime_types[i+4], "NOUN");
      strcpy(phrases[i],   "NOUNPHRASE");
      strcpy(phrases[i+1], "VERBPHRASE");
      strcpy(phrases[i+2], "PREPPHRASE");
      strcpy(phrases[i+3], "PREPPHRASE");
      strcpy(phrases[i+4], "PREPPHRASE");
      return (0);
   }
   return(1);
   }

/*****************************************************/
/* Compare the passed type with all the types for    */
/* this word in the type_array. If the type is       */
/* found, then return 0. The pass_number parameter   */
/* identifies the word in the input sentence.        */
/*****************************************************/
int check_type(char *pass_type, int pass_number)
{
   int i;
   for (i=0; type_array[pass_number][i][0]; i++) {
      if (strcmp(type_array[pass_number][i],
                pass_type) == 0)
         /* Passed type is found in array           */
         return (0);
   }
   /* Passed type is not found in array              */
   return(1);
}

/*****************************************************/
/* If the correct type is "NAME" or "PRON" then the  */
/* word refers to a subject so copy the word to the  */
/* subjects array.                                   */
/*****************************************************/
void check_subject()
{
   int i;
   for (i=0; i<word_ct; i++) {
       if (strcmp(prime_types[i], "NAME") == 0) {

          strcpy(subjects[sentence], word_array[i]);
          subject_number = SINGULAR;
          subjects_type[sentence] = NAME;
          break;
       }
       if (strcmp(prime_types[i], "PRON") == 0) {
          strcpy(subjects[sentence], word_array[i]);
          subjects_type[sentence] = PRONOUN;
          break;
       }
  }
  return;
}

/*****************************************************/
/* Determine the sentence tense and usage by         */
/* matching auxiliary and verb information, or by    */
/* matching previous sentence information.           */
/*****************************************************/
void check_aux_verb()
{
   int i, j, matches;
   char *result;
   char temp_tenses[5];

   /*************************************************/
   /* Auxiliary in sentence                         */
   /*************************************************/
   if (strlen(auxiliaries[sentence]) > 0) {
       if (aux_usage != verb_usage) {
           tenses[sentence] = UNKNOWN;
           usages[sentence] = UNKNOWN;
           return;
       }
       for (i=0,j=0,matches=0; aux_tense[i]; i++) {
         if ((result = strchr(verb_tense,aux_tense[i]))
                                        != NULL) {
             temp_tenses[j++] = *result;
             matches++;
         }
       }
       temp_tenses[j] = '\0';
       if (matches == 0) {
           tenses[sentence] = UNKNOWN;
           usages[sentence] = UNKNOWN;
           return;
       }
       usages[sentence] = aux_usage;
       if (matches == 1) {
           tenses[sentence] = temp_tenses[0];
           return;
       }
       for (i=sentence-1; i>=0 && i>=sentence-3; i--) {
          if ((strcmpi(subjects[i],
                     subjects[sentence]) == 0)    &&
             (strcmpi(actions[i],
                     actions[sentence]) == 0)     &&
             (strchr(temp_tenses, tenses[i])
                                     != NULL) &&
             (strlen(places[i]) > 0)) {
             tenses[sentence]    = tenses[i];
             return;
          }
       }
       tenses[sentence]    = PRESENT;
       return;
   }

   /**************************************************/
   /* No auxiliary in sentence                       */
   /**************************************************/
   usages[sentence]  = verb_usage;
   if (strchr(verb_tense, PAST) != NULL) {
       tenses[sentence]   = PAST;
       return;
   }

   /**************************************************/
   /* No auxiliary, verb tense is present or future  */
   /**************************************************/
   for (i=sentence-1; i>=0 && i>=sentence-3; i--) {
      if ((strcmpi(subjects[i],
                 subjects[sentence]) == 0)       &&
          (strcmpi(actions[i],
                 actions[sentence]) == 0)        &&
          (strchr(verb_tense, tenses[i]) != NULL) &&
          (strlen(places[i]) > 0)) {
          tenses[sentence]  = tenses[i];
          return;
      }
   }
   tenses[sentence]  = PRESENT;
   return;
}

/*****************************************************/
/* Match the subject, verb, and auxiliary number.    */
/* If the match is successful, then the sentence     */
/* number is the matched number.                     */
/*****************************************************/
void check_number()
{
   if (strchr(verb_number, subject_number) == NULL) {
      numbers[sentence] = UNKNOWN;
      return;
   }
   if ((strten(auxiliaries[sentence]) > 0) &&
      (strchr(aux_number, subject_number) == NULL)) {
      numbers[sentence] = UNKNOWN;
      return;
   }
   numbers[sentence] = subject_number;
   return;
}

/*****************************************************/
/* Read the dictionary to extract the auxiliary      */
/* information.                                      */
/*****************************************************/
void get_aux()
{
   rewind(infile);
   fgets(dic_record, 80, infile);
   while (! feof(infile)) {
       if (match_aux() == 0)
          return;
       fgets(dic_record, 80, infile);
   }
   return;
}

/*****************************************************/
/* If the sentence auxiliary matches the word in the */
/* current dictionary record, then extract the       */
/* auxiliary information from the dictionary.        */
/*****************************************************/
int match_aux()
{
   int i,j;
   char *dic_word;
   dic_word = extract_word();
   if (strcmpi(auxiliaries[sentence], dic_word) != 0)
      return (1);

   aux_usage = dic_record[29];
   for (i=30,j=0; i<34; i++,j++) {
      if (isspace(dic_record[i])) break;
      aux_tense[j] = dic_record[i];
   }
   /* Trim the tense  */
   aux_tense[j] = '\0';
   for (i=41,j=0; i<43; i++,j++) {
      if (isspace(dic_record[i])) break;
      aux_number[j] = dic_record[i];
   }
   /* Trim the number*/
   aux_number[j] = '\0';
   for (i=44,j=0; i<47; i++,j++) {
      if (isspace(dic_record[i])) break;
      aux_meaning [sentence] [j] = dicrecord [i];
   }
   return(0);
}

/*****************************************************/
/* Generate a response with information from a       */
/* matching, previous sentence.                      */
/*****************************************************/
void make_response()
{
  int i;

  /***************************************************/
  /* Input sentence is not asking for information.   */
  /***************************************************/
  if (strcmpi(word_array[0], "where") != 0) {
    strcpy(response, "OK");
    return;
  }

  /***************************************************/
  /* Match subject, action, tense, and meaning.      */
  /***************************************************/
  for (i=sentence-1; i>=0; i--) {
    if ((strcmpi(subjects[i],subjects[sentence])==0) &&
        (strcmpi(actions[i], actions[sentence]) ==0) &&
        (strlen(places[i])                      > 0) &&
        (tenses[i]              == tenses[sentence]) &&
        (strpbrk(aux_meaning[i],aux_meaning[sentence])
                                      != NULL)) {
        make_answer(i);
        return;
    }
  }
  /***************************************************/
  /* Match subject, action, and tense.               */
  /***************************************************/
  for (i=sentence-1; i>=0; i--) {
    if ((strcmpi(subjects[i],subjects[sentence])==0) &&
        (strcmpi(actions[i], actions[sentence]) ==0) &&
        (strlen(places[i])                      > 0) &&
        (tenses[i]              == tenses[sentence])) {
    make_answer (i);
    return;
    }
  }
  /***************************************************/
  /*Match subject, action, and meaning.              */
  /***************************************************/
  for (i=sentence-1; i>=0; i--) {
    if ((strcmpi(subjects[i],subjects[sentence])==0) &&
        (strcmpi(actions[i], actions[sentence]) ==0) &&
        (strlen(places[i])  > 0) &&
        (strpbrk(aux_meaning[i],aux_meaning[sentence])
                                      != NULL)) {
        strcpy(response, 'I'm not sure, but ");
       make_answer(i);
       return;
    }
  }
  /***************************************************/
  /* Match subject and action.                       */
  /***************************************************/
  for (i=sentence-1; i>=0; i--) {
    if ((strcmpi(subjects[i],subjects[sentence])==0) &&
        (strcmpi(actions[i], actions[sentence]) ==0) &&
        (strlen(places[i])  > 0)) {
       strcpy(response, 'I'm not sure, but ");
       make_answer(i);
       return;
    }
  }
  strcpy(response, "I don't know");
  return;
}

/*****************************************************/
/* Move information from a previous sentence to the  */
/* response.                                         */
/*****************************************************/
void make_answer(int prev_sentence)
{
   if (subjects_type[prev_sentence] == PRONOUN) {
       if (strlen(response) == 0) {
          subjects[prev_sentence][0] =
            (char) toupper(subjects [prev_sentence] [0] );
       }
       else {
          subjects[prev_sentence] [0] =
          (char) tolower(subjects[prev_sentence][0]);
       }
   }
   strcat(response, subjects[prev_sentence]);
   strcat(response, " ");
   if (strlen(auxiliaries[prev_sentence]) > 0) {
       strcat(response, auxiliaries[prev_sentence]);
       strcat(response, " ");
   }
   get_verb(tenses[prev_sentence],
           numbers[prev_sentence],
           usages[prev_sentence]);
   strcat(response, places[prev_sentence]);
   return;
}

/*****************************************************/
/* Get the correct verb from the dictionary.         */
/*****************************************************/
void get_verb(char pass_tense,
            char pass_number, char pass_usage)
{
   rewind{infile);
   fgets(dic_record, 80, infile);
   while (! feof(infile)) {
       if (match_verb(pass_tense,
                    pass_number, pass_usage) == 0)
           break;
       fgets(dic_record, 80, infile);
   }
   return;
}

/*****************************************************/
/* If the verb information in the current record     */
/* matches the passed information, then move the     */
/* correct verb to the response.                     */
/*****************************************************/
int match_verb(char pass_tense,
             char pass_number, char pass_usage)
{
  int i;
  char *root;
  char *dic_word;
  root = extract_root();

  /* Match verb with root  */
  if (strcmpi(actions[sentence], root) == 0) {
     /* Match verb with tense  */
     for (i=301 i<34; i++) {
        if (isspace(dic_record[i])) return(1);
        if (dic_record[i] -= pass_tense) break;
     }
     /* Match verb with number  */
     for (i=41; i<43; i++) {
        if (isspace(dic_record[i])) return(1);
        if (dic_record[i] == pass_number) break;
     }
     /* Match verb with usage  */
     if (dic record[29] == pass_usage) {
        dic_word = extract_word();
        strcat(response, dic_word);
        return(0);
     }
  }
  return(1);
}

/* End of File */