/* NAME = lsys.c */
/* L-Systemes Michel BRET 07-10-2001 */
/* cc -g lsys.c lsys0.o -o lsys */

#include "lsys.h"

/* Regle G -> D */
/* ------------ */
typedef struct
    {
    char G[256];
    char D[256];
    } Regle;
Regle *R;

char *V, *A, *MOT1, *MOT2, *FIN1, *FIN2, *Mot1, *Mot2, *Mot, *Fin1, *Fin2, *Fin;
long NV, NR, NM0, NM;

char *malloc(long);
void axiome(char *);
void regles(char *);
char *copier(char *, char *, char *);
void editer();
long mot(long);
long production(char *, char *);

/***************************************************************/
/*    LS nom n                                                 */

main(long argc, char **argv)
{
char *buf, *pc;
long n, dim0, dim, no, i;
FILE *fp;

if (argc < 3)
    {
    printf("\n==================================\n");
    printf("%s f1 n [f2]\n", argv[0]);
    printf("  f1 = fichier de la forme:\n");
    printf("    VOCABULAIRE\n");
    printf("    A B C ...\n");
    printf("    REGLES\n");
    printf("    A -> BC\n");
    printf("    ...\n");
    printf("    AXIOME\n");
    printf("    A\n");
    putchar('\n');
    printf("n = profondeur du mot genere\n");
    putchar('\n');
    printf("f2 = fichier contenant le mot\n");
    printf("\n==================================\n");
    exit(0);
    }

buf = lire(argv[1]);

n = atoi(argv[2]);

V = vocabulaire(buf, &NV);
regles(buf);
axiome(buf);

editer();

NM0 = 1000000;
NM = NM0;
deb:
if ((MOT1 = malloc(NM)) == 0)
    erreur_malloc(NM);
if ((MOT2 = malloc(NM)) == 0)
    erreur_malloc(NM);
FIN1 = MOT1 + NM;
FIN2 = MOT2 + NM;
Mot = Mot1 = MOT1;
strcpy(Mot1, A);
Mot2 = MOT2;
Fin1 = FIN1;
Fin =Fin2 = FIN2;
*Mot2 = 0;    /* Vide */

/* regles(Mot1) -> Mot2, Mot1 <-> Mot2 */
if (mot(n))
    {
    free(MOT1);
    free(MOT2);
    NM *=2;
    printf("DEBORDEMENT\n");
    printf("REALLOCATION %d\n", NM);
    goto deb;
    }

if (argc >= 4)
    {
    if ((fp = fopen(argv[3], "w")) == 0)
        {
        printf("ERREUR ECRITURE %s\7\n", argv[3]);
        exit(-1);
        }
    dim = strlen(Mot);
    if (fwrite(Mot, 1, dim, fp) < dim)
        {
        printf("DISQUE PLEIN\7\n");
        exit(-1);
        }
    printf("ECRITURE %s\n", argv[3]);
    fclose(fp);
    }
}

/***************************************************************/
/*    regles(char pc)                                          */
/*    Reserve R -> REGLES                                      */
/*    Sort en cas d'erreur                                     */

void regles(char *pc)

{
char *pc1, *pc2;
long dim, i;

/* Rechercher REG */
pc1 = mot_cle(pc, "REG", 0);
pc1 = avance(pc1, '\n');
pc2 = mot_cle(pc1, "VOC", "AXI");

/* Charger les regles */
NR = 0;
pc = pc1;
while (pc < pc2)
    {
    pc = avance(pc, '\n');
    NR++;
    }
dim = NR * sizeof(Regle);
if ((R = (Regle *) malloc(dim)) == 0)
    erreur_malloc(dim);
pc = pc1;
for (i = 0; i < NR; i++)
    {
    pc = copier((R + i)->G, pc, " ");
    while (1)
        {
        switch (*pc)
            {
            case 0:
            case '\n':
                printf("ERREUR REGLE\7\n");
                exit(-1);
            case ' ':
            case '\t':
            case '-':
                pc++;
                break;
            case '>':
                pc++;
                goto suite;
            }
        }
suite:
    pc = copier((R + i)->D, pc, "\n");
    }
}

