SYNTACTICAL STRUCTURES

Sentences, if constructed properly, are comprised of two parts: subject and predicate. For example. The sentence "many hands make light work." Splits into "many hands" and "make light work". The predicative qualifies or describes the subject. In some sentences either the subject or the predicate may be implied, rather than stated. For example in the sentence "come here!" The subject, "you", is implied. Of course this type of sentence can lead to misunderstandings!

Within the subject, one word is the "subject word". In the sentence "many hands make light work.", the subject word is "hands" because it is a noun following an adjective. Whereas in the sentence, "most of the audience enjoyed the concert." The subject word is "most", denoted by an adjective phrase following it, "of the audience".

Within a sentence there is also an object. The object is a noun, perhaps represented by a pronoun, upon which the sentence's verb acts. For example. In the sentence "the cat chased the mouse." The object is "mouse", because it is the noun acted upon by the verb, "chased".

Often a sentence contains phrases and clauses. Clauses are sub-sections of the sentence with their own verb (action word), a phrase does not have a verb. For example. "I saw Mrs Brown drive her car along the motorway." This sentence contains the subject, "I" and the predicative "saw Mrs Brown drive her car along the motorway." The predicative is further divided into: "saw Mrs Brown", "drive her car" and "along the motorway."

This breaking down of sentences can be taken further. Linguistics declares that a phrase can be broken down into a hierarchical structure in which groups of words appear as groups. If we analyse the sentence "I believe that the box fell off the kitchen table." First we can split it into the subject and predicate;
SubjectPredicate
I believethat the box fell off the kitchen table
full syntactical analyse of the sentence is;

    S--------VP--------S-------S-------VP------PP------NP-------N---------N
    |        |         |       |       |       |       |        |         |
    NP       V        CONJ     NP      V       P      DET       N         N
    |        |         |       |       |       |       |        |         |
    I     believe     that     |      fell    off     the    kitchen    table
                            +--+--+
                            |     |
                           DET    N
                            |     |
                           the   box


Key to diagram

CONJ Conjunction
DET  Determiner
N    Noun
NP   Noun Phrase
P    Preposition
S    Sentence
VP   Verb Phrase
V    Verb
A predicate parser that extracts subjects and clauses from a sentence is a useful device for breaking a sentence down into small sections.
---------
Listing 3
---------

/* PREDICATE PARSER */

/*---------------*/
/* Include files */
/*---------------*/
#include 
#include 
#include 
#include 

/*-----------*/
/* Constants */
/*-----------*/
#define num_a    139
#define num_q    72
#define num_l    20
#define num_c    14
#define num_f    18
#define num_qs    5

/*-----------*/
/* Lexicons  */
/*-----------*/
/* Verbs and adverbs */
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",
                           "CROSS", "ENTER", "CLIMB", "TIE", "CROUCH","CRAWL",
                           "BREATHE", "SNIFF", "SPIT" ,"GO","PUT","DRINK",
                           "LOOK", "TURN", "BORN","LEAVE", "URINATE",
                           "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","HAD","HAS" };

static char *questions[num_qs] = { "WHAT", "WHEN", "HOW", "WHY", "WHERE" };

/* Prepositions and conjunctions */
static char *fillers[num_f] = { "IS", "THE" , "A", "AN" , "ARE" ,"TOO","ALSO",
                                "COME" , "FROM" , "ITS" , "THEIR" ,"WITH",
                                "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","BIG",
                        "SMALL", "FAT", "THIN", "TALL" ,"SHORT",
                        "LARGE", "PETITE", "TINY" , "BLACK", "BLUE",
                        "RED", "YELLOW", "ORANGE","GREEN","BROWN" ,
                        "GINGER" , "PURPLE","MAUVE", "SILVERY", "SILVER",
                        "GOLD", "CYAN" ,"LAZY" ,"CARNIVOROUS" ,"PAST", "MY",
                        "IN" , "ON", "BESIDE","OLD" };


static char *locations[num_l] = { "IN" , "ON", "BESIDE" , "EAST" , "WEST" ,
                                  "NORTH" ,"SOUTH" , "UNDER" , "UP" ,
                                  "BELOW", "ABOVE", "RIGHT", "LEFT",
                                  "OVER","INTO","AROUND" , "TO", "OFF",
                                  "THERE" };

typedef struct {
    char text[500];
    char object[80];
    char description[80];
    char action[80];
}
SUBJECT;

SUBJECT subject;
SUBJECT predicate;
SUBJECT clause1;
SUBJECT clause2;
SUBJECT clause3;

/*---------------------*/
/* Function prototypes */
/*---------------------*/
int IS_COLOUR(char *);
int IS_FILLER(char *);
int IS_LOCATION(char *);
int IS_VERB(char *);
void strchg(char *, char *, char *);
void truncstr(char *,int );

