/*
 * Copyright (c) 1978 Charles H. Forsyth
 *
 * Modified 02-Dec-80 Bob Denny -- Conditionalize debug code for smaller size
 *  Also note other mods. Now minimization is turned on at run time by '-m'.
 * More     19-Mar-82 Bob Denny -- New C library & compiler
 *  This routine is unimplemented. Define MIN to turn it on. Have fun.
 */

/*
 * lex -- dfa minimisation routines
 */

#include <stdio.h>
#include "lexlex.h"

#ifdef  MIN
#else
/*
 * Dummy routine
 */
dfamin()
{
}
#endif

#ifdef  MIN

member(e, v, i)
register e, *v, i;
{

        while (i--)
                if (e==*v++)
                        return(1);
        return(0);
}

extern struct set **oldpart;
extern int **newpart;
extern int nold, nnew;

struct  xlist {
        struct  set     *x_set;
        struct  trans   *x_trans;
              };

xcomp(a, b)
struct xlist *a, *b;
{
        if (a->x_trans > b->x_trans)
                return(1);
        if (a->x_trans==b->x_trans)
                return(0);
        return(-1);
}

dfamin()
{
        struct xlist *temp, *tp, *xp, *zp;
        struct trans *trp;
        int *tp2, *ip;
        struct set *gp, **xch;
        int i, j, k, niter;

        if(mflag == 0) return;          /*** NOTE ***/

#ifdef DEBUG
        fprintf(lexlog, "\nDFA minimisation (%d states)\n", ndfa);
#endif

        temp = lalloc(ndfa, sizeof(*temp), "minimisation");
        oldpart = lalloc(ndfa, sizeof(*oldpart), "minimisation");
        newpart = lalloc(ndfa*2+1, sizeof(*newpart), "minimisation");
        setlist = 0;
/*
 * partition first into final
 * states which identify different
 * translations, and non-final
 * states.
 */
        tp = temp;
        for (i = 0; i < ndfa; i++, tp++) {
                tp->x_set = dfa[i].df_name;
                if (tp->x_set->s_final)
                        tp->x_trans = nfa[tp->x_set->s_final].n_trans; else
                        tp->x_trans = 0;
        }
        qsort(temp, tp-temp, sizeof(*tp), xcomp);
        for (xp = temp; xp < tp; xp = zp) {
                ip = newpart;
                for (zp = xp; zp < tp && zp->x_trans==xp->x_trans; zp++)
                        *ip++ = zp->x_set->s_state-dfa;
                oldpart[nold++] = newset(newpart, ip-newpart, 0);
        }
        free(temp);
/*
 * create a new partition,
 * by considering each group in
 * the old partition.  For each
 * such group, create new subgroups
 * such that two states are in the
 * same subgroup iff they have
 * transitions on the same set of
 * characters into the same
 * set of groups in the old partition.
 * repeat this process until
 * a fixed point is reached.
 */
        niter = 0;
        do {
                niter++;

#ifdef DEBUG
                fprintf(lexlog, "\n%d groups in partition %d\n", nold, niter);
#endif

                for (i = 0; i < nold; i++) {
                        fprintf(lexlog, "group %d: ", i);
                        pset(oldpart[i], 0);
                        fprintf(lexlog, "\n");
                }
                nnew = 0;
                tp2 = newpart;
                for (i = 0; i < nold; i++) {
                        gp = oldpart[i];
                        for (j = 0; j < gp->s_len; j++) {
                                if (member(gp->s_els[j], newpart, tp2-newpart))
                                        continue;
                                *tp2++ = gp->s_els[j];
                                for (k = 0; k < gp->s_len; k++)
                                        if (k!=j &&
                                            !member(gp->s_els[k], newpart,
                                                tp2-newpart) &&
                                            eqstate(gp->s_els[j],gp->s_els[k]))
                                                *tp2++ = gp->s_els[k];
                                *tp2++ = -1;
                        }
                }
                *tp2++ = -1;
                for (tp2 = newpart; *tp2 != -1; tp2 = ++ip) {
                        for (ip = tp2; *ip != -1; ip++)
                                ;
                        oldpart[nnew++] = newset(tp2, ip-tp2, 0);
                }
                i = nold; nold = nnew; nnew = i;
        } while (nnew!=nold);

#ifdef DEBUG
        if (ndfa==nnew)
                fprintf(lexlog, "\nno states saved by minimisation\n"); else
                fprintf(lexlog, "\n%d states saved by minimisation\n", ndfa-nnew);
#endif

        free(newpart);
        free(oldpart);
}

eqstate(a, b)
{
        register struct move *dp1, *dp2;

/**  dfa vector has no element 'df_moves', transition entries have no elements
        df_char nor df_set. Obviously unimplemented stuff.

        dp1 = dfa[a].df_moves;
        dp2 = dfa[b].df_moves;
        for (; dp1->df_set; dp1++, dp2++)
                if (dp2->df_set==0)
                        return(0);
                else if (dp1->df_char != dp2->df_char ||
                         dp1->df_set->s_group != dp2->df_set->s_group)
                        return(0);
        return(dp2->df_set==0);
**/

}
#endif