/***************************************************************/
/*    axiome(char pc)                                          */
/*    Reserve A -> AXIOME                                      */
/*    Sort en cas d'erreur                                     */

void axiome(char *pc)

{
char c, *pc2;
long dim;

/* Rechercher AXI */
pc = mot_cle(pc, "AXI", 0);
pc = avance(pc, '\n');
dim = strlen(pc);
if ((A = malloc(dim)) == 0)
    erreur_malloc(dim);
pc2 = A;
while ((c = *pc++) && c != '\n' && c != ' ' && c != '\t')
    *pc2++ = c;
*pc2 = 0;
}

/***************************************************************/
/*    copier(buf, pc, sep)                                     */
/*    pc -> ...sep, copie ... dans buf, retourne pc -> suite   */

char *copier(char *buf, char *pc, char *sep)

{
char c;

while ((c = *pc) == ' ' || c == '\t')
    pc++;
while (*pc != *sep && *pc != ' ' && *pc != '\t')
    *buf++ = *pc++;
*buf = 0;
pc++;
return(pc);
}

/***************************************************************/
/*    editer()                                                 */
/*    Edite le vocabulaire V, les regles R et l'axiome A       */

void editer()

{
char *pc;
long i;

printf("\n======================================\n\n");
printf("VOCABULAIRE\n-----------\n");
pc = V;
for (i = 0; i < NV; i++)
    {
    printf("%s ", pc);
    while (*pc++)
        ;
    }
putchar('\n');
putchar('\n');

printf("REGLES\n------\n");
for (i = 0; i < NR; i++)
    {
    printf("%d: ", i + 1);
    printf("%s -> ", (R + i)->G);
    printf("%s\n", (R + i)->D);
    putchar('\n');
    }

printf("AXIOME\n------\n%s\n", A);
printf("\n======================================\n\n");
}

/***************************************************************/
/*    mot(n)                                                   */
/*    Genere et edite le mot de profondeur n                   */

long mot(long n)

{
long i;

while (n-- > 0)
    {
    if (production(Mot1, Mot2))
        return(1);
    Mot = Mot2;
    Mot2 = Mot1;
    Mot1 = Mot;
    Fin = Fin2;
    Fin2 = Fin1;
    Fin1 = Fin;
    }

n = strlen(Mot);
printf("Longueur du mot genere = %d\n", n);
if (n < 1000)
    printf("%s\n", Mot);
else
    {
    for (i = 0; i < 1000; i++)
        putchar(Mot[i]);
    printf(" ...");
    }
putchar('\n');
return(0);
}

/***************************************************************/
/*    production(pc1, pc2)                                     */
/*    Remplace pc1[0...] par regle(pc1[0...]) dans pc2         */
/*    En sortie pc1 et pc2 -> suite                            */
/*    Retourne 1 si debordement                                */

long production(char *pc1, char *pc2)

{
char *pc, *G, *D;
long ng, nd, i, j;

while (*pc1)
    {
    for (i = 0; i < NR; i++)
        {
        G = (R + i)->G;
        ng = strlen(G);
        for (j = 0; j < ng; j++)
            if (pc1[j] != G[j])
                goto suite0;
    /* Remplacer */
        D = (R + i)->D;
        nd = strlen(D);
        pc = D;
        for (j = 0; j < nd; j++)
            {
            if (pc2 >= Fin2)
                return(1);
            *pc2++ = *pc++;
            }
        pc1 += ng;
        goto suite1;
suite0:    /* Regle suivante */
        ;
        }
/* Copier le symbole */
    *pc2++ = *pc1++;
suite1:    /* Caractere suivant */
    ;
    }
*pc2 = 0;
return(0);
}

/* END */