/*--------------------*/
/* Start of functions */
/*--------------------*/
static void GET_OBJECT(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)
        {
            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 (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 void GET_ACTION(char *text , char *action)
{
    /* Obtain action words from the phrase string */

    char *p;
    char pre[50];
    char copy[250];

    strcpy(copy,text);
    strcpy(action,"");
    strcpy(pre,"");

    p = strtok(text," ,.;:?!");

    while(p)
    {
        if (IS_VERB(p))
        {
            if (stricmp(pre,"THE"))
            {
                if (*action)
                    strcat(action," ");
                strcat(action,p);
            }
        }
        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_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_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 *subject)
{
    /* Splits a sentence into its two parts */

    char *p;
    char *q;
    char word[40];
    char save;
    char previous[40];

    strcpy(predicate,data);
    strcpy(subject,"");

    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(subject,p);
                return;
            }
            if (stricmp(word,"MOST") == 0)
            {
                save = *p;
                *p = 0;
                strcpy(predicate,data);
                *p = save;
                strcpy(subject,p);
                return;
            }

            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(subject,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(subject,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 */
                        save = *q;
                        *q = 0;
                        strcpy(predicate,data);
                        *q = save;
                        strcpy(subject,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 truncstr(char *p,int num)
{
    /* Truncate string by losing last num characters */
    if (num < strlen(p))
        p[strlen(p) - num] = 0;
}

void main()
{
    /* This is a test call */
    char *p;
    FILE *fp;

    char text[250];

    fp = fopen("response.out","w+");

    do
    {
        printf("\nEnter a phrase\n");
        gets(text);
        if (*text != 0)
        {
            strupr(text);
            GET_PREDICATE(text,subject.text,predicate.text);
            GET_ACTION(subject.text,subject.action);
            fprintf(fp,"\nSUBJECT [%s] PREDICATE [%s]",subject.text,
                       predicate.text);
            GET_OBJECT(subject.text,subject.object);
            fprintf(fp,"\nOBJECT[%s]",subject.object);
            fprintf(fp,"\nACTION [%s]",subject.action);
            GET_DESCRIPTION(subject.text,subject.description);
            fprintf(fp,"\nDESCRIPTION [%s]",subject.description);

            fprintf(fp,"\nPREDICATE ANALYSIS");
            GET_PREDICATE(predicate.text,text,clause1.text);
            if (*clause1.text)
            {
                p = strstr(predicate.text,clause1.text);
                *p = 0;
            }
            GET_ACTION(predicate.text,predicate.action);
            fprintf(fp,"\nACTION [%s]",predicate.action);
            GET_OBJECT(predicate.text,predicate.object);
            fprintf(fp,"\nOBJECT [%s]",predicate.object);
            GET_DESCRIPTION(predicate.text,predicate.description);
            fprintf(fp,"\nDESCRIPTION [%s]",predicate.description);

            GET_PREDICATE(clause1.text,text,clause2.text);
            if (*clause2.text)
            {
                p = strstr(clause1.text,clause2.text);
                *p = 0;
            }
            fprintf(fp,"\nFIRST CLAUSE ANALYSIS");
            fprintf(fp,"\nCLAUSE [%s]",clause1.text);
            GET_ACTION(clause1.text,clause1.action);
            fprintf(fp,"\nACTION [%s]",clause1.action);
            GET_OBJECT(clause1.text,clause1.object);
            fprintf(fp,"\nOBJECT [%s]",clause1.object);
            GET_DESCRIPTION(clause1.text,clause1.description);
            fprintf(fp,"\nDESCRIPTION [%s]",clause1.description);

            GET_PREDICATE(clause2.text,text,clause3.text);
            if (*clause3.text)
            {
                p = strstr(clause2.text,clause3.text);
                *p = 0;
            }

            fprintf(fp,"\nSECOND CLAUSE ANALYSIS");
            fprintf(fp,"\nCLAUSE [%s]",clause2.text);
            GET_ACTION(clause2.text,clause2.action);
            fprintf(fp,"\nACTION [%s]",clause2.action);
            GET_OBJECT(clause2.text,clause2.object);
            fprintf(fp,"\nOBJECT [%s]",clause2.object);
            GET_DESCRIPTION(clause2.text,clause2.description);
            fprintf(fp,"\nDESCRIPTION [%s]",clause2.description);

            fprintf(fp,"\nTHIRD CLAUSE ANALYSIS");
            fprintf(fp,"\nCLAUSE [%s]",clause3.text);
            GET_ACTION(clause3.text,clause3.action);
            fprintf(fp,"\nACTION [%s]",clause3.action);
            GET_OBJECT(clause3.text,clause3.object);
            fprintf(fp,"\nOBJECT [%s]",clause3.object);
            GET_DESCRIPTION(clause3.text,clause3.description);
            fprintf(fp,"\nDESCRIPTION [%s]",clause3.description);
        }
    }
    while(*text);
}
A type of parser which makes use of syntactical structures is the "augmented transition network", abbreviated to "ATN". ATN was developed by Thorne, Bratley and Dewar in 1968, and built upon by W.A. Woods. He published his work under the title "Transition network grammars for natural language analysis" in the communications of the association for computing machinery journal, volume 13 in 1970. The general idea behind ATN is that in the English language, verb phrases generally follow noun phrases. Thus an ATN seeks a noun phrase, and then seeks a verb phrase to associate with the noun phrase. This idea of using grammatical rules to parse sentences is illustrated in the following example of a "depth-first exhaustive search" syntactical parser.
---------
Listing 4
---------

/*---------------*/
/* Include Files */
/*---------------*/
#include 
#include 
#include 


The following data comprises the rules of grammar, and the lexicon for the
parser. Other rules and words can be added as required.


char *data[] = { "= ",
                 "=  ",
                 "= ",
                 "= ",
                 "=",
                 "=
                   ",
                 "=",
                 "= ",
                 "= ",
                 "= ",
                 "=",
                 "=A","AN","THE","THIS","THAT",
                 "=GREEN","RED","BLUE","YELLOW","CYAN","STRONG",
                  "BUILT",
                 "=JACK","JOHN","ROSE","GRASS","SUN","HOUSE","TREE",
                 "=GREW","SHONE","MADE",
                 "=TO","OF","IN",
                 "=AND","OR","IS",
                 "" };


/*----------------*/
/* Work variables */
/*----------------*/

char as[100];
char h[250];
char text[250];
char gs[50][100];
char ws[50][100];
int ra[50];
int la[50];
int lb[50];

char temp[100];

int s;
int c;
int q;
int r;
int f;
int ls;
int c1;
int c2;
int c3;
int c4;
int counter;
char *p;
int i;
int j;
int k;

void main()
{

    s = 1;
    c = 0;
    q = 1;

    /* Clear the display */
    clrscr();

    /* Receive an input phrase from the operator */
    printf("\nInput a sentence ");
    gets(text);

    /* Convert the input phrase to upper case */
    strupr(text);

    /* Insert a space at the beginning of the input string */
    memmove(&text[1],text,strlen(text) + 1);
    text[0] = 32;

    /* Append a space to the end of the input string */
    strcat(text," ");

    /* Preserve a copy of the input string */
    strcpy(H,text);

    /* Load constant data */
    counter = 0;
    r = 0;
    do
    {
        f = 0;
        strcpy(as,data[counter]);
        if (*as)
        {
            while(as[strlen(as) - 1] == 32)
                as[strlen(as) - 1] = 0;

            for(i = 0; i < strlen(as); i++)
            {
                if(as[i] == '=')
                {
                    strncpy(gs[r],as,i);
                    gs[r][i + 1] = 0;
                    f = 1;
                    strcpy(ws[r],&as[i+1]);
                    i = strlen(as);
                }
            }
            if (f == 0)
            {
                strcpy(gs[r], gs[r - 1]);
                strcpy(ws[r],as);
            }
        }
        r = r + 1;
        counter++;
    }
    while(*as);

    /*----------------*/
    /* The parse loop */
    /*----------------*/

    /* Clear the display */
    clrscr();

    printf("Syntactical parsing analysis of %s",text);
    printf("\n\n");
    do
    {
        f = 0;
        s = 0;
        ls = strlen(text);
        c1 = 0;
        q = 0;

        for(i = q; i < ls; i++)
        {
            if (text[i] == ' ')
            {
                i = i + 1;
                c1 = c1 + 1;
                for(j = s; j <= r; j++)
                {
                    p = &text[i];
                    strcpy(temp,ws[j]);
                    strcat(temp," ");
                    if (strncmp(temp,p,strlen(ws[j])+1) == 0)
                    {
                        c = c + 1;
                        la[c] = i;
                        lb[c] = ls - strlen(ws[j]) - i;
                        p = &text[strlen(text) - lb[c]];
                        strcpy(temp,p);
                        text[la[c]] = 0;
                        strcat(text,gs[j]);
                        strcat(text,temp);
                        f = 1;
                        ra[c] = j;
                        printf("\n%d %s",c,text);
                        c2 = c1 + 1;
                        for(k = 0; k < strlen(ws[j]); k++)
                        {
                            if(ws[j][k] == ' ')
                                c2++;
                        }
                        c3 = 0;
                        c4 = 0;
                        strcpy(as,"");
                        for(k = 0; k < strlen(h); k++)
                        {
                            strcat(as," ");
                            as[strlen(as) - 1] = h[k];
                            if (h[k] == ' ')
                            {
                                c3++;
                                c4++;
                                if (c3 > c1 && c4 <= c2)
                                {
                                    as[strlen(as) - 1] = 0;
                                }
                                if (c3 == c1)
                                    strcat(as,"(");
                                if (c4 == c2)
                                    strcat(as,") ");
                            }
                        }
                        strcpy(h,as);
                        printf("\n%s",h);
                        j = r;
                        i = ls;
                    }
                }
            }
        }
        p = &text[strlen(text) - 2];
        if (c1 == 1 && c2 == 1 && strncmp(text," <",2) == 0 &&
            strcmp(p,"> ") == 0)
        {
            printf("\n\nParsing complete");
            exit(0);
        }
    }
    while(f == 1);
    printf("\nParsing complete");
}
Here are some sample outputs of the syntactical parser;
Syntactical parsing analysis of  THIS IS THE HOUSE THAT JACK BUILT


1   IS THE HOUSE THAT JACK BUILT
 (THIS) IS THE HOUSE THAT JACK BUILT

2    THE HOUSE THAT JACK BUILT
 (THIS) (IS) THE HOUSE THAT JACK BUILT

3     HOUSE THAT JACK BUILT
 (THIS) (IS) (THE) HOUSE THAT JACK BUILT

33
4      THAT JACK BUILT
 (THIS) (IS) (THE) (HOUSE) THAT JACK BUILT

5      THAT JACK BUILT
 (THIS) (IS) (THE) ((HOUSE)) THAT JACK BUILT

6     THAT JACK BUILT
 (THIS) (IS) ((THE)((HOUSE))) THAT JACK BUILT

7      JACK BUILT
 (THIS) (IS) ((THE)((HOUSE))) (THAT) JACK BUILT

8       BUILT
 (THIS) (IS) ((THE)((HOUSE))) (THAT) (JACK) BUILT

9      
   BUILT
 (THIS) (IS) ((THE)((HOUSE))) (THAT) ((JACK)) BUILT

10      BUILT
 (THIS) (IS) ((THE)((HOUSE))) ((THAT)((JACK))) BUILT

11      
 (THIS) (IS) ((THE)((HOUSE))) ((THAT)((JACK))) (BUILT)

Parsing complete



Syntactical parsing analysis of  THE SUN SHONE AND THE GRASS GREW


1   SUN SHONE AND THE GRASS GREW
 (THE) SUN SHONE AND THE GRASS GREW

2    SHONE AND THE GRASS GREW
 (THE) (SUN) SHONE AND THE GRASS GREW

3    SHONE AND THE GRASS GREW
 (THE) ((SUN)) SHONE AND THE GRASS GREW

4   SHONE AND THE GRASS GREW
 ((THE)((SUN))) SHONE AND THE GRASS GREW

5    AND THE GRASS GREW
 ((THE)((SUN))) (SHONE) AND THE GRASS GREW

34
6    AND THE GRASS GREW
 ((THE)((SUN))) ((SHONE)) AND THE GRASS GREW

7    AND THE GRASS GREW
 ((THE)((SUN))) (((SHONE))) AND THE GRASS GREW

8   AND THE GRASS GREW
 (((THE)((SUN)))(((SHONE)))) AND THE GRASS GREW

9    THE GRASS GREW
 (((THE)((SUN)))(((SHONE)))) (AND) THE GRASS GREW

10     GRASS GREW
 (((THE)((SUN)))(((SHONE)))) (AND) (THE) GRASS GREW

11      GREW
 (((THE)((SUN)))(((SHONE)))) (AND) (THE) (GRASS) GREW

12      GREW
 (((THE)((SUN)))(((SHONE)))) (AND) (THE) ((GRASS)) GREW

13     GREW
 (((THE)((SUN)))(((SHONE)))) (AND) ((THE)((GRASS))) GREW

14     
 (((THE)((SUN)))(((SHONE)))) (AND) ((THE)((GRASS))) (GREW)

15     
 (((THE)((SUN)))(((SHONE)))) (AND) ((THE)((GRASS))) ((GREW))

16     
 (((THE)((SUN)))(((SHONE)))) (AND) ((THE)((GRASS))) (((GREW)))

17    
 (((THE)((SUN)))(((SHONE)))) (AND) (((THE)((GRASS)))(((GREW))))

18  
 ((((THE)((SUN)))(((SHONE))))(AND)(((THE)((GRASS)))(((GREW)))))

Parsing complete
Syntactical parsing involves complex and very impressive algorithms. Too complex for the average human mind? I think so. I think that in order to understand natural language we must understand the human mind. In the next chapter I shall explore natural language parsing from the much simpler psychology angle. Too simple? Perhaps, but remember that a child can understand simple phrases. It takes a rare breed to comprehend linguistics!