View Source Document

thue.c

/* $Header: C:\\UTILS\\CVS\\ROOT/programs\\lang\\thue/thue.c,v 1.4 2000/09/02 16:46:29 John Colagioia Exp $
 *
 * Recent Changes:
 *
 * $Log: thue.c,v $
 * Revision 1.5  2010/12/18           Chris Pressey
 * Fix off-by-one error in sort routine, reported by
 * Nathan Thern.  Fix another off-by-one error in
 * random number generation.  Modernize: use rand()
 * and rename getline() to avoid name conflict.
 *
 * Revision 1.4  2000/09/02 16:46:29  John Colagioia
 * Trivial bugfix.
 *
 * Revision 1.2  2000/02/29 21:51:24  John Colagioia
 *
 * Just added some basic header info in the comments.
 *
 *
 */

/* For want of a nail,
    the shoe was lost.
   For want of a shoe,
    the horse was lost.
   For want of a horse,
    the knight was lost.
   For want of a knight,
    the battle was lost.
   So it was a kingdom was lost,
    all for the want of a nail.
    -- George Herbert, Jacula Prudentum
       (Colloqual Adaptation)
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <time.h>

#define SEP "::="

    char    * get_line  (FILE * infile);

struct rule
    {
     char   lhs[64];
     char   rhs[64];
    } rulebase[128];

int ruleidx = 0,
    debug = 0;
char    *dataspace,
    *tempspace;

int main (int argc, char *argv[])
{
 char   *line,
    *c,
    *tmp,
    *target[64],
     tempstr[64];
 int     state,
     flagstate,
     i, j, k,
     order,
     temp,
     rnum[64];
 FILE   *infile;

 srand(time(0));
 dataspace = malloc(16384);
 tempspace = malloc(16384);
 if (dataspace == NULL || tempspace == NULL) {
    fprintf (stderr, "Could not allocate sufficient working memory\n");
    exit(1);
 }
 target[0] = dataspace;
 memset (rulebase, 0, sizeof (rulebase));
 memset (dataspace, 0, sizeof (dataspace));
 if (argc > 1)
    infile = fopen (argv[1], "r");
 else
    infile = stdin;
 if (infile == NULL)
    return (-1);

 order = 0;
 if (argc > 2)
    switch (argv[2][0])
    {
     case 'r':  /* Right-to-Left Processing */
        order = 2;
        break;
     case 'l':  /* Left-to-Right */
        order = 1;
        break;
     case 'd':
        debug = 1;
        break;
    }

 /* Get input file */
 state = 0;
 while (!feof (infile))
    {
     line = get_line (infile);
     if (state == 0)
        {
         if (line != NULL && !strlen (line))
            continue;
         c = strstr (line, SEP);
         if (c == NULL)
            fprintf (stderr, "Malformed production: \"%s\"!\n", line);
         else if (c == line)
            state = 1;
         else   {
             flagstate = 0;
             for (tmp=line;tmp!=c;tmp++)
                if (!isspace (*tmp))
                     flagstate = 1;
             if (flagstate)
                {
                 *c = '\000';
                 c += strlen (SEP);
                 strcpy (rulebase[ruleidx].lhs, line);
                 strcpy (rulebase[ruleidx].rhs, c);
                 ++ruleidx;
                }
             else   state = 1;
            }
        }
     else if (line != NULL)
            strcat (dataspace, line);
    }

 if (debug)
    printf ("Initial:  \"%s\"\n", dataspace);

 /* Apply rules */
 state = 1;
 while (state)
    {
     /* Get all valid LHSs */
     j = 1;
     k = 0;
     c = dataspace;
     for (i=0;i<ruleidx;i++)
        do
        {
         k = j;
         target[k] = strstr (c, rulebase[i].lhs);
         rnum[k] = i;
         if (target[k] != NULL)
            {
             ++j;
             c = target[k] + 1;
            }
         else
            c = dataspace;
        }
        while (target[k]);

     if (j == 1)
        {
         state = 0;
         continue;
        }

     /* Sort the LHS list - Just a bubble sort */
     for (i=1;i<j;i++)
        for (k=1;k<i;k++)
        if (target[i] < target[k])
            {
             c = target[i];     temp = rnum[i];
             target[i] = target[k]; rnum[i] = rnum[k];
             target[k] = c;     rnum[k] = temp;
            }

     /* Choose rule to apply */
     switch (order)
        {
         case 2:
            i = j - 1;
            break;
         case 1:
            i = 1;
            break;
         default:
            i = rand() % (j - 1) + 1;
            break;
        }
     line = target[i];
     temp = rnum[i];
     c = line + strlen (rulebase[temp].lhs);
     *line = '\000';

     /* Check for I/O */
     i = rulebase[temp].rhs[0] == '~';
     if (i)
        {
         puts (&rulebase[temp].rhs[1]);
         memset (tempstr, 0, sizeof (tempstr));
        }
     else
        {
         i = !strcmp (rulebase[temp].rhs, ":::");
         if (i)
                     {
            fgets (tempstr, sizeof (tempstr), stdin);
                        tempstr[strlen (tempstr) - 1] = '\0';
                     }
        }

     /* Apply the rule */
     sprintf (tempspace, "%s%s%s", dataspace, i?tempstr:rulebase[temp].rhs, c);
     strcpy (dataspace, tempspace);
     if (debug)
        puts (dataspace);
    }

 if (debug)
    printf ("Final:  \"%s\"\n", dataspace);
 return (0);
}

char * get_line (FILE * infile)
{
 static char     buffer[256];
    char    *s;

 memset (buffer, 0, sizeof (buffer));
 /* Get next line from file */
 s = fgets (buffer, sizeof (buffer), infile);
 if (s == NULL)
    return (NULL);
 buffer[strlen (buffer) - 1] = '\0';
 /* Return pointer to string */
 return (buffer);
}