Putting the techniques already described together, and building upon them we can start to look to the future. A future where intelligence is evident in computer programs.
FRANK is a demonstration of a computer program which learns by accepting input from the operator, and uses what it knows to make intelligent responses to questions. The program is offered as an example skeleton of how certain AI techniques can be used to create intelligent computer programs. It is not intended to be viewed as a finished program.
Frank receives an input from the operator, and then branches to one of many possible sub-modules depending upon the nature of the input.
INPUT | +----|-----|------|----|----|----|--|-+-|-----|-----|----|----|---|-----+ | | | | | | | | | | | | | | | WHAT HOW WHERE WHEN WHY HAVE DO | DID SHOULD IS WILL I YOU OTHER | CAN Fig 1. First level of decision treeEach branch of the descision tree branches in turn to other more specific inputs. For example. The WHAT branch sub-divides depending upon the target subject: You, Your, I or something else. So the input "WHAT IS YOUR NAME?" will pass first to the WHAT branch. From there it will pass to the YOUR sub- branch of the WHAT branch. This branch can have a multitude of sub-branches and leaves. Such as: NAME, AGE, SEX, CREED, BREEDING, FATHER'S, MOTHER'S etc.
WHAT | +-------+----+-|---------+ | | | | YOU YOUR I OTHER Fig 2. WHAT decision branch level oneThe sub-branches may sub-divide themselves in to infinite recusions of the same sub-branch structure as illustrated in fig 3.
YOUR | +-----|----|-----|-------+---------|-----------+ | | | | | | | NAME AGE SEX CREED BREEDING FATHER'S MOTHER'S | | +-----|----|-----|-------|----------+-----------+ | | | | | | | NAME AGE SEX CREED BREEDING FATHER'S MOTHER'S | | etc Fig 3. WHAT....YOUR decision sub-branchFacts about FRANK are hard coded, or can be entered, but must start "FRANK ". Other knowledge can be stored in a file called "frank.dat". By amending the knowledge available to FRANK, you can see how learning can occur.
Listing 1. Frank Main program /*-----------------------------------------------------------------*/ /* FRANK */ /* Conversational Computer Model */ /*-----------------------------------------------------------------*/ #includeThe SHOULD module illustrates how Frank makes decisions based upon the information already given to it. In deciding whether or not the operator should do something, Frank extracts the action from the input, and scans its knowledge base for a value judgement on that action. If a value judgment is found, the object of the judgement is compared with the object of the input. If the two correspond, or the value judgement knowledge does not have a qualifying object, then an affirmative encouragement can be made to the operator.#include #include char text[250]; /* User input */ char f_last[250]; /* Frank's last statement */ /* Parser variables */ char question[80]; char order[80]; char object[80]; char description[80]; char subject[80]; char number[80]; char action[80]; char location[80]; char colour[80]; char size[80]; char who[80]; char tense; /* Record of statements */ /* Statements about frank MUST commence FRANK */ char *facts[2000] = { "FRANK DOES LIKE CATS BECAUSE THEY'RE INDEPENDANT." , "FRANK DOES NOT LIKE DOGS BECAUSE THEY'RE DUMB." , "FRANK DOES NOT SMOKE BECAUSE I'M NOT ALLOWED TO!" , "FRANK HAS BEEN TO MORROCO", "FRANK HAS BEEN TO AMERICA", "FRANK HAS NEVER BEEN TO GERMANY" }; /* Index into facts table */ int fact_ptr; char fflags[2000]; char stk[50][40]; int stp; typedef struct { char text[240]; char object[80]; char description[80]; char action[80]; } SUBJECT; SUBJECT psubj; SUBJECT predicate; SUBJECT clause1; SUBJECT clause2; SUBJECT clause3; SUBJECT clause4; /*---------------------*/ /* Function prototypes */ /*---------------------*/ void DID(void); void DO(void); void EXPAND(void); void GET_DATA(void); void HAVE(void); void HOW(void); void I(void); void INITIALISE(void); void IS(void); void RESPOND(void); void SHOULD(void); void STATEMENT(void); void WHAT(void); void WHEN(void); void WHERE(void); void WHY(void); void WILL(void); void YOU(void); void strchg(char *, char *, char *); void strins(char *, char *); void strlench(char *,int); void truncstr(char *,int); /*---------------*/ /* Start of code */ /*---------------*/ void cdecl say(char *format, ...) { /*----------------------*/ /* Frank says something */ /*----------------------*/ va_list arg_ptr; static char output[1000]; va_start(arg_ptr, format); vsprintf(output, format, arg_ptr); va_end(arg_ptr); if (*output) strcpy(f_last,output); printf("%s",f_last); } void TOPAST(char *word) { /*------------------------------*/ /* Convert a word to past tense */ /*------------------------------*/ if (word[strlen(word) - 1] == 'E') strcat(word,"D"); else if (word[strlen(word) - 1] == 'Y') { /* Irregular words! */ if (stricmp(word,"PAY") == 0) strcpy(word,"PAID"); else if (stricmp(word,"PLAY") == 0) strcpy(word,"PLAYED"); else if (stricmp(word,"FLY") == 0) strcpy(word,"FLEW"); else { word[strlen(word) - 1] = 0; strcat(word,"IED"); } } else strcat(word,"ED"); } void EXPAND() { /*--------------------------*/ /* Expand abbreviated words */ /*--------------------------*/ /* DON'T must be protected from expansion */ strchg(text,"DON'T","DON|T"); /* Expand "'RE" */ strchg(text,"'RE"," ARE"); /* Expand "'S" */ strchg(text,"'S"," IS"); /* Expand I'M */ strchg(text,"I'M","I AM"); /* Expand "N'T" */ strchg(text,"N'T"," NOT"); /* Expand "I'VE" */ strchg(text,"I'VE","I HAVE"); /* DON'T must be protected from expansion */ strchg(text,"DON|T","DON'T"); } char GET_ATT(char *s1, char *s2) { /*---------------------------------------------*/ /* Determine the operators attitude towards s2 */ /*---------------------------------------------*/ char string[100]; strcpy(string,"I DON'T LIKE "); strcat(string,s2); if (strstr(s1,string)) return(0); strcpy(string,"I DON'T LOVE "); strcat(string,s2); if (strstr(s1,string)) return(0); strcpy(string,"I DON'T ENJOY "); strcat(string,s2); if (strstr(s1,string)) return(0); strcpy(string,"I DON'T DISLIKE "); strcat(string,s2); if (strstr(s1,string)) return(1); strcpy(string,"I HATE "); strcat(string,s2); if (strstr(s1,string)) return(0); strcpy(string,"I DISLIKE "); strcat(string,s2); if (strstr(s1,string)) return(0); strcpy(string,"I LIKE "); strcat(string,s2); if (strstr(s1,string)) return(1); strcpy(string,"I LOVE "); strcat(string,s2); if (strstr(s1,string)) return(1); strcpy(string,"I ENJOY "); strcat(string,s2); if (strstr(s1,string)) return(1); strcpy(string,"I DO ENJOY "); strcat(string,s2); if (strstr(s1,string)) return(1); return(1); } char GET_FATT(char *s1, char *s2) { /*----------------------------------------------*/ /* Determine the computer's attitude towards s2 */ /*----------------------------------------------*/ char string[100]; strcpy(string,"FRANK DOES NOT LIKE "); strcat(string,s2); if (strstr(s1,string)) return(0); strcpy(string,"FRANK DOES NOT ENJOY "); strcat(string,s2); if (strstr(s1,string)) return(0); strcpy(string,"FRANK DOES NOT "); strcat(string,s2); if (strstr(s1,string)) return(0); strcpy(string,"FRANK DOES LIKE "); strcat(string,s2); if (strstr(s1,string)) return(1); strcpy(string,"FRANK DOES ENJOY "); strcat(string,s2); if (strstr(s1,string)) return(1); return(1); } void RESPOND() { /*------------------------------*/ /* Root of the response process */ /*------------------------------*/ char *p; char key_word[40]; /*---------------------------*/ /* Get first word from input */ /*---------------------------*/ p = strchr(text,32); if (p) { *p = 0; p++; strcpy(key_word,text); memmove(text,p,strlen(p)+1); } else { strcpy(key_word,text); *text = 0; } /*-------------------------------*/ /* Branch on first word of input */ /*-------------------------------*/ if (strcmp(key_word,"WHAT") == 0) { WHAT(); return; } if (strcmp(key_word,"HOW") == 0) { HOW(); return; } if (strcmp(key_word,"WHERE") == 0) { WHERE(); return; } if (strcmp(key_word,"WHEN") == 0) { WHEN(); return; } if (strcmp(key_word,"WHY") == 0) { WHY(); return; } if (strcmp(key_word,"HAVE") == 0) { HAVE(); return; } if (strcmp(key_word,"DO") == 0 || strcmp(key_word,"DOES") == 0) { DO(); return; } if (strcmp(key_word,"CAN") == 0) { DO(); return; } if (strcmp(key_word,"DID") == 0) { DID(); return; } if (strcmp(key_word,"SHOULD") == 0) { SHOULD(); return; } if (strcmp(key_word,"IS") == 0) { IS(); return; } if (strcmp(key_word,"ARE") == 0) { IS(); return; } if (strcmp(key_word,"WILL") == 0) { WILL(); return; } if (strcmp(key_word,"I") == 0) { I(); return; } if (strcmp(key_word,"YOU") == 0) { YOU(); return; } /* Put key_word back at start of text */ strcat(key_word," "); strins(text,key_word); STATEMENT(); } void INITIALISE() { /* Set variables */ strcpy(f_last,"I didn't say anything."); /* Find end of facts table */ fact_ptr = 0; while(facts[fact_ptr]) fflags[fact_ptr++] = 0; } void GET_DATA() { char *p; char temp[1000]; FILE *fp; fp = fopen("frank.dat","r"); if (fp == NULL) return; for(;;) { p = fgets(temp,999,fp); if (p == NULL) break; truncstr(temp,1); facts[fact_ptr] = malloc(strlen(temp)); if (facts[fact_ptr] == NULL) { printf("\nOut of memory"); exit(0); } strcpy(facts[fact_ptr++],temp); } fclose(fp); } void main() { char *p; clrscr(); INITIALISE(); GET_DATA(); for(;;) { printf("\n?"); gets(text); /* Remove leading spaces */ p = text; while(*p == 32) p++; memmove(text,p,strlen(p) + 1); /* Remove trailing puntuation */ p = &text[strlen(text) - 1]; while(strchr("?.;:!,",*p) && p >= text) *p-- = 0; /* If an empty string has been entered, abort */ if (*text == 0) break; /* Convert text to upper case */ strupr(text); /* Expand */ EXPAND(); RESPOND(); } } Listing 2. Frank WHAT sub-module /* Frank WHAT() */ #include #include extern char text[]; extern char *facts[]; extern int fact_ptr; extern char question[80]; extern char order[80]; extern char object[80]; extern char description[80]; extern char subject[80]; extern char number[80]; extern char action[80]; extern char location[80]; extern char colour[80]; extern char size[80]; extern char who[80]; extern char tense; /* Function prototypes */ void NLP(void); void say(char *, ...); char *strrstr(char *,char *); void WCOMPUTER(void); void WCOMPUTERS(void); void WHUMAN(void); void WOTHER(void); void WHAT() { /* Start of the branch for all WHAT questions */ /* Straight WHAT */ if (*text == 0) { say(""); return; } /* Parse text */ NLP(); /* Possible branches depending upon the target */ if (strcmp(who,"YOU") == 0 || strcmp(who,"YOU,") == 0) { /* Reference made to 'FRANK' */ WCOMPUTER(); return; } if (strcmp(who,"YOUR") == 0 || strcmp(who,"YOUR,") == 0) { /* Reference made to something of 'FRANK' */ WCOMPUTERS(); return; } if (strcmp(who,"I") == 0 || strcmp(who,"I,") == 0) { /* Reference made to the operator */ WHUMAN(); return; } /* No recognisable reference made */ WOTHER(); return; } void WCOMPUTER() { /* WHAT DO YOU.... */ int n; char *p; if (strcmp(action,"THINK") == 0) { p = strstr(text,object); memmove(text,p,strlen(text)); for(n = 0; n < fact_ptr; n++) { if (strncmp("FRANK",facts[n],5) == 0 && strstr(facts[n],text)) { /* This fact does apply to FRANK */ p = strrstr(facts[n],"DOES"); if (p) { say("I DO %s",p); return; } } } say("I HAVE NO FEELINGS ABOUT %s.",text); return; } say("I DON'T KNOW!"); return; } void WCOMPUTERS() { /* WHAT....YOUR.... */ if (strcmp(object,"NAME") == 0) { if (tense == 1) say("MY NAME WAS, AND STILL IS FRANK."); else if (tense == 2) say("MY NAME'S FRANK."); else say("MY NAME WILL STILL BE FRANK."); return; } } void WHUMAN() { /* WHAT....I.... */ say("I DON'T KNOW!"); return; } void WOTHER() { int n; char *p; if (strcmp(question,"IS") == 0 || strcmp(question,"ARE") == 0 || strcmp(question,"DOES") == 0) { /* WHAT IS.... or WHAT ARE.... */ /* Search facts table for the object */ for(n = 0; n < fact_ptr; n++) { if ((p = strstr(facts[n],object)) != NULL) { p += strlen(object); if (strchr(".,;: ", *p) || *p == 0) { say(facts[n]); return; } } } } say("I HAVE NO IDEA!"); } Listing 3. Frank HOW sub-module. /* Frank HOW() */ #include #include typedef struct { char text[240]; char object[80]; char description[80]; char action[80]; } SUBJECT; extern SUBJECT psubj; extern SUBJECT predicate; extern SUBJECT clause1; extern SUBJECT clause2; extern SUBJECT clause3; extern SUBJECT clause4; extern char text[]; extern char *facts[]; extern int fact_ptr; extern char question[80]; extern char order[80]; extern char object[80]; extern char description[80]; extern char subject[80]; extern char number[80]; extern char action[80]; extern char location[80]; extern char colour[80]; extern char size[80]; extern char who[80]; extern char tense; void HOW_YOU(void); void NLP(void); void say(char *, ...); void strins(char *, char *); char *strrstr(char *, char *); void strlench(char *,int ); void HOW() { /*---------*/ /* HOW.... */ /*---------*/ int n; char string[250]; char *p; NLP(); /*--------------*/ /* HOW...YOU... */ /*--------------*/ if (strcmp(who,"YOU") == 0 || strncmp(who,"YOU,",4) == 0) { HOW_YOU(); return; } say("I HAVE NO IDEA!"); } void HOW_YOU() { /*----------------*/ /* HOW....YOU.... */ /*----------------*/ if (strcmp(question,"DO") == 0 && strcmp(text,"YOU DO") == 0) { /* How do you do? */ say("VERY WELL, THANKS!"); return; } if (strcmp(question,"ARE") == 0 && strcmp(text,"YOU") == 0) { /* How are you? */ say("VERY WELL, THANKS!"); return; } say("I DON'T KNOW!"); } Listing 4. Frank WHERE sub-module /* Frank WHERE() */ #include #include typedef struct { char text[240]; char object[80]; char description[80]; char action[80]; } SUBJECT; extern SUBJECT psubj; extern SUBJECT predicate; extern SUBJECT clause1; extern SUBJECT clause2; extern SUBJECT clause3; extern SUBJECT clause4; extern char text[]; extern char *facts[]; extern int fact_ptr; extern char question[80]; extern char order[80]; extern char object[80]; extern char description[80]; extern char subject[80]; extern char number[80]; extern char action[80]; extern char location[80]; extern char colour[80]; extern char size[80]; extern char who[80]; extern char tense; void NLP(void); void WHERE_YOU(void); void say(char *, ...); void strins(char *, char *); char *strrstr(char *, char *); void strlench(char *,int ); void WHERE() { /*-----------*/ /* WHERE.... */ /*-----------*/ int n; char string[250]; char *p; NLP(); /*----------------*/ /* WHERE...YOU... */ /*----------------*/ if (strcmp(who,"YOU") == 0 || strncmp(who,"YOU,",4) == 0) { WHERE_YOU(); return; } say("I HAVE NO IDEA!"); } void WHERE_YOU() { /*------------------*/ /* WHERE....YOU.... */ /*------------------*/ if (strcmp(action,"GOING") == 0) { /* Where are you going? */ say("I'M NOT GOING ANY WHERE!"); } say("I DON'T KNOW!"); } Listing 5. Frank WHEN sub-module. /* Frank WHEN() */ #include #include typedef struct { char text[240]; char object[80]; char description[80]; char action[80]; } SUBJECT; extern SUBJECT psubj; extern SUBJECT predicate; extern SUBJECT clause1; extern SUBJECT clause2; extern SUBJECT clause3; extern SUBJECT clause4; extern char text[]; extern char *facts[]; extern int fact_ptr; extern char question[80]; extern char order[80]; extern char object[80]; extern char description[80]; extern char subject[80]; extern char number[80]; extern char action[80]; extern char location[80]; extern char colour[80]; extern char size[80]; extern char who[80]; extern char tense; void NLP(void); void WHEN_YOU(void); void say(char *, ...); void strins(char *, char *); char *strrstr(char *, char *); void strlench(char *,int ); void WHEN() { /*-----------*/ /* WHEN.... */ /*-----------*/ int n; char string[250]; char *p; NLP(); /*---------------*/ /* WHEN...YOU... */ /*---------------*/ if (strcmp(who,"YOU") == 0 || strncmp(who,"YOU,",4) == 0) { WHEN_YOU(); return; } say("I HAVE NO IDEA!"); } void WHEN_YOU() { /*-----------------*/ /* WHEN....YOU.... */ /*-----------------*/ if (strcmp(action,"GOING") == 0) { /* When are you going? */ say("I'M NOT GOING ANY WHERE!"); return; } say("I DON'T KNOW!"); } Listing 6. Frank WHY sub-module. /* Frank WHY() */ #include #include typedef struct { char text[240]; char object[80]; char description[80]; char action[80]; } SUBJECT; extern SUBJECT psubj; extern SUBJECT predicate; extern SUBJECT clause1; extern SUBJECT clause2; extern SUBJECT clause3; extern SUBJECT clause4; extern char text[]; extern char *facts[]; extern int fact_ptr; extern char question[80]; extern char order[80]; extern char object[80]; extern char description[80]; extern char subject[80]; extern char number[80]; extern char action[80]; extern char location[80]; extern char colour[80]; extern char size[80]; extern char who[80]; extern char tense; void WHY_DO_YOU(void); char GET_FATT(char *, char *); void NLP(void); void say(char *, ...); void strins(char *, char *); char *strrstr(char *, char *); void strlench(char *,int ); void WHY() { /* WHY.... */ NLP(); if ((strcmp(who,"YOU") == 0 || strcmp(who,"YOU,") == 0) && (strcmp(question,"DO") == 0 || strcmp(object,"DON'T") == 0)) { WHY_DO_YOU(); return; } say("I HAVE NO IDEA!"); } void WHY_DO_YOU() { /* WHY DO YOU.... */ char attitude; char negative; int n; char *p; if (strcmp(object,"DON'T")) { memmove(text,&text[4],strlen(text)); negative = 0; if (strcmp(object,"NOT") == 0) { strcpy(object,subject); p = strstr(text,"NOT"); if (p) strlench(p,-4); negative = 1; } } else { memmove(text,&text[10],strlen(text)); negative = 1; } for(n = 0; n < fact_ptr; n++) { if (strncmp("FRANK",facts[n],5) == 0 && strstr(facts[n],text)) { /* This fact does apply to FRANK */ if (strcmp(action,"LIKE") == 0) { p = strstr(facts[n],"BECAUSE"); attitude = GET_FATT(facts[n],object); if (negative) { if (attitude == 1) say("NO I %s",text); else say("%s",p); } else { if (attitude == 1) say("%s",p); else say("I DO NOT %s",text); } return; } else { attitude = GET_FATT(facts[n],text); p = strstr(facts[n],"BECAUSE"); if (negative) { if (attitude == 1) say("BUT I DO %s",text); else say("%s",p); return; } if (attitude == 1) say("%s",p); else say("BUT I DON'T %s",text); return; } } } say("I DON'T KNOW"); return; } Listing 7. Frank HAVE sub-module. /* Frank HAVE() */ #include #include typedef struct { char text[240]; char object[80]; char description[80]; char action[80]; } SUBJECT; extern SUBJECT psubj; extern SUBJECT predicate; extern SUBJECT clause1; extern SUBJECT clause2; extern SUBJECT clause3; extern SUBJECT clause4; extern char text[]; extern char *facts[]; extern int fact_ptr; extern char question[80]; extern char order[80]; extern char object[80]; extern char description[80]; extern char subject[80]; extern char number[80]; extern char action[80]; extern char location[80]; extern char colour[80]; extern char size[80]; extern char who[80]; extern char tense; void HAVE_YOU(void); char GET_FATT(char *, char *); void NLP(void); void say(char *, ...); void strins(char *, char *); char *strrstr(char *, char *); void strlench(char *,int ); void HAVE() { /* HAVE.... */ int n; char string[250]; char *p; NLP(); if (strcmp(who,"YOU") == 0 || strncmp(who,"YOU,",4) == 0) { HAVE_YOU(); return; } for(n = 0; n < fact_ptr; n++) { if(strstr(facts[n],text)) { say("I BELIEVE SO"); return; } } strcpy(string,text); p = strrstr(string,object); if (p) { strins(p,"DON'T "); for(n = 0; n < fact_ptr; n++) { if(strstr(facts[n],string)) { say("I DON'T THINK SO."); return; } } strcpy(string,text); p = strrstr(string,object); strins(p,"DO "); for(n = 0; n < fact_ptr; n++) { if(strstr(facts[n],string)) { say("I THINK SO."); return; } } strcpy(string,text); p = strrstr(string,object); strins(p,"DO NOT "); for(n = 0; n < fact_ptr; n++) { if(strstr(facts[n],string)) { say("I DO NOT THINK SO."); return; } } } say("I HAVE NO IDEA!"); } void HAVE_YOU() { /* HAVE YOU.... */ int n; char string[250]; memmove(text,&text[4],strlen(text)); /* Remove 'EVER' as it's superflous */ if (strncmp(text,"EVER ",5) == 0) memmove(text,&text[5],strlen(text)); strcpy(string,"NOT "); strcat(string,text); for(n = 0; n < fact_ptr; n++) { if (strncmp("FRANK",facts[n],5) == 0 && strstr(facts[n],text)) { /* This fact does apply to FRANK */ /* Check for negative response */ strcpy(string,"NOT "); strcat(string,text); if (strstr(facts[n],string)) say("NO, I HAVE %s",string); else { strcpy(string,"NEVER "); strcat(string,text); if (strstr(facts[n],string)) say("NO, I HAVE %s",string); else say("YES, I HAVE %s",text); } return; } } say("I DON'T KNOW"); return; } Listing 8. Frank DO sub-module. /* Frank DO() */ #include #include typedef struct { char text[240]; char object[80]; char description[80]; char action[80]; } SUBJECT; extern SUBJECT psubj; extern SUBJECT predicate; extern SUBJECT clause1; extern SUBJECT clause2; extern SUBJECT clause3; extern SUBJECT clause4; extern char text[]; extern char *facts[]; extern char fflags[]; extern int fact_ptr; extern char stk[50][40]; extern int stp; extern char question[80]; extern char order[80]; extern char object[80]; extern char description[80]; extern char subject[80]; extern char number[80]; extern char action[80]; extern char location[80]; extern char colour[80]; extern char size[80]; extern char who[80]; extern char tense; int DOES_OBJECT(char *); void DO_YOU(void); char GET_FATT(char *, char *); void NLP(void); void say(char *, ...); void strins(char *, char *); char *strrstr(char *, char *); void strlench(char *,int ); void DO() { /* DO.... */ int n; NLP(); if (strcmp(who,"YOU") == 0 || strncmp(who,"YOU,",4) == 0) { DO_YOU(); return; } n = DOES_OBJECT(text); if (n == 0) say("I DON'T THINK SO!"); else if (n == 1) say("YES! I THINK SO."); else say("I HAVE NO IDEA"); return; } void DO_YOU() { /* DO YOU.... */ char attitude; char negative; int n; char *p; char string[250]; memmove(text,&text[4],strlen(text)); negative = 0; if (strcmp(object,"NOT") == 0) { strcpy(object,subject); p = strstr(text,"NOT"); if (p) strlench(p,-4); negative = 1; } for(n = 0; n < fact_ptr; n++) { if (strncmp("FRANK",facts[n],5) == 0 && strstr(facts[n],text)) { /* This fact does apply to FRANK */ if (strcmp(action,"LIKE") == 0) { attitude = GET_FATT(facts[n],object); if (negative) { if (attitude == 1) say("NO I %s",text); else say("NO I DO NOT %s",text); } else { if (attitude == 1) say("YES I %s",text); else say("NO I DO NOT %s",text); } return; } else { strcpy(string,"NOT "); strcat(string,text); if (strstr(facts[n],text)) say("NO, I DO %s",string); else { strcpy(string,"NEVER "); strcat(string,text); if (strstr(facts[n],text)) say("NO, I HAVE %s",string); else say("YES, I %s",text); } return; } } } say("I DON'T KNOW"); return; } int DOES_OBJECT(char *s1) { char string[250]; char this_object[80]; char act[80]; int n; char known; /* Reset fflags[] */ for(n = 0; n < fact_ptr; n++) fflags[n] = 0; strcpy(this_object,object); stp = -1; strcpy(text,s1); NLP(); if (*subject) strcpy(text,subject); else strcpy(text,object); strcpy(object,this_object); strcpy(act,action); if (*act) strcat(act," "); do { known = 0; /* Check for object does not do action period! */ strcpy(string,object); strcat(string," DOES NOT "); strcat(string,act); truncstr(string,1); for(n = 0; n < fact_ptr; n++) { if(strcmp(facts[n],string) == 0) { return(0); } } strcpy(string,object); strcat(string," DO NOT "); strcat(string,act); truncstr(string,1); for(n = 0; n < fact_ptr; n++) { if(strcmp(facts[n],string) == 0) { return(0); } } /* Check for object does do action period! */ strcpy(string,object); strcat(string," DOES "); strcat(string,act); truncstr(string,1); for(n = 0; n < fact_ptr; n++) { if(strcmp(facts[n],string) == 0) { return(1); } } strcpy(string,object); strcat(string," DO "); strcat(string,act); truncstr(string,1); for(n = 0; n < fact_ptr; n++) { if(strcmp(facts[n],string) == 0) { return(1); } } strcpy(string,object); strcat(string," "); strcat(string,act); truncstr(string,1); for(n = 0; n < fact_ptr; n++) { if(strcmp(facts[n],string) == 0) { return(1); } } /* Specific checks */ strcpy(string,object); strcat(string," DOES NOT "); strcat(string,act); strcat(string,"A "); strcat(string,text); for(n = 0; n < fact_ptr; n++) { if(strstr(facts[n],string)) { return(0); } } strcpy(string,object); strcat(string," DO NOT "); strcat(string,act); strcat(string,"AN "); strcat(string,text); for(n = 0; n < fact_ptr; n++) { if(strstr(facts[n],string)) { return(0); } } strcpy(string,object); strcat(string," DOES NOT "); strcat(string,act); strcat(string,text); for(n = 0; n < fact_ptr; n++) { if(strstr(facts[n],string)) { return(0); } } strcpy(string,object); strcat(string," DO NOT "); strcat(string,act); strcat(string,text); for(n = 0; n < fact_ptr; n++) { if(strstr(facts[n],string)) { return(0); } } strcpy(string,object); strcat(string," DOES "); strcat(string,act); strcat(string,text); for(n = 0; n < fact_ptr; n++) { if(strstr(facts[n],string)) { return(1); } } strcpy(string,object); strcat(string," DO "); strcat(string,act); strcat(string,text); for(n = 0; n < fact_ptr; n++) { if(strstr(facts[n],string)) { return(1); } } strcpy(string,object); strcat(string," DO "); strcat(string,act); strcat(string,"A "); strcat(string,text); for(n = 0; n < fact_ptr; n++) { if(strstr(facts[n],string)) { return(1); } } strcpy(string,object); strcat(string," DO "); strcat(string,act); strcat(string,"AN "); strcat(string,text); for(n = 0; n < fact_ptr; n++) { if(strstr(facts[n],string)) { return(1); } } /* There may be multiple references for the object */ /* This will check each in turn */ for(;;) { strcpy(string,object); strcat(string," IS "); for (n = 0; n < fact_ptr; n++) { if (strstr(facts[n],string) && !fflags[n]) { stp++; if (stp == 50) { printf("STACK OVERFLOW!"); exit(0); } strcpy(stk[stp],object); strcpy(this_object,text); fflags[n] = 1; known = 1; strcpy(text,facts[n]); NLP(); if (*subject) strcpy(object,subject); strcpy(text,this_object); break; } } if (!known) { strcpy(string,object); strcat(string," ARE "); for (n = 0; n < fact_ptr; n++) { if (strstr(facts[n],string) && !fflags[n]) { stp++; if (stp == 50) { printf("STACK OVERFLOW!"); exit(0); } strcpy(stk[stp],object); strcpy(this_object,text); fflags[n] = 1; known = 1; strcpy(text,facts[n]); NLP(); if (*subject) strcpy(object,subject); strcpy(text,this_object); break; } } } if (!known) { if(stp > -1) { /* Backtrack down tree to original object */ /* and try the next path */ strcpy(object,stk[stp--]); } else break; } else break; } } while(known); /* Don't know */ return(-1); } Listing 9. Frank DID sub-module. /* Frank DID() */ #include #include typedef struct { char text[240]; char object[80]; char description[80]; char action[80]; } SUBJECT; extern SUBJECT psubj; extern SUBJECT predicate; extern SUBJECT clause1; extern SUBJECT clause2; extern SUBJECT clause3; extern SUBJECT clause4; extern char text[]; extern char *facts[]; extern int fact_ptr; extern char question[80]; extern char order[80]; extern char object[80]; extern char description[80]; extern char subject[80]; extern char number[80]; extern char action[80]; extern char location[80]; extern char colour[80]; extern char size[80]; extern char who[80]; extern char tense; void NLP(void); void TOPAST(char *); void say(char *, ...); void strins(char *, char *); char *strrstr(char *, char *); void DID() { /* DID.... */ int n; char string[250]; char *p; char *q; NLP(); if (strcmp(who,"YOU") == 0 || strcmp(who,"YOU,") == 0) { /* DID YOU.... */ say("I DON'T KNOW"); return; } for(n = 0; n < fact_ptr; n++) { if(strstr(facts[n],text)) { say("I BELIEVE SO"); return; } } strcpy(string,text); p = strrstr(string,object); if (p) { strins(p,"NOT "); for(n = 0; n < fact_ptr; n++) { if(strstr(facts[n],string)) { say("I DON'T THINK SO."); return; } } strcpy(string,text); p = strrstr(string,object); strins(p,"DID "); for(n = 0; n < fact_ptr; n++) { if(strstr(facts[n],string)) { say("I THINK SO."); return; } } } /* If there is a verb, convert it to past tense and try again */ strcpy(string,text); p = strstr(string,action); if(p) { q = p; p += strlen(action); memmove(q,p,strlen(p)+1); } TOPAST(action); strins(q,action); for(n = 0; n < fact_ptr; n++) { if(strstr(facts[n],string)) { say("I BELIEVE SO"); return; } } strcpy(string,text); p = strrstr(string,object); if (p) { strins(p,"NOT "); for(n = 0; n < fact_ptr; n++) { if(strstr(facts[n],string)) { say("I DON'T THINK SO."); return; } } strcpy(string,text); p = strrstr(string,object); strins(p,"DID "); for(n = 0; n < fact_ptr; n++) { if(strstr(facts[n],string)) { say("I THINK SO."); return; } } } say("I HAVE NO IDEA!"); }
"HARRY IS A MAN"
"A MAN IS NOT MEAT"
For example. If Frank is told;
"IT IS GOOD TO EAT MEAT"
and is then asked;
"SHOULD I EAT MEAT?"
Frank will encourage the operator to "EAT MEAT", because Frank has been told that it is good to do so. Hovever, if Frank is asked;
"SHOULD I EAT HARRY?"
Frank will find that "EAT" is a good thing to do, when applied to meat. Frank does not know what "HARRY" is, and so will sit on the fence rather, and say that it depends on whether or not "HARRY" is "MEAT".
Listing 10. Frank SHOULD sub-module. /* Frank SHOULD() */ #includeThe IS() module includes the interesting function IS_OBJECT(). IS_OBJECT() is interesting because it carries out deductive reasoning. Given an object and a subject, for example "CAT" and "LIVING" it will search its knowledge to deduce whether the object is as described by the subject, or is not.#include typedef struct { char text[240]; char object[80]; char description[80]; char action[80]; } SUBJECT; extern SUBJECT psubj; extern SUBJECT predicate; extern SUBJECT clause1; 147 extern SUBJECT clause2; extern SUBJECT clause3; extern SUBJECT clause4; extern char text[]; extern char *facts[]; extern int fact_ptr; extern char question[80]; extern char order[80]; extern char object[80]; extern char description[80]; extern char subject[80]; extern char number[80]; extern char action[80]; extern char location[80]; extern char colour[80]; extern char size[80]; extern char who[80]; extern char tense; char GET_ATT(char *, char *); int IS_OBJECT(char *); void PREDPAR(void); void SHOULD_I(void); void SHOULD_I_GO(void); void NLP(void); void say(char *, ...); void strins(char *, char *); char *strrstr(char *, char *); void strsing(char *); void strlench(char *,int ); void trim(char *); void SHOULD() { /* SHOULD.... */ NLP(); if (strcmp(who,"I") == 0 || strncmp(who,"I,",2) == 0) { SHOULD_I(); return; } say("I HAVE NO IDEA!"); } void SHOULD_I() { /* SHOULD I.... */ char negative; int n; int known; char *p; char save_text[250]; memmove(text,&text[2],strlen(text)); negative = 0; if (strcmp(object,"NOT") == 0) { strcpy(object,subject); p = strstr(text,"NOT"); if (p) strlench(p,-4); negative = 1; } /*---------------------*/ /* Many possibilities! */ /*---------------------*/ if (*action == 0) { /* Parse text */ strcpy(save_text,text); PREDPAR(); strcpy(text,save_text); trim(psubj.text); } else strcpy(psubj.text,action); /* psubj.text holds the suggested 'action' */ if (strcmp(psubj.text,"GO") == 0) { SHOULD_I_GO(); return; } /* Search knowledge base for a value judgement of the action */ strcpy(save_text,"GOOD TO "); strcat(save_text,psubj.text); for(n = 0; n < fact_ptr; n++) { if (strstr(facts[n],save_text)) { p = strrstr(facts[n],save_text); if (!negative) { if (*p == 0) say("YES! %s",facts[n]); else if (strcmp(p,object) == 0) say("YES! %s",facts[n]); else { strsing(p); known = IS_OBJECT(p); if (known == 0) say("NO! %s IS NOT A %s",object,p); else if (known == 1) say("YES! %s IS A %s",object,p); else say("THAT DEPENDS ON WHETHER OR NOT %s IS A %s", object,p); } } else { if (*p == 0) say("NO! %s",facts[n]); else if (strcmp(p,object) == 0) say("NO! %s",facts[n]); else { strsing(p); known = IS_OBJECT(p); if (known == 0) say("NO! %s IS NOT A %s",object,p); else if (known == 1) say("YES! %s IS A %s",object,p); else say("THAT DEPENDS ON WHETHER OR NOT %s IS A %s", object,p); } } return; } } strcpy(save_text,"BAD TO "); strcat(save_text,psubj.text); for(n = 0; n < fact_ptr; n++) { if (strstr(facts[n],save_text)) { if (!negative) { p = strrstr(facts[n],save_text); if (*p == 0) say("NO! %s",facts[n]); else if (strcmp(p,object) == 0) say("NO! %s",facts[n]); else { strsing(p); known = IS_OBJECT(p); if (known == 0) say("YES! %s IS NOT A %s",object,p); else if (known == 1) say("NO! %s IS A %s",object,p); else say("THAT DEPENDS ON WHETHER OR NOT %s IS A %s", object,p); } } else { if (*p == 0) say("YES! %s",facts[n]); else if (strcmp(p,object) == 0) say("YES! %s",facts[n]); else { strsing(p); known = IS_OBJECT(p); if (known == 0) say("NO! %s IS NOT A %s",object,p); else if (known == 1) say("YES! %s IS A %s",object,p); else say("THAT DEPENDS ON WHETHER OR NOT %s IS A %s", object,p); } } return; } } /* No value judgement was found on the action */ /* therefore no opinion can be given */ say("I DON'T KNOW!"); return; } void SHOULD_I_GO() { /* SHOULD I GO.... */ int n; signed char yes; signed char attitude; attitude = -1; yes = -1; /* Determine the operator's attitude towards the object */ for(n = 0; n < fact_ptr; n++) { if (strstr(facts[n],object)) { yes = GET_ATT(facts[n],object); break; } } if (*subject) { /* Determine the operator's attitude towards the subject */ for(n = 0; n < fact_ptr; n++) { if (strstr(facts[n],object)) { attitude = GET_ATT(facts[n],object); break; } } } if (yes == 1 && attitude == 1) { say("YOU LIKE %s AND %s.",object,subject); return; } if (yes == 1 && attitude == -1) { say("YOU LIKE %s.",object); return; } if (yes == 1 && attitude == 0) { say("YOU LIKE %s, BUT YOU DON'T LIKE %s.",object,subject); return; } if (yes == 0 && attitude == 1) { say("YOU LIKE %s, BUT YOU DON'T LIKE %s.",subject,object); return; } if (yes == 0 && attitude == 0) { say("YOU DON'T LIKE %s OR %s.",object,subject); return; } if (yes == 0 && attitude == -1) { say("YOU DON'T LIKE %s.",object); return; } say("I HAVE NO IDEA!"); }
Given the knowledge:
"A CAT IS A CARNIVORE"
"A CARNIVORE IS AN ANIMAL"
"AN ANIMAL IS LIVING"
IS_OBJECT() will find that there is no direct correlation between "CAT" and "LIVING". It then searches for any indirect reference. This it finds in "A CAT IS A CARNIVORE". The search continues with "CAT" replaced with "CARNIVORE" until a match is made with the subject, "LIVING", or no further indirect references occur. When there are no further indirect references IS_OBJECT() back tracks down the search tree until it finds another indirect reference, and so it continues. The back tracking is achieved by the stack "STK[]". IS_OBJECT() is prevented from searching the same path more than once by the flags table fflags[].
Listing 11. Frank IS sub-module. /* Frank IS() */ #include#include #include typedef struct { char text[240]; char object[80]; char description[80]; char action[80]; } SUBJECT; extern char stk[50][40]; extern int stp; extern SUBJECT psubj; extern SUBJECT predicate; extern SUBJECT clause1; extern SUBJECT clause2; extern SUBJECT clause3; extern SUBJECT clause4; extern char text[]; extern char *facts[]; extern char fflags[]; extern int fact_ptr; extern char question[80]; extern char order[80]; extern char object[80]; extern char description[80]; extern char subject[80]; extern char number[80]; extern char action[80]; extern char location[80]; extern char colour[80]; extern char size[80]; extern char who[80]; extern char tense; int IS_OBJECT(char *); void NLP(void); void say(char *, ...); void strins(char *, char *); char *strrstr(char *, char *); void IS() { /* IS.... or ARE.... */ int n; NLP(); if (strcmp(who,"YOU") == 0 || strcmp(who,"YOU,") == 0) { /* IS/ARE YOU.... */ say("I DON'T KNOW"); return; } n = IS_OBJECT(text); if (n == 1) { say("I BELIEVE SO"); return; } if (n == 0) { say("I DON'T THINK SO."); return; } say("I HAVE NO IDEA!"); } int IS_OBJECT(char *s1) { char string[250]; char this_object[80]; char loc[80]; int n; char known; /* Reset fflags[] */ for(n = 0; n < fact_ptr; n++) fflags[n] = 0; strcpy(this_object,object); stp = -1; strcpy(text,s1); NLP(); if (*subject) strcpy(text,subject); else strcpy(text,object); strcpy(object,this_object); strcpy(loc,location); if (*loc) strcat(loc," "); do { known = 0; strcpy(string,object); strcat(string," IS NOT "); strcat(string,loc); strcat(string,"A "); strcat(string,text); for(n = 0; n < fact_ptr; n++) { if(strstr(facts[n],string)) { return(0); } } strcpy(string,object); strcat(string," IS NOT "); strcat(string,loc); strcat(string,"AN "); strcat(string,text); for(n = 0; n < fact_ptr; n++) { if(strstr(facts[n],string)) { return(0); } } strcpy(string,object); strcat(string," IS NOT "); strcat(string,loc); strcat(string,text); for(n = 0; n < fact_ptr; n++) { if(strstr(facts[n],string)) { return(0); } } strcpy(string,object); strcat(string," ARE NOT "); strcat(string,loc); strcat(string,text); for(n = 0; n < fact_ptr; n++) { if(strstr(facts[n],string)) { return(0); } } strcpy(string,object); strcat(string," IS "); strcat(string,loc); strcat(string,text); for(n = 0; n < fact_ptr; n++) { if(strstr(facts[n],string)) { return(1); } } strcpy(string,object); strcat(string," ARE "); strcat(string,loc); strcat(string,text); for(n = 0; n < fact_ptr; n++) { if(strstr(facts[n],string)) { return(1); } } strcpy(string,object); strcat(string," IS "); strcat(string,loc); strcat(string,"A "); strcat(string,text); for(n = 0; n < fact_ptr; n++) { if(strstr(facts[n],string)) { return(1); } } strcpy(string,object); strcat(string," IS "); strcat(string,loc); strcat(string,"AN "); strcat(string,text); for(n = 0; n < fact_ptr; n++) { if(strstr(facts[n],string)) { return(1); } } /* There may be multiple references for the object */ /* This will check each in turn */ for(;;) { strcpy(string,object); strcat(string," IS "); for (n = 0; n < fact_ptr; n++) { if (strstr(facts[n],string) && !fflags[n]) { stp++; if (stp == 50) { printf("STACK OVERFLOW!"); exit(0); } strcpy(stk[stp],object); strcpy(this_object,text); fflags[n] = 1; known = 1; strcpy(text,facts[n]); NLP(); if (*subject) strcpy(object,subject); strcpy(text,this_object); break; } } if (!known) { strcpy(string,object); strcat(string," ARE "); for (n = 0; n < fact_ptr; n++) { if (strstr(facts[n],string) && !fflags[n]) { stp++; if (stp == 50) { printf("STACK OVERFLOW!"); exit(0); } strcpy(stk[stp],object); strcpy(this_object,text); fflags[n] = 1; known = 1; strcpy(text,facts[n]); NLP(); if (*subject) strcpy(object,subject); strcpy(text,this_object); break; } } } if (!known) { if(stp > -1) { /* Backtrack down tree to original object */ /* and try the next path */ strcpy(object,stk[stp--]); } else break; } else break; } } while(known); /* Don't know */ return(-1); } Listing 12. Frank WILL sub-module. /* Frank WILL() */ #include #include typedef struct { char text[240]; char object[80]; char description[80]; char action[80]; } SUBJECT; extern SUBJECT psubj; extern SUBJECT predicate; extern SUBJECT clause1; extern SUBJECT clause2; extern SUBJECT clause3; extern SUBJECT clause4; extern char text[]; extern char *facts[]; extern int fact_ptr; extern char question[80]; extern char order[80]; extern char object[80]; extern char description[80]; extern char subject[80]; extern char number[80]; extern char action[80]; extern char location[80]; extern char colour[80]; extern char size[80]; extern char who[80]; extern char tense; void WILL_YOU(void); char GET_FATT(char *, char *); void NLP(void); void say(char *, ...); void strins(char *, char *); char *strrstr(char *, char *); void strlench(char *,int ); void WILL() { /* WILL.... */ int n; char string[250]; char *p; NLP(); /*--------------*/ /* WILL YOU.... */ /*--------------*/ if (strcmp(who,"YOU") == 0 || strncmp(who,"YOU,",4) == 0) { WILL_YOU(); return; } /*---------------*/ /* Other WILL....*/ /*---------------*/ strcpy(string,text); p = strrstr(string,object); strins(p,"WILL "); for(n = 0; n < fact_ptr; n++) { if(strstr(facts[n],string) || strcmp(facts[n],string) == 0) { say("YOU THINK SO"); return; } } strcpy(string,text); p = strrstr(string,object); if (p) { strins(p,"WILL NOT "); for(n = 0; n < fact_ptr; n++) { if(strstr(facts[n],string)) { say("YOU DON'T THINK SO."); return; } } } strcpy(string,text); p = strrstr(string,object); if (p) { strins(p,"WONT "); for(n = 0; n < fact_ptr; n++) { if(strstr(facts[n],string)) { say("YOU DON'T THINK SO."); return; } } } say("I HAVE NO IDEA!"); } void WILL_YOU() { /*--------------*/ /* WILL YOU.... */ /*--------------*/ say("I DON'T KNOW"); return; } Listing 13. Frank I sub-module. /* Frank I() */ #include #include static char negative; typedef struct { char text[240]; char object[80]; char description[80]; char action[80]; } SUBJECT; extern SUBJECT psubj; extern SUBJECT predicate; extern SUBJECT clause1; extern SUBJECT clause2; extern SUBJECT clause3; extern SUBJECT clause4; extern char text[]; extern char *facts[]; extern int fact_ptr; extern char question[80]; extern char order[80]; extern char object[80]; extern char description[80]; extern char subject[80]; extern char number[80]; extern char action[80]; extern char location[80]; extern char colour[80]; extern char size[80]; extern char who[80]; extern char tense; /* Function prototypes */ char GET_ATT(char *, char *); void IDO(void); void IDONT(void); void ISTATE(void); void NLP(void); void PREDPAR(void); void STATEMENT(void); void WANT(void); void WANTGO(void); void say(char *, ...); char *strftos(char *); void strins(char *, char *); void trim(char *); void I() { char save_text[250]; if (*text == 0) { say("I DON'T UNDERSTAND."); return; } /* Parse text */ strcpy(save_text,text); PREDPAR(); strcpy(text,save_text); trim(psubj.text); if (strcmp(psubj.text,"DON'T") == 0) { IDONT(); return; } if (strncmp(psubj.text,"DON'T ",6) == 0) { strcpy(predicate.text,&psubj.text[6]); psubj.text[6] = 0; IDONT(); return; } IDO(); } void IDONT() { /* I DON'T.... */ negative = 1; trim(predicate.text); if (strcmp(predicate.text,"WANT") == 0) { WANT(); return; } if (strncmp(predicate.text,"LIKE",4) == 0) { ISTATE(); return; } if (strncmp(predicate.text,"LOVE",4) == 0) { ISTATE(); return; } if (strncmp(predicate.text,"HATE",4) == 0) { ISTATE(); return; } } void IDO() { /* I DO.... */ /* The 'DO' may be implied */ negative = 0; if (strcmp(psubj.text,"WANT") == 0) { WANT(); return; } if (strncmp(psubj.text,"LIKE",4) == 0) { ISTATE(); return; } if (strncmp(psubj.text,"LOVE",4) == 0) { ISTATE(); return; } if (strncmp(psubj.text,"HATE",4) == 0) { ISTATE(); return; } } void WANT() { /* I WANT.... I DON'T WANT.... */ char string[250]; if (negative) { /* Consider clause 1 etc */ strcpy(string,clause1.text); } else strcpy(string,predicate.text); trim(string); if (strncmp(string,"TO GO ",6) == 0) { if (negative) strcpy(clause2.text,&string[6]); else strcpy(clause1.text,&string[6]); string[6] = 0; trim(string); } if (strcmp(string,"TO GO") == 0) { WANTGO(); return; } } void WANTGO() { /* I WANT TO GO.... I DON'T WANT TO GO.... */ char string[250]; char destination[80]; char found_fact; char attitude; int n; if (negative) { /* Consider clause 2 etc */ strcpy(string,clause2.text); strcpy(destination,clause2.object); } else { strcpy(string,clause1.text); strcpy(destination,clause1.object); } else say("WHY DO YOU WANT TO GO %s?",string); return; } void ISTATE() { /* I LIKE.... or I DON'T LIKE */ char temp[5]; /* Treat this as a statement */ strcpy(temp,"I "); strins(text,temp); STATEMENT(); } Listing 14. Frank YOU sub-module. /* Frank YOU() */ #include #include static char negative; typedef struct { char text[240]; char object[80]; char description[80]; char action[80]; } SUBJECT; extern SUBJECT psubj; extern SUBJECT predicate; extern SUBJECT clause1; extern SUBJECT clause2; extern SUBJECT clause3; extern SUBJECT clause4; extern char text[]; extern char *facts[]; extern int fact_ptr; extern char question[80]; extern char order[80]; extern char object[80]; extern char description[80]; extern char subject[80]; extern char number[80]; extern char action[80]; extern char location[80]; extern char colour[80]; extern char size[80]; extern char who[80]; extern char tense; /* Function prototypes */ char GET_ATT(char *, char *); void YOU_DO(void); void YOU_DONT(void); void YOU_STATE(void); void NLP(void); void PREDPAR(void); void STATEMENT(void); void YOU_SHOULD(void); void YOU_WANT(void); void YOU_WANT_GO(void); void say(char *, ...); char *strftos(char *); void strins(char *, char *); void trim(char *); void YOU() { char save_text[250]; if (*text == 0) { say("I DON'T UNDERSTAND."); return; } /* Parse text */ strcpy(save_text,text); PREDPAR(); strcpy(text,save_text); trim(psubj.text); if (strcmp(psubj.text,"DON'T") == 0) { YOU_DONT(); return; } if (strncmp(psubj.text,"DON'T ",6) == 0) { strcpy(predicate.text,&psubj.text[6]); psubj.text[6] = 0; YOU_DONT(); return; } YOU_DO(); } void YOU_DONT() { /* YOU DON'T.... */ negative = 1; trim(predicate.text); if (strcmp(predicate.text,"WANT") == 0) { YOU_WANT(); return; } if (strncmp(predicate.text,"LIKE",4) == 0) { YOU_STATE(); return; } if (strncmp(predicate.text,"LOVE",4) == 0) { YOU_STATE(); return; } if (strncmp(predicate.text,"HATE",4) == 0) { YOU_STATE(); return; } } void YOU_DO() { /* YOU DO.... */ /* The 'DO' may be implied */ negative = 0; if (strcmp(psubj.text,"WANT") == 0) { YOU_WANT(); return; } if (strncmp(psubj.text,"SHOULD ",7) == 0) { memmove(psubj.text,&psubj.text[7],strlen(psubj.text)); YOU_SHOULD(); return; } if (strncmp(psubj.text,"LIKE",4) == 0) { YOU_STATE(); return; } if (strncmp(psubj.text,"LOVE",4) == 0) { YOU_STATE(); return; } if (strncmp(psubj.text,"HATE",4) == 0) { YOU_STATE(); return; } } void YOU_WANT() { /* YOU WANT.... YOU DON'T WANT.... */ char string[250]; if (negative) { /* Consider clause 1 etc */ strcpy(string,clause1.text); } else strcpy(string,predicate.text); trim(string); if (strncmp(string,"TO GO ",6) == 0) { if (negative) strcpy(clause2.text,&string[6]); else strcpy(clause1.text,&string[6]); string[6] = 0; trim(string); } if (strcmp(string,"TO GO") == 0) { YOU_WANT_GO(); return; } } void YOU_SHOULD() { /* YOU SHOULD.... YOU SHOULD NOT.... */ if (strcmp(psubj.text,"GO TO") == 0) { YOU_WANT_GO(); return; } if (strcmp(psubj.text,"NOT") == 0) { negative = 1; if (strcmp(predicate.text,"GO ") == 0) { strins(clause1.text,"GO "); strcpy(clause2.text,clause1.text); strcpy(clause2.object,clause1.object); YOU_WANT_GO(); } } } void YOU_WANT_GO() { /* YOU WANT TO GO.... YOU DON'T WANT TO GO.... */ char string[250]; char destination[80]; char found_fact; char attitude; int n; if (negative) { /* Consider clause 2 etc */ strcpy(string,clause2.text); strcpy(destination,clause2.object); } else { strcpy(string,clause1.text); strcpy(destination,clause1.object); } trim(string); if (*string == 0) { /* No destination specified */ say("WHAT MAKES YOU THINK I'VE GOT TO GO?"); return; } /* The operator has stated that FRANK do/donot want to go to */ /* a destination */ /* Frank should check the facts table to determine a possible reason */ /* for the operators desire to go to the specified destination */ found_fact = 0; for(n = 0; n < fact_ptr; n++) { if (strstr(facts[n],destination)) { found_fact = 1; break; } } if(found_fact) { /* Determine the operators attitude towards the destination */ attitude = GET_ATT(facts[n],destination); strcpy(string,facts[n]); strftos(string); /* Check for paradoxs */ /* EG: I don't like chelsea */ /* You want to go to chelsea */ if (attitude != negative) say("BECAUSE %s?",string); else say("BUT YOU SAID %s!",string); return; } if (negative) say("WHAT MAKES YOU THINK I AM ARE GOING %s?",string); else say("WHY DO YOU THINK I SHOULD GO %s?",string); return; } void YOU_STATE() { /* YOU LIKE.... or YOU DON'T LIKE */ char temp[5]; /* Treat this as a statement */ strcpy(temp,"YOU "); strins(text,temp); STATEMENT(); } Listing 15. Frank other statements sub-module. /* Frank STATEMENT() */ #include #include extern char text[]; extern char *facts[]; extern int fact_ptr; extern char question[80]; extern char order[80]; extern char object[80]; extern char description[80]; extern char subject[80]; extern char number[80]; extern char action[80]; extern char location[80]; extern char colour[80]; extern char size[80]; extern char who[80]; extern char tense; /* Function prototypes */ void NLP(void); void say(char *); void STATEMENT() { /* The operator has made a statement */ /* record it for posperity */ if (fact_ptr < 2000) { facts[fact_ptr] = malloc(strlen(text)+1); if (facts[fact_ptr]) { strcpy(facts[fact_ptr],text); fact_ptr++; } } say("If you say so."); } Listing 16. Frank parser module. /*---------------*/ /* Include files */ /*---------------*/ #include #include #include #include /*-----------*/ /* Constants */ /*-----------*/ #define num_a 141 #define num_p 12 #define num_q 41 #define num_l 20 #define num_n 37 #define num_c 14 #define num_f 17 #define num_qs 19 #define num_s 9 #define num_o 3 /*-----------*/ /* Lexicons */ /*-----------*/ static char *actions[num_a] = { "LIKE" , "DISLIKE", "LOVE" , "HATE" , "SLEEP" , "PUMP", "MAKE" , "WEAR" , "RENOUNCE" , "SHORTEN", "KEEP", "FEED", "DESCEND" , "CONVERT", "KEEP", "OPEN" , "EAT" , "READ" , "DRY" , "KILL" , "MEND", "CAUSE", "SIT" , "SAT" , "CLOSE", "TAKE", "RUN" , "JUMP", "SKIP", "HOP", "BREAK", "INVENT", "DISCOVER", "EXPLORE", "PUNCH","KICK", "IGNITE", "CHAT", "WRITE", "TALK","LISTEN", "WHISTLE","SHOUT","SCREAM","DRINK","BATHE", "WASH", "FLY" , "SWIM", "CROSS", "ENTER", "CLIMB", "TIE", "CROUCH", "CRAWL", "BREATHE", "SNIFF", "SPIT" ,"GO","PUT","DRINK", "LOOK", "TURN", "BORN","LEAVE", "SMOKE", "LIGHT", "DESIGN" , "DRAW" ,"PAINT", "BOIL", "STRAIN", "POUR","TELEPHONE","PHONE", "CALL" ,"DRESS", "CUT", "SAW", "GONE","STUDY", "FOLD" , "PLAY", "PAY", "EARN","MEET", "MET", "LIVE","DWELL", "BEEN", "HEAR" , "HEARD", "SING" , "SUNG", "DEVELOP", "STIR","SEE", "SEEN", "RING", "FEEL" , "FELT", "DIED", "HUNT", "ASK", "STAY" ,"KISS", "CUDDLE", "GIVE","BUY", "BOUGHT", "LICK" , "TASTE", "ADMIRE" , "PROVIDE", "COME", "BUILD", "BUILT", "REFERENCE" ,"WENT", "CONSTRUCT" ,"LEAN","WALK","CARRY","RIDE", "ORBIT", "DRIVE" , "DROVE" , "DOWN", "ALONG", "SHALL", "SHOULD" , "THINK", "THOUGHT","GOT","GET", "LEND", "LENT","HAVE", "HAS" , "HAD","SUGGEST" }; static char *questions[num_qs] = { "WHAT", "WHEN", "HOW", "WHY", "WHERE", "WHO","DO", "DOES" ,"ARE", "IS", "WAS", "CAN" ,"AM" ,"WHICH","HAVE" , "WILL" , "DID" , "HAS", "SHOULD"}; static char *orders[num_o] = { "USE" , "TELL", "QUIT" }; static char *fillers[num_f] = { "IS", "THE" , "A", "AN" , "ARE" ,"TOO","ALSO", "OF" , "COME" , "FROM" , "ITS" , "THEIR" , "THAT" , "ABOUT", "THING" , "THIS" , "BECAUSE" }; static char *qualifiers[num_q] = {"FAST", "SLOW", "ROUND", "SQUARE", "HAIRY", "BALD", "FRIGHTENING","INTERESTED", "SHY", "NICE", "HORRIBLE" , "LOVELY","INTERESTING", "PRETTY" , "BEAUTIFUL" , "BLONDE" , "BRUNETTE" , "SEXY" , "SHINY" , "DULL" , "BORING" , "CAREFUL" , "HARD" , "SOFT" , "GENTLE" , "QUICK" , "LIGHT", "HEAVY", "RADIOACTIVE", "METALLIC","TIRED", "GASEOUS", "BRIGHT", "SWEET", "SOUR" , "BITTER", "GOOD","BAD","DRUNK","STUPID","MUTUAL" }; static char *sizes[num_s] = {"BIG", "SMALL", "FAT", "THIN", "TALL" ,"SHORT", "LARGE", "PETITE", "TINY" }; static char *colours[num_c] = { "BLACK", "BLUE", "RED", "YELLOW", "ORANGE", "GREEN","BROWN" , "GINGER" , "PURPLE", "MAUVE", "SILVERY", "SILVER", "GOLD", "CYAN" }; static char *numbers[num_n] = { "ALL" , "SOME" , "FEW" , "MANY" , "MOST" , "COUPLE","NEXT","PREVIOUS","ONE", "TWO", "THREE" , "FOUR", "EVERY", "LAST", "FIVE", "SIX", "SEVEN","EIGHT", "NINE", "TEN", "ELEVEN","TWELVE", "THIRTEEN","FOURTEEN", "FIFTEEN", "SIXTEEN", "SEVENTEEN", "EIGHTEEN", "NINETEEN","TWENTY", "THIRTY", "FOURTY", "FIFTY", "SIXTY","SEVENTY", "EIGHTY", "NINETY" }; static char *pronouns[num_p] = { "THEM", "THEY", "WE", "HIM", "HER" ,"US" , "HE", "I", "YOU" ,"MY", "YOUR" , "ME"}; static char *locations[num_l] = { "IN" , "ON", "BESIDE" , "EAST" , "WEST" , "NORTH" ,"SOUTH" , "UNDER" , "UP" , "DOWN", "BELOW", "ABOVE", "RIGHT", "LEFT", "OVER","INTO","AROUND" , "TO", "OFF", "THERE" }; /*------------*/ /* Work areas */ /*------------*/ char last_subject[80]; char last_object[80]; /* Global variables */ typedef struct { char text[240]; char object[80]; char description[80]; char action[80]; } SUBJECT; extern char text[]; extern char question[80]; extern char order[80]; extern char object[80]; extern char description[80]; extern char subject[80]; extern char number[80]; extern char action[80]; extern char location[80]; extern char colour[80]; extern char size[80]; extern char who[80]; extern char tense; extern SUBJECT psubj; extern SUBJECT predicate; extern SUBJECT clause1; extern SUBJECT clause2; extern SUBJECT clause3; extern SUBJECT clause4; /*---------------------*/ /* Function prototypes */ /*---------------------*/ int IS_COLOUR(char *); int IS_FILLER(char *); int IS_LOCATION(char *); int IS_NUMBER(char *); int IS_PRONOUN(char *); int IS_SIZE(char *); int IS_VERB(char *); void strchg(char *, char *, char *); void truncstr(char *,int ); /*--------------------*/ /* Start of functions */ /*--------------------*/ static void GET_QUESTION(char *text, char *question) { /* Extract a question from the phrase string */ char *p; char first_word[40]; char save; int n; int more; strcpy(question,""); do { more = 0; p = strpbrk(text," ,.;:?!"); save = *p; *p = 0; strcpy(first_word,text); *p = save; for(n = 0; n < num_qs; n++) { if (stricmp(first_word,questions[n]) == 0) { /* store question */ if (*question) strcat(question," "); strcat(question,first_word); /* remove question from text */ if (p) { while(strchr(" ,.:;?!",*p) && *p) p++; if (*p) memmove(text,p,strlen(p) + 1); } else *text = 0; more = 1; } } } while(more); } static void GET_ORDER(char *text, char *order) { /* Extract an order from the phrase string */ char *p; char first_word[40]; char save; int n; strcpy(order,""); p = strpbrk(text," ,.;:?!"); save = *p; *p = 0; strcpy(first_word,text); *p = save; for(n = 0; n < num_o; n++) { if (stricmp(first_word,orders[n]) == 0) { /* store order */ strcpy(order,first_word); /* remove order from text */ while(strchr(" ,.:;?!",*p)) p++; memmove(text,p,strlen(p) + 1); return; } } } static void GET_OBJECT(char *text, char *object, char *action) { /* Obtain object from phrase string */ char *p; int n; int ignore; char temp[30]; char copy[250]; strcpy(copy,text); p = strtok(text," ,.;:?!"); while(p) { ignore = 0; if (stricmp(p,action) == 0) ignore = 1; if (!ignore) ignore = IS_FILLER(p); if (!ignore) ignore = IS_NUMBER(p); if (!ignore) ignore = IS_COLOUR(p); if (!ignore) ignore = IS_SIZE(p); if (!ignore) ignore = IS_LOCATION(p); if (!ignore) ignore = IS_PRONOUN(p); if (!ignore) { for (n = 0; n < num_q; n++) { if (stricmp(p,qualifiers[n]) == 0) ignore = 1; else { strcpy(temp,qualifiers[n]); if (temp[strlen(temp) - 1] == 'E') { temp[strlen(temp) - 1] = 0; if (temp[strlen(temp) - 1] == 'L') temp[strlen(temp) - 1] = 0; } strcat(temp,"LY"); if (stricmp(p,temp) == 0) { ignore = 1; break; } } } } if (!ignore) { for(n = 0; n < num_qs; n++) { if (stricmp(p,questions[n]) == 0) { ignore = 1; break; } } } if (!ignore) { if (stricmp(p,"IT") == 0) strcpy(object,last_object); else strcpy(object,p); strcpy(text,copy); p = strstr(text,object); strcpy(last_object,""); if (p) { /* Capture preceeding preposition */ p--; while(*p == 32) p--; while(*p != 32 && p >= text) p--; if (*p == 32) p++; if (strncmp("THE ",p,4) == 0) strcpy(last_object,"THE "); else if (strncmp("the ",p,4) == 0) strcpy(last_object,"the "); } strcat(last_object,object); return; } p = strtok(NULL," ,.;:?!"); } strcpy(text,copy); strcpy(object,""); } static void GET_SUBJECT(char *text, char *subject, char *object, char *action) { /* Obtain subject from phrase string */ char *p; int ignore; char copy[250]; strcpy(copy,text); strcpy(last_subject,subject); strcpy(subject,""); /* Restrict phrase to that part following the object */ p = strstr(text,object); if (p == NULL) p = strstr(text,"IT "); memmove(text,p,strlen(p) + 1); p = strtok(text," ,.;:?!"); while(p) { ignore = 0; if (stricmp(p,object) == 0) ignore = 1; if (!ignore) ignore = IS_FILLER(p); if (!ignore) ignore = IS_LOCATION(p); if (!ignore) ignore = IS_PRONOUN(p); if (!ignore) ignore = IS_COLOUR(p); if (!ignore) ignore = IS_SIZE(p); if (!ignore) ignore = IS_NUMBER(p); if (stricmp(p,action) == 0) ignore = 1; if (!ignore) { if (stricmp(p,"IT")) { if (*subject) strcat(subject," "); strcat(subject,p); } } p = strtok(NULL," ,.;:?!"); } strcpy(text,copy); } static void GET_OBJECT_QUALIFY(char *text, char *object_qualify, char *subject) { /* Obtain qualifying statements from phrase string */ char *p; int n; int ignore; char oq[78]; char copy[250]; char temp[30]; strcpy(copy,text); strcpy(object_qualify,""); p = strtok(text," ,.;:?!"); while(p) { for(n = 0; n < num_q; n++) { if (stricmp(p,qualifiers[n]) == 0) { if (*object_qualify) strcat(object_qualify,","); strcat(object_qualify,p); break; } else { strcpy(temp,qualifiers[n]); if (temp[strlen(temp) - 1] == 'E') { temp[strlen(temp) - 1] = 0; if (temp[strlen(temp) - 1] == 'L') temp[strlen(temp) - 1] = 0; } strcat(temp,"LY"); if (stricmp(p,temp) == 0) { if (*object_qualify) strcat(object_qualify,","); strcat(object_qualify,p); break; } } } p = strtok(NULL," ,.;:?!"); } strcpy(text,copy); ignore = 0; strcpy(oq,object_qualify); p = strtok(object_qualify,","); while(p) { if (stricmp(p,subject) == 0) { ignore = 1; break; } p = strtok(NULL,","); } strcpy(object_qualify,oq); if (!ignore) for (n = 0; n < num_q; n++) { if (stricmp(subject,qualifiers[n]) == 0) { if (*object_qualify) strcat(object_qualify,","); strcat(object_qualify,subject); strcpy(subject,""); break; } } } static void GET_NUMBER(char *text, char *number) { /* Obtain number words from phrase string */ char *p; char copy[250]; int n; strcpy(copy,text); strcpy(number,""); p = strtok(text," ,.;:?!"); while(p) { for(n = 0; n < num_n; n++) { if (stricmp(p,numbers[n]) == 0) { if (*number) strcat(number,","); strcat(number,p); break; } } p = strtok(NULL," ,.;:?!"); } strcpy(text,copy); } static void GET_WHO(char *text, char *who) { /* Obtain first or second person references from phrase string */ char *p; char copy[250]; int n; strcpy(copy,text); strcpy(who,""); p = strtok(text," ,.;:?!"); while(p) { for(n = 0; n < num_p; n++) { if (stricmp(p,pronouns[n]) == 0) { if (*who) strcat(who,","); strcat(who,p); break; } } p = strtok(NULL," ,.;:?!"); } strcpy(text,copy); } static void GET_COLOUR(char *text, char *colour) { /* Obtain colour words from the phrase string */ char *p; char copy[250]; int n; strcpy(copy,text); strcpy(colour,""); p = strtok(text," ,.;:?!"); while(p) { for(n = 0; n < num_c; n++) { if (stricmp(p,colours[n]) == 0) { if (*colour) strcat(colour,","); strcat(colour,p); break; } } p = strtok(NULL," ,.;:?!"); } strcpy(text,copy); } static void GET_SIZE(char *text, char *size) { /* Obtain size description words from the phrase string */ char *p; char copy[250]; int n; strcpy(copy,text); strcpy(size,""); p = strtok(text," ,.;:?!"); while(p) { for(n = 0; n < num_s; n++) { if (stricmp(p,sizes[n]) == 0) { if (*size) strcat(size,","); strcat(size,p); break; } } p = strtok(NULL," ,.;:?!"); } strcpy(text,copy); } static void GET_LOCATION(char *text, char *location) { /* Obtain location description words from the phrase string */ char *p; char copy[250]; int n; strcpy(copy,text); strcpy(location,""); p = strtok(text," ,.;:?!"); while(p) { for(n = 0; n < num_l; n++) { if (stricmp(p,locations[n]) == 0) { if (*location) strcat(location,","); strcat(location,p); break; } } p = strtok(NULL," ,.;:?!"); } strcpy(text,copy); } static void GET_ACTION(char *text , char *action) { /* Obtain action words from the phrase string */ char *p; char n; char word[50]; char pre[50]; char copy[250]; strcpy(copy,text); strcpy(action,""); strcpy(pre,""); p = strtok(text," ,.;:?!"); while(p) { for(n = 0; n < num_a; n++) { strcpy(word,actions[n]); if (stricmp(p,word) == 0) { if (stricmp(pre,"THE")) { if (*action) strcat(action,","); strcat(action,p); } break; } else { /* Past tense */ if (word[strlen(word) - 1] == 'E') strcat(word,"D"); else if (word[strlen(word) - 1] == 'Y') { /* Irregular words! */ if (stricmp(word,"PAY") == 0) strcpy(word,"PAID"); else if (stricmp(word,"PLAY") == 0) strcpy(word,"PLAYED"); else { word[strlen(word) - 1] = 0; strcat(word,"IED"); } } else strcat(word,"ED"); if (stricmp(p,word) == 0) { if (*action) strcat(action,","); strcat(action,p); break; } else { /* Plural */ strcpy(word,actions[n]); strcat(word,"S"); if (stricmp(p,word) == 0) { if (stricmp(pre,"THE")) { if (*action) strcat(action,","); strcat(action,p); break; } } else { /* Active */ strcpy(word,actions[n]); strcat(word,"ING"); if (stricmp(p,word) == 0) { if (stricmp(pre,"THE")) { if (*action) strcat(action,","); strcat(action,p); break; } } } } } } strcpy(pre,p); p = strtok(NULL," ,.;:?!"); } strcpy(text,copy); } static int IS_FILLER(char *p) { /* Return 1 if the word is a filler word */ char n; for(n = 0; n < num_f; n++) { if (stricmp(p,fillers[n]) == 0) return(1); } return(0); } static int IS_NUMBER(char *p) { /* Return 1 if the word is a number */ int n; for(n = 0; n < num_n; n++) { if (stricmp(p,numbers[n]) == 0) return(1); } return(0); } static int IS_COLOUR(char *p) { /* Return 1 if the word is a colour */ char n; for(n = 0; n < num_c; n++) { if (stricmp(p,colours[n]) == 0) return(1); } return(0); } static int IS_SIZE(char *p) { /* Return 1 if the word is a size description word */ char n; for(n = 0; n < num_s; n++) { if (stricmp(p,sizes[n]) == 0) return(1); } return(0); } static int IS_LOCATION(char *p) { /* Return 1 if the word is a location description */ char n; for(n = 0; n < num_l; n++) { if (stricmp(p,locations[n]) == 0) return(1); } return(0); } static int IS_PRONOUN(char *p) { /* Return 1 if the word is a first or second person reference */ char n; for(n = 0; n < num_p; n++) { if (stricmp(p,pronouns[n]) == 0) return(1); } return(0); } void NLP() { /* Parses a simple phrase and returns the component parts */ char *p; char *q; GET_QUESTION(text, question); GET_ACTION(text , action); GET_ORDER(text,order); GET_OBJECT(text,object,action); GET_SUBJECT(text, subject, object, action); GET_WHO(text,who); GET_OBJECT_QUALIFY(text, description, subject); GET_COLOUR(text,colour); GET_SIZE(text,size); GET_NUMBER(text , number); GET_LOCATION(text,location); if (strstr(question,"WAS")) tense = 1; else if (strstr(question,"IS")) tense = 2; else if (strstr(question,"DO")) tense = 2; else if (strstr(question,"IS")) tense = 2; else if (strstr(question,"DID")) tense = 1; else if (strstr(text,"GOT ")) tense = 2; else if (strstr(question,"WILL")) tense = 3; else tense = 0; if (tense == 0) { /* Perhaps action gives a clue */ if (*action) { if (strchr(action,',') == NULL) { p = &action[strlen(action) - 2]; if (stricmp(p,"ED") == 0) tense = 1; } else { q = action; do { p = strchr(q,','); q = p - 1; if (*q == 'S') { tense = 2; break; } q--; if (stricmp(q,"ED") == 0) { tense = 1; break; } q = p + 1; } while(p); } } } } /* --------------------------------------------------------- */ /* Toolbox functions for working with conversational strings */ /* --------------------------------------------------------- */ void truncstr(char *p,int num) { /* Truncate string by losing last num characters */ if (num < strlen(p)) p[strlen(p) - num] = 0; } void trim(char *text) { /* remove trailing spaces */ char *p; p = &text[strlen(text) - 1]; while(*p == 32 && p >= text) *p-- = 0; } void strlench(char *p,int num) { /* Change length of string by adding or deleting characters */ if (num > 0) memmove(p + num,p,strlen(p) + 1); else { num = 0 - num; memmove(p,p + num,strlen(p) + 1); } } void strins(char *p, char *q) { /* Insert string q into p */ strlench(p,strlen(q)); strncpy(p,q,strlen(q)); } void strchg(char *data, char *s1, char *s2) { /* Replace all occurences of s1 with s2 */ char *p; char changed; do { changed = 0; p = strstr(data,s1); if (p) { /* Delete original string */ strlench(p,0 - strlen(s1)); /* Insert replacement string */ strins(p,s2); changed = 1; } } while(changed); } char *strftos(char *data) { /* convert first person to second person */ /* I ---------> YOU */ /* ME --------> YOU */ /* I AM ------> YOU ARE */ /* YOUR ------> MY */ /* MY --------> YOUR */ /* YOU ARE ---> I AM */ /* YOU -------> I */ /* I WAS -----> YOU WERE */ /* YOU WERE --> I WAS */ char *copy; char *p; char *q; char *r; strcat(data," "); /* Allocate space for a copy of the string */ copy = malloc(strlen(data) * 2); if (copy == NULL) return NULL; strcpy(copy,""); /* Check first phrase */ p = data; do { if (strncmp(p,"I AM",4) == 0) { q = &p[4]; if (ispunct(*q) || *q == 0 || *q == 32) { strcat(copy,"YOU ARE "); copy[strlen(copy) - 1] = *q; } p += 5; } else if (strncmp(p,"I am",4) == 0) { q = &p[4]; if (ispunct(*q) || *q == 0 || *q == 32) { if (p == data) strcat(copy,"You are "); else { p--; if (*p == '.') strcat(copy,"You are "); else strcat(copy,"you are "); p++; } copy[strlen(copy) - 1] = *q; p += 5; } } else if (strncmp(p,"I WAS ",6) == 0) { strcat(copy,"YOU WERE "); p += 6; } else if (strncmp(p,"I was ",6) == 0) { if (p == data) strcat(copy,"You were "); else { p--; if (*p == '.') strcat(copy,"You were "); else strcat(copy,"you were "); p++; } p += 6; } else if (strncmp(p,"YOU ARE",7) == 0) { q = &p[7]; if (ispunct(*q) || *q == 0 || *q == 32) { strcat(copy,"I AM "); copy[strlen(copy) - 1] = *q; p += 8; } } else if (strncmp(p,"You are",7) == 0) { q = &p[7]; if (ispunct(*q) || *q == 0 || *q == 32) { strcat(copy,"I am "); copy[strlen(copy) - 1] = *q; p += 8; } } else if (strncmp(p,"you are",7) == 0) { q = &p[7]; if (ispunct(*q) || *q == 0 || *q == 32) { strcat(copy,"I am "); copy[strlen(copy) - 1] = *q; p += 8; } } else if (strncmp(p,"YOU WERE ",9) == 0) { strcat(copy,"I WAS "); p += 9; } else if (strncmp(p,"You were ",9) == 0) { strcat(copy,"I was "); p += 9; } else if (strncmp(p,"you were ",9) == 0) { strcat(copy,"I was "); p += 9; } else if (strncmp(p,"I ",2) == 0) { /* Is the next word uppercase ? */ if (p == data) { q = p; q++; while(*q == 32) q++; if(islower(*q)) strcat(copy,"You "); else strcat(copy,"YOU "); } else { q = p; q++; while(*q == 32) q++; if(islower(*q)) strcat(copy,"you "); else strcat(copy,"YOU "); } p += 2; } else if (strncmp(p,"YOU",3) == 0) { r = &p[3]; if (ispunct(*r) || *r == 0 || *r == 32) { if (p == data) strcat(copy,"I "); else { q = p; while(*q != '.' && q >= data) { q--; if (*q != 32) break; } if (q == data || *q == '.') strcat(copy,"I "); else strcat(copy,"ME "); } copy[strlen(copy) - 1] = *r; p += 4; } } else if (strncmp(p,"You",3) == 0) { r = &p[3]; if (ispunct(*r) || *r == 0 || *r == 32) { strcat(copy,"I "); p += 4; copy[strlen(copy) -1] = *r; } } else if (strncmp(p,"you",3) == 0) { r = &p[3]; if (ispunct(*r) || *r == 0 || *r == 32) { strcat(copy,"me "); p += 4; copy[strlen(copy) -1] = *r; } } else if (strncmp(p,"ME ",3) == 0) { strcat(copy,"YOU "); p += 3; } else if (strncmp(p,"Me ",3) == 0) { strcat(copy,"You "); p += 3; } else if (strncmp(p,"me ",2) == 0) { strcat(copy,"you "); p += 3; } else if (strncmp(p,"YOUR ",5) == 0) { strcat(copy,"MY "); p += 5; } else if (strncmp(p,"Your ",5) == 0) { strcat(copy,"My "); p += 5; } else if (strncmp(p,"your ",5) == 0) { strcat(copy,"my "); p += 5; } else if (strncmp(p,"MY ",3) == 0) { strcat(copy,"YOUR "); p += 3; } else if (strncmp(p,"My ",3) == 0) { strcat(copy,"Your "); p += 3; } else if (strncmp(p,"my ",3) == 0) { strcat(copy,"your "); p += 3; } else if (strncmp(p,"ME.",3) == 0) { strcat(copy,"YOU."); p += 3; } else if (strncmp(p,"Me.",3) == 0) { strcat(copy,"You."); p += 3; } else if (strncmp(p,"me.",2) == 0) { strcat(copy,"you."); p += 3; } else if (strncmp(p,"YOU.",4) == 0) { strcat(copy,"ME."); p += 4; } else if (strncmp(p,"You.",4) == 0) { strcat(copy,"Me."); p += 4; } else if (strncmp(p,"you.",4) == 0) { strcat(copy,"me."); p += 4; } q = ©[strlen(copy)]; /* Step to next word */ while(*p && *p != 32) *q++ = *p++; while(strchr(" ,.:;?!",*p) && *p) *q++ = *p++; *q = 0; } while(*p); /* Remove trailing space */ truncstr(copy,1); p = strrchr(copy,32); if (p) { p++; if (stricmp(p,"I") == 0) { truncstr(copy,1); if (isupper(copy[2])) strcat(copy,"ME"); else strcat(copy,"me"); } } /* Transfer copy to data */ strcpy(data,copy); /* Free memory */ free(copy); return data; } void strcor(char *data) { /* Correct common gramatical errors */ char *p; p = strstr(data,"WHY YOU DO NOT"); if (p) strncpy(p,"WHY DO YOU NOT ",14); p = strstr(data,"WHY ME DO NOT"); if (p) { strlench(p,-1); strncpy(p,"WHY DO I NOT ",13); } } void strwhy(char *data) { /* Change data into a question */ char *p; p = data; strins(data,"WHY "); strcor(data); /* Remove any text following the first part of the string */ p = strpbrk(data,",.:;!"); if (p) *p = 0; p = data; while(*p && *p != '.' && *p != '!') p++; if (*p) *p = '?'; else strins(p,"? "); } char *strrstr(char *s1, char *s2) { /* find occurence of s2 in s1, and point to first word after it */ char *p; p = strstr(s1,s2); if (p) { p += strlen(s2); while(*p == 32) p++; } return(p); } void strsing(char *word) { char *p; /* Convert plurals to singular */ if (strcmp(word,"GAS") == 0) return; if (strcmp(word,"GASSES") == 0) { strcpy(word,"GAS"); return; } if (word[strlen(word) - 1] == 'S' && word[strlen(word) - 2] != 'S') { word[strlen(word) - 1] = 0; /* Words ending IES, convert to Y in the singular */ p = &word[strlen(word) - 2]; if (strcmp(p,"IE") == 0) strcpy(p,"Y"); else /* Words ending OUS are NOT plurals! */ if (strcmp(p,"OU") == 0) strcat(word,"S"); else { /* Words ending MEN are MAN in the singular */ p--; if (strcmp(p,"MEN") == 0) strcpy(p,"MAN"); } } } /* PREDICATE CLAUSE ANALYSIS */ /*--------------------*/ /* Start of functions */ /*--------------------*/ static void GET_POBJECT(char *text, char *object) { /* Copy NOUN into object */ char *p; int n; int ignore; char temp[30]; char copy[250]; char previous[50]; strcpy(copy,text); strcpy(object,""); strcpy(previous,""); p = strtok(text," ,.;:?!"); while(p) { ignore = IS_LOCATION(p); if (!ignore) ignore = IS_FILLER(p); if (!ignore) { for (n = 0; n < num_q; n++) { if (stricmp(p,qualifiers[n]) == 0) ignore = 1; else { strcpy(temp,qualifiers[n]); if (temp[strlen(temp) - 1] == 'E') { temp[strlen(temp) - 1] = 0; if (temp[strlen(temp) - 1] == 'L') temp[strlen(temp) - 1] = 0; } strcat(temp,"LY"); if (stricmp(p,temp) == 0) { ignore = 1; break; } } } } if (!ignore) { for(n = 0; n < num_qs; n++) { if (stricmp(p,questions[n]) == 0) { ignore = 1; break; } } /* We must also ignore words such as "CAN" and "MAY" and "DO" */ if (stricmp(p,questions[n]) == 0) { ignore = 1; break; } } if (!ignore) { /* We must also ignore words such as "CAN" and "MAY" and "DO" */ if (stricmp(p,"CAN") == 0 || stricmp(p,"WILL") == 0 || stricmp(p,"MAY") == 0 || stricmp(p,"DO") == 0 || stricmp(p,"SHALL") == 0 || stricmp(p,"SHOULD") == 0) ignore = 1; } if (!ignore) if (IS_VERB(p)) ignore = 1; if (stricmp(p,"OF") == 0) { if (*object) strcat(object," "); strcat(object,"OF"); strcat(object,previous); strcpy(previous,""); } else if(!ignore) { if (*object) strcat(object," "); strcat(object,p); } if (ignore && stricmp(p,"OF") != 0) strcpy(previous,p); else strcpy(previous,""); p = strtok(NULL," ,.;:?!"); } strcpy(text,copy); } static void GET_DESCRIPTION(char *text, char *object_qualify) { /* Obtain qualifying statements from phrase string */ char *p; int n; char copy[250]; char temp[50]; char previous[50]; strcpy(copy,text); strcpy(object_qualify,""); strcpy(previous,""); p = strtok(text," ,.;:?!"); while(p) { for(n = 0; n < num_q; n++) { if (stricmp(p,qualifiers[n]) == 0) { if (*object_qualify) strcat(object_qualify," "); strcat(object_qualify,p); break; } else { strcpy(temp,qualifiers[n]); if (temp[strlen(temp) - 1] == 'E') { temp[strlen(temp) - 1] = 0; if (temp[strlen(temp) - 1] == 'L') temp[strlen(temp) - 1] = 0; } strcat(temp,"LY"); if (stricmp(p,temp) == 0) { if (*object_qualify) strcat(object_qualify," "); strcat(object_qualify,p); break; } } } if (stricmp(previous,"THE") == 0 || stricmp(previous,"A") == 0 || stricmp(previous,"AN") == 0 || stricmp(previous,"OF") == 0) { if (IS_VERB(p)) { if (*object_qualify) strcat(object_qualify," "); strcat(object_qualify,p); } } strcpy(previous,p); p = strtok(NULL," ,.;:?!"); } strcpy(text,copy); } static int IS_DESCRIPTION(char *p) { int n; for(n = 0; n < num_q; n++) { if (stricmp(p,qualifiers[n]) == 0) return 1; } return 0; } void GET_PREDICATE(char *data,char *predicate,char *psubj) { /* Splits a sentence into its two parts */ char *p; char *q; char word[40]; char save; char previous[40]; strcpy(predicate,data); strcpy(psubj,""); p = data; q = p; do { p = strpbrk(p," .,;:?!"); if (p) { save = *p; *p = 0; strcpy(word,q); *p = save; p++; if (stricmp(word,"IT") == 0) { save = *p; *p = 0; strcpy(predicate,data); *p = save; strcpy(psubj,p); return; } if (stricmp(word,"ARE") == 0 && q != data) { save = *q; *q = 0; strcpy(predicate,data); strcpy(predicate,data); *q = save; strcpy(psubj,q); return; } if (stricmp(word,"MOST") == 0) { save = *p; *p = 0; strcpy(predicate,data); *p = save; strcpy(psubj,p); return; } if ((stricmp(word,"IS") == 0 || stricmp(word,"CAN") == 0 || stricmp(word,"WILL") == 0 || stricmp(word,"MAY") == 0 || stricmp(word,"THAT") == 0 || stricmp(word,"WAS") == 0 || stricmp(word,"DID") == 0 || stricmp(word,"SHALL") == 0 || stricmp(word,"SHOULD") == 0 || stricmp(word,"DO") == 0) && q == data) { /* Situations such as IS A LION A CAT? */ /* Skip the next word */ p = strpbrk(p," .,;:?!"); if (p) { while(*p == 32) p++; q = p; do { p = strpbrk(p," .,;:?!"); if (p) { save = *p; *p = 0; strcpy(word,q); /* Is this word a filler? */ if(IS_FILLER(word) || IS_VERB(word)) { *p = save; save = *q; *q = 0; strcpy(predicate,data); *q = save; strcpy(psubj,q); return; } *p = save; while(*p == 32) p++; q = p; } } while(p); } } if (stricmp(word,"IS") == 0 || stricmp(word,"CAN") == 0 || stricmp(word,"WILL") == 0 || stricmp(word,"AM") == 0 || stricmp(word,"TO") == 0 || stricmp(word,"FOR") == 0 || stricmp(word,"MAY") == 0 || stricmp(word,"THAT") == 0 || stricmp(word,"WAS") == 0 || stricmp(word,"DID") == 0 || stricmp(word,"DIDN'T") == 0 || stricmp(word,"IN") == 0 || stricmp(word,"WITH") == 0 || stricmp(word,"SHALL") == 0 || stricmp(word,"SHOULD") == 0) { if (q != data) { save = *q; *q = 0; strcpy(predicate,data); *q = save; strcpy(psubj,q); return; } } if (stricmp(previous,"THE") && stricmp(previous,"A") && stricmp(previous,"AN") && stricmp(previous,"OF") && stricmp(previous,"SHALL") && stricmp(word,"SHOULD") && stricmp(previous,"WILL")) { if (q != data) { if(!IS_FILLER(word) && !IS_LOCATION(word) && !IS_DESCRIPTION(word) && !IS_VERB(word) && !IS_FILLER(previous) && !IS_LOCATION(previous) && !IS_DESCRIPTION(previous) && !IS_VERB(previous)) { save = *q; *q = 0; strcpy(predicate,data); *q = save; strcpy(psubj,q); return; } if(IS_VERB(word)) { /* Ignore verbs starting a clause/phrase */ /* If the previous word is a noun */ /* and we are scanning the predicate */ /* return from the previous word */ /* Ignore the verb if the previous word is an adverb */ if (stricmp(previous,"DO") && stricmp(previous,"NOT") && stricmp(previous,"DON'T") && stricmp(previous,"TO")) { save = *q; *q = 0; strcpy(predicate,data); *q = save; strcpy(psubj,q); return; } } } } } save = *p; *p = 0; strcpy(previous,q); q = &previous[strlen(previous)-1]; while(strchr(" .,;:!?",*q)) *q-- = 0; *p = save; q = p; } while(p); } int IS_VERB(char *word) { int n; char verb[40]; for(n = 0; n < num_a; n++) { strcpy(verb,actions[n]); if (stricmp(word,verb) == 0) { return 1; } /* Past tense */ if (verb[strlen(verb) - 1] == 'E') strcat(verb,"D"); else if (verb[strlen(verb) - 1] == 'Y') { /* Irregular words! */ if (stricmp(verb,"PAY") == 0) strcpy(verb,"PAID"); else if (stricmp(verb,"PLAY") == 0) strcpy(verb,"PLAYED"); else { verb[strlen(verb) - 1] = 0; strcat(verb,"IED"); } } else strcat(verb,"ED"); if (stricmp(word,verb) == 0) { return 1; } /* Plurals */ strcpy(verb,actions[n]); strcat(verb,"S"); if (stricmp(word,verb) == 0) { return 1; } /* ING */ strcpy(verb,actions[n]); if (verb[strlen(verb) - 1] == 'E') truncstr(verb,1); strcat(verb,"ING"); if (stricmp(word,verb) == 0) { return 1; } } return 0; } void PREDPAR() { char *p; GET_PREDICATE(text,psubj.text,predicate.text); GET_ACTION(psubj.text,psubj.action); GET_POBJECT(psubj.text,psubj.object); GET_DESCRIPTION(psubj.text,psubj.description); GET_PREDICATE(predicate.text,text,clause1.text); if (*clause1.text) { p = strstr(predicate.text,clause1.text); *p = 0; } GET_ACTION(predicate.text,predicate.action); GET_POBJECT(predicate.text,predicate.object); GET_DESCRIPTION(predicate.text,predicate.description); GET_PREDICATE(clause1.text,text,clause2.text); if (*clause2.text) { p = strstr(clause1.text,clause2.text); *p = 0; } GET_ACTION(clause1.text,clause1.action); GET_POBJECT(clause1.text,clause1.object); GET_DESCRIPTION(clause1.text,clause1.description); GET_PREDICATE(clause2.text,text,clause3.text); if (*clause3.text) { p = strstr(clause2.text,clause3.text); *p = 0; } GET_ACTION(clause2.text,clause2.action); GET_POBJECT(clause2.text,clause2.object); GET_DESCRIPTION(clause2.text,clause2.description); GET_PREDICATE(clause3.text,text,clause4.text); if (*clause4.text) { p = strstr(clause3.text,clause4.text); *p = 0; } GET_ACTION(clause3.text,clause3.action); GET_POBJECT(clause3.text,clause3.object); GET_DESCRIPTION(clause3.text,clause3.description); GET_ACTION(clause4.text,clause4.action); GET_POBJECT(clause4.text,clause4.object); GET_DESCRIPTION(clause4.text,clause4.description); }