Natural Language

Authors

Publication

Pub Details

Date

Pages

See all articles from QL Hacker's Journal 18

A while back I asked for some help in porting a program listed in the C Users Journal. Emiliano Barbaini of Italy volunteered to help. I sent him the code and in return he sent me back the changes he made to get the program to run on the QL and on an BULL DPX/2.

I took the changes, made them, and then compiled the program. It compiled fine, but I did not notice any changes to the output (still did not work). Emiliano used C68 v 3.05 where as I used v 3.03 (Hey, I know 3.14c is the latest, just shows how often I use C68). This might have made the difference.

I want not too sure about presenting the code here, but Emiliano was able to get it running on a QL. So, I’m sure it’s just something that I am doing (or not doing). Give it a try and see how it works for you.

There were some follow on articles in the C Users Journal that expanded this Natural Language program. If you are interested, I can photocopy the articles for you. The source code for recent issues of the CUJ are available on the Internet.

/* natural_c */
#include <stdlib_h>
#include <stdio_h>
#include <string_h>
#include <ctype_h>

#define ING 73 /* Restriction for ING word */

void initialize(void);
void reset_sentence(void);
void get_record(char *);
char *extract_word(void);
int match_record(char *, int);
char *extract_root(void);
void check_underlying(void);
int check_type(char *,int);
void check_subject(void);
void check_action(void);
void check_place(void);
void make_response(void);
void make_answer(int);
void get_verb_ing(void);
int match_verb_ing(void);

FILE *infile;
char dic_record[80];
int sentence;
int word_ct;
char word_array[10][15];
char root_array[10][15];
char prime_types[10][11];
char phrases[10][11];
char type_array[10][5][11];
char subjects[20][15];
char actions[20][15];
char places[20][31];
char response[80];


void main()
{
char *cur_word;
char in_sentence[80];

initialize();
if ((infile = fopen("diction", "r+")) == NULL) {
printf ("¥nError opening dictionary¥n");
exit(0);
}
printf("¥nSentence: ");

while(gets(in_sentence)) {
if (in_sentence[0] == '¥0') break;
reset_sentence();

cur_word = strtok(in_sentence, " ");
while(cur_word != NULL) {
get_record(cur_word);
cur_word = strtok(NULL, " ");
if (++word_ct > 9) break;
}

check_underlying();

check_subject();
check_action();
check_place();

make_response();
printf("Response: %s¥n¥nSentence: ", response);

if (++sentence > 19) break;
} /* end while */

fclose(infile);
return;
}

/*****************************************************/
/* Initialize variables (subjects, actions and */
/* places arrays contain entries for 20 sentences). */
/*****************************************************/
void initialize()
{
int i;
for (i=0; i<20; i++) {
subjects[i][0] = '¥0';
actions[i][0] = '¥0';
places[i][0] = '¥0';
}
sentence = 0;
return;
}

/*****************************************************/
/* These variables are initialized for each new */
/* input sentence (each of the 10 word entries for */
/* the input sentence has 5 type_array entries). */
/*****************************************************/
void reset_sentence()
{
int i,j;
word_ct = 0;
for (i=0; i<10; i++) {
word_array[i][0] = '¥0';
root_array[i][0] = '¥0';
prime_types[i][0] = '¥0';
phrases[i][0] = '¥0';
for (j=0; j<5; j++)
type_array[i][j][0] = '¥0';
}
return;
}

/*****************************************************/
/* Get all the records from the dictionary. If the */
/* passed word is not in the dictionary, then the */
/* word could be a name. */
/*****************************************************/
void get_record(char *pass_word)
{
int types = 0;
rewind (infile);
fgets(dic_record, 80, infile);
while (! feof(infile)) {
if (match_record(pass_word, types) == 0)
types++;
fgets(dic_record, 80, infile);

/***** Deleted Line
puts(dic_record);
*********/

}
if (types == 0) {

/*** Old Line ***/
if (isupper( (int) pass_word[0]))
/**** ***/

if (isupper(pass_word[0]) != 0)
strcpy(type_array[word_ct][types], "NAME");
else
strcpy(type_array[word_ct][types],
"NOTFOUND");
}
strcpy(word_array[word_ct], pass_word);
return;
}

/*****************************************************/
/* 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 a VERB, then also extract the root and */
/* and copy it to the root array. */
/*****************************************************/
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=14,j=0; i<20; 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],
"VERB") == 0) {
root = extract_root();
strcpy(root_array[word_ct], root);
}

return(0);
}

/*****************************************************/
/* Extract the word from the dictionary. The word is */
/* 14 characters in length and starts in column 1. */
/*****************************************************/
char *extract_word()
{
int i, j;
char dic_word[15];
for (i=0,j=0; i<14; i++) {
if (isspace(dic_record[i])) break;
dic_word[j++] = dic_record[i];
}
/* Trim the dictionary word */
dic_word[j] = '¥0';
return(dic_word);
}

/*****************************************************/
/* Extract the root from the dictionary. It */
/* identifies a group of similar words (the root for */
/* run, ran, runs and running is run). It is 14 */
/* characters in length and starts in column 35. */
/*****************************************************/
char *extract_root()
{
int i, j;
char root[15];
for (i=34,j=0; i<48; i++) {
if (isspace(dic_record[i])) break;
root[j++] = dic_record[i];
}
/* Trim the root */
root[j] = '¥0';
return(root);
}

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

/* Structure WH-AUX-NAME-VERB */
i = 0;
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");
return;
}


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


/* 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(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");
return;
}

return;
}

/*****************************************************/
/* 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", 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]);
break;
}
}
return;
}

/*****************************************************/
/* If the correct type is "VERB", then the word */
/* refers to an action so copy the word's root from */
/* the root array to the actions array. */
/*****************************************************/
void check_action()
{
int i;
for (i=0; i<word_ct; i++) {
if (strcmp(prime_types[i], "VERB") == 0) {
strcpy(actions[sentence], root_array[i]);
break;
}
}
return;
}

/*****************************************************/
/* If the phrase is a "PREPPHRASE", then all the */
/* words in the phrase refer to a place. Concatenate */
/* these words to the places array. */
/*****************************************************/
void check_place()
{
int i;
for (i=0; i<word_ct; i++) {
if (strcmp(phrases[i], "PREPPHRASE") == 0) {
strcat(places[sentence], " ");
strcat(places[sentence], word_array[i]);
}
}
return;
}

/*****************************************************/
/* Determine the kind of response to generate. If */
/* the input sentence is a where-question and the */
/* subject and action is found in a previous array */
/* entry, then the response can state the location */
/* of where the subject and action occured. */
/*****************************************************/
void make_response()
{
int i;

/* Last input sentence is not a where-question */
if (strcmpi(word_array[0],"where") != 0) {
strcpy(response, "Ok");
return;
}

/* Last input sentence is a where-question */
for (i=sentence-1; i >= 0; i--) {
if ( (strcmp(subjects[i],
subjects[sentence]) == 0) &&
(strcmp(actions[i],
actions[sentence]) == 0) &&
(strlen(places[i]) != 0) ) {
make_answer(i);
return;
}
}

/* Not enough information in actions and */
/* subjects arrays. */
strcpy(response, "I don't know");
return;
}

/*****************************************************/
/* Generate a response that states the location of */
/* where the subject and action occured. */
/*****************************************************/
void make_answer(int prev_sentence)
{
strcpy(response, subjects[prev_sentence]);
strcat(response, " ");
strcat(response, "was ");
get_verb_ing();
strcat(response, places[prev_sentence]);
return;
}

/*****************************************************/
/* Retrieve the ING version of the word from the */
/* dictionary (the ING version of run is running). */
/*****************************************************/
void get_verb_ing()
{
rewind (infile);
fgets(dic_record, 80, infile);
while (! feof(infile)) {
if (match_verb_ing() == 0) break;
fgets(dic_record, 80, infile);
}
return;
}

/*****************************************************/
/* If the root in the current dictionary record */
/* matches the root in the actions array, and the */
/* current dictionary record has an ING restriction, */
/* then extract the dictionary word and return 0. */
/*****************************************************/
int match_verb_ing()
{
int i;
char *root;
char *dic_word;

root = extract_root();
if (strcmp(actions[sentence],root) == 0) {
/* Root found, look for ING restriction */
for (i=24; i<33; i++) {
if (isspace(dic_record[i])) break;
if (dic_record[i] == ING) {
dic_word = extract_word();
strcat(response, dic_word);
return(0);
}
}
}
return(1);
}


Dictionary file : diction

a DET
the DET
house NOUN
street NOUN
store NOUN
jump NOUN
go VERB go
goes VERB go
going VERB I go
went VERB go
run VERB run
runs VERB run
running VERB I run
ran VERB run
walk VERB walk
walks VERB walk
walking VERB I walk
walked VERB walk
jump VERB jump
jumps VERB jump
jumping VERB I jump
jumped VERB jump
is AUX
was AUX
to PREP
in PREP
on PREP
where WH

Products

 

Downloadable Media

 

Image Gallery

Scroll to Top