/***********************************
  (C) Copyright 1992-1993; dit/upm
   Distributed under the conditions stated in the
   TOPO General Public License (see file LICENSE)
 ***********************************
 $Log: gendef.c,v $
 * Revision 1.15  1993/06/10  14:00:13  lotos
 * new annotation CALL
 *
 * Revision 1.14  1993/05/28  10:41:43  lotos
 * opcion -c tiene niveles
 *
 * Revision 1.13  1993/05/25  10:59:09  lotos
 * ldcend y ldcinit pasan al principio
 *
 * Revision 1.12  1993/03/24  17:51:24  lotos
 * use of annotation 'nonconstructor'
 * annotation ldcinit and ldc (final) go into ATable
 *
 * Revision 1.11  1993/01/18  18:12:15  lotos
 * distribution issues
 *
 * Revision 1.10  1992/11/17  18:42:55  lotos
 * added ldcinit and late ldc
 *
 * Revision 1.9  1992/10/14  17:43:25  lotos
 * forget about ophuscation
 *
 * Revision 1.8  1992/05/06  18:50:21  lotos
 * indentation of PARTIAL annotation
 *
 * Revision 1.7  92/01/14  15:25:11  lotos
 * distribution issues
 * 
 * Revision 1.6  92/01/13  19:24:31  lotos
 * adaptec to ophuscate
 * 
 * Revision 1.5  91/11/14  20:17:59  lotos
 * allowed internal operations of a external sort
 * added fail annotation of LDM
 * 
 * Revision 1.4  91/10/02  16:49:25  lotos
 * color sort is now in the AT
 * 
 * Revision 1.3  91/05/03  19:51:03  lotos
 * system V adaptation
 * 
 * Revision 1.2  91/04/11  18:32:56  lotos
 * cosmetics
 * 
 * Revision 1.1  91/02/06  20:13:21  lotos
 * Initial revision
 * 
 ***********************************/

#ifndef lint
static char rcsid[]= "$Id: gendef.c,v 1.15 1993/06/10 14:00:13 lotos Exp $";
#endif

/***********************************************************************

     "gendef.o": modulo generador de la definicion de tipo de datos.

***********************************************************************/

#include <stdio.h>
#include "idle.h"
#include "tabop.h"
#include "lisec.h"
#include "matec.h"
#include "patrones.h"
#include "ecuaciones.h"
#include "LDM.h"
#include "gendef.h"


static void GenOpSinArg(OpDato)
/* Genera una operacion sin argumentos. */
EstManOp *OpDato;	/* Operacion dato. */
{ static EstPat *PatNul= NULL;
  EstLisEc Cur;		/* Cursor de la lista de ecuaciones. */
  EstManEc *PrimEc;	/* Primera ecuacion. */
  EstManEc *EcAct;	/* Ecuacion actual. */
  char *c;

  aborta_si(OpDato == NULL ||
	    OpDato->Tipo != OpSinArg)
  if (PatNul == NULL)
  { PatNul= AsigMem(EstPat, 1);
    InicPat(PatNul);
  }
  /* Generacion de las declaraciones. */
  if (OpcProg.InsCom > 0)
  { Sangra();
    EscComOp(OpDato->Nodo);
  }
  Sangra();
  (void) printf("%s %s ", BEGIN_OPERATION_DEF, OpDato->Id);
  PrimEc= OpDato->u.LisEc.EcOrig;
  if (PrimEc == NULL)
    (void) printf("%s", BUILD);
  else
    for (EcAct= PrimEc->SigEc;; EcAct= EcAct->SigEc)
      if (EcAct->Premisas == NULL)
      { (void) printf("%s", REWRITE);
	break;
      }
      else if (EcAct == PrimEc)
      { (void) printf("%s", GENERAL);
	break;
      }
  (void) printf(" %d 0\n", ClTab(sort(iddec(OpDato->Nodo)))->Num);
  IncSang();
  /* Anotacion "partial". */
  c= partial(iddec(OpDato->Nodo));
  if (c != NULL)
  { char Buf[BUFSIZ];
    char *s;

    s= name(iddec(OpDato->Nodo));
    if (s == NULL)
      s= lexv(iddec(OpDato->Nodo));
    (void) sprintf(Buf, "%s %d %s", s, line(OpDato->Nodo),
				       file(OpDato->Nodo));
    EscAnot(PARTIAL_ANNOTATION, Buf, c);
  }
  /* Comienza la generacion de codigo. */
  if (PrimEc != NULL)
  { /* Hay, al menos, una ecuacion. */
    /* Generacion de codigo para las ecuaciones con premisas. */
    Cur.EcOrig= PrimEc;
    do
    { EcAct= Cur.EcOrig->SigEc;
      if (EcAct->Premisas == NULL)
      { Cur.EcOrig= Cur.EcOrig->SigEc;
	continue;
      }
      EscRegla(EcAct, PatNul, 0);
      SuprEcLis(&Cur);
    } while (EcAct != PrimEc);
    PrimEc= OpDato->u.LisEc.EcOrig= Cur.EcOrig;
  }
  if (PrimEc == NULL)
  { /* No hay ecuaciones sin premisas. */
    Sangra();
    (void) printf("%s %d %d", BUILD, OpDato->Num,
		  ClTab(sort(iddec(OpDato->Nodo)))->Num);
    if (nonconstructor(iddec(OpDato->Nodo)) != STR_ERR)
    { char *s;

      s= name(iddec(OpDato->Nodo));
      if (s == NULL)
	s= lexv(iddec(OpDato->Nodo));
      (void) printf(" %s %s %s %d %s", ANNOTATION, FAIL_ANNOTATION,
				       s, line(OpDato->Nodo),
					  file(OpDato->Nodo));
    }
    (void) printf("\n");
  }
  else
  { /* Generacion de codigo para una de las ecuaciones sin premisas. */
    EscRegla(PrimEc->SigEc, PatNul, 0);
    SuprLisEc(&OpDato->u.LisEc);
  }
  DecSang();
  Sangra();
  (void) printf("%s\n", END_OPERATION_DEF);
}

static int OpReescSiempre(MatOp)
/* Indica si una operacion se puede reescribir siempre. */
EstEcxArg *MatOp;	/* Matriz de la operacion. */
{ EstManEc *PrimEc;	/* Primera ecuacion. */
  EstManEc *EcAct;	/* Ecuacion actual. */
  EstArgEc *PrimArgEc;	/* Primer argumento de una ecuacion. */
  EstArgEc *ArgActEc;	/* Argumento actual de una ecuacion. */
  int SoloVar;

  aborta_si(MatEcxArgIncorr(MatOp))
  if (MatOp->EcOrig == NULL)
    return FALSE;
  EcAct= PrimEc= MatOp->EcOrig;
  ArgActEc= PrimArgEc= MatOp->ArgEcOrig;
  do
  { if (EcAct->Premisas == NULL)
    { SoloVar= TRUE;
      do
      { if (idclass(idref(ArgActEc->NodoArg)) == opn_id)
	{ SoloVar= FALSE;
	  break;
	}
	ArgActEc= ArgActEc->SigArg;
      } while (ArgActEc != PrimArgEc);
      if (SoloVar)
	return TRUE;
    }
    ArgActEc= PrimArgEc= PrimArgEc->SigEc;
    EcAct= EcAct->SigEc;
  } while (EcAct != PrimEc);
  return FALSE;
}

static void GenReglasIdPat(MatDato, PatDato, ComPatPrev)
/* Genera un conjunto de reglas con identico patron. */
EstEcxArg *MatDato;	/* Matriz dato. */
EstPat *PatDato;	/* Patron dato. */
int ComPatPrev;		/* Elementos comunes con el patron previo. */
{ EstEcxArg Cur;	/* Cursor de la matriz final. */
  EstManEc *PrimEc;	/* Primera ecuacion. */
  EstManEc *EcAct;	/* Ecuacion actual. */
  int EsPrimReg= TRUE;	/* Indica si es la primera regla. */

  aborta_si(MatEcxArgIncorr(MatDato) ||
	    MatDato->EcOrig == NULL ||
	    PatIncorr(PatDato) ||
	    ComPatPrev > 0 ||
	    PatDato->NumElem < -ComPatPrev)
  /* Generacion de las reglas condicionales. */
  PrimEc= Cur.EcOrig= MatDato->EcOrig;
  Cur.ArgEcOrig= MatDato->ArgEcOrig;
  do
  { EcAct= Cur.EcOrig->SigEc;
    if (EcAct->Premisas == NULL)
    { Cur.EcOrig= Cur.EcOrig->SigEc;
      Cur.ArgEcOrig= Cur.ArgEcOrig->SigEc;
      continue;
    }
    EscRegla(EcAct, PatDato, ComPatPrev);
    SuprEcMat(&Cur);
    if (EsPrimReg)
    { EsPrimReg= FALSE;
      ComPatPrev= PatDato->NumElem;
    }
  } while (EcAct != PrimEc);
  PrimEc= MatDato->EcOrig= Cur.EcOrig;
  MatDato->ArgEcOrig= Cur.ArgEcOrig;
  if (PrimEc != NULL)
  { /* Generacion de una regla incondicional. */
    EscRegla(PrimEc->SigEc, PatDato, ComPatPrev);
    SuprMatEcxArg(MatDato);
  }
}

static void GenReglasOrd(MatDato, PatDato, ComPatPrev)
/* Genera un conjunto de reglas de forma ordenada. */
EstEcxArg *MatDato;	/* Matriz dato. */
EstPat *PatDato;	/* Patron dato. */
int ComPatPrev;		/* Elementos comunes con el patron previo. */
{ EstArgEc *PrimArgEc;	/* Primer argumento de una ecuacion. */
  EstArgEc *ArgActEc;	/* Argumento actual de una ecuacion. */
  EstArgEc *ArgAntEc;	/* Argumento anterior de una ecuacion. */
  int NumEc= 0; 	/* Numero de ecuaciones. */
  EstArgEc *ArgEcAct;	/* Argumento en la ecuacion actual. */
  EstArgEc *ArgAntSel;	/* Argumento anterior al seleccionado. */
  int NumMaxOp= 0;	/* Numero maximo de operaciones. */
  int NumActOp; 	/* Numero actual de operaciones. */
  EstEcxArg MatPrinc;	/* Matriz principal. */
  EstEcxArg Submat;	/* Submatriz. */
  int EsPrimPat= TRUE;	/* Indica si es el primer patron. */

  aborta_si(MatEcxArgIncorr(MatDato) ||
	    MatDato->EcOrig == NULL ||
	    PatIncorr(PatDato) ||
	    ComPatPrev > 0 ||
	    PatDato->NumElem < -ComPatPrev)
  /* Se cuentan las ecuaciones de la matriz dato. */
  ArgEcAct= PrimArgEc= MatDato->ArgEcOrig;
  do
  { ++NumEc;
    ArgEcAct= ArgEcAct->SigEc;
  } while (ArgEcAct != PrimArgEc);
  /* Se selecciona la columna con mayor numero de operaciones. */
  ArgActEc= PrimArgEc;
  do
  { ArgAntEc= ArgActEc;
    ArgActEc= ArgActEc->SigArg;
    NumActOp= 0;
    ArgEcAct= ArgActEc;
    /* Se cuentan las operaciones de una columna. */
    do
    { if (idclass(idref(ArgEcAct->NodoArg)) == opn_id)
	++NumActOp;
      ArgEcAct= ArgEcAct->SigEc;
    } while (ArgEcAct != ArgActEc);
    if (NumActOp > NumMaxOp)
    { NumMaxOp= NumActOp;
      ArgAntSel= ArgAntEc;
    }
  } while ((NumMaxOp != NumEc) && (ArgActEc != PrimArgEc));
  /* Comienza la generacion de codigo. */
  if (NumMaxOp == 0)
  { /* Solo hay variables en la matriz dato. */
    GenReglasIdPat(MatDato, PatDato, ComPatPrev);
    return;
  }
  /* Se inicia la generacion de submatrices. */
  MatPrinc.EcOrig= MatDato->EcOrig;
  MatPrinc.ArgEcOrig= ArgAntSel;
  Submat.EcOrig= NULL;
  Submat.ArgEcOrig= NULL;
  while (NumMaxOp > 0)
  { /* Generacion de una submatriz. */
    EstArgEc *PrincArgSel;	/* Principio del argumento
				   seleccionado. */
    EstArgEc *ArgSelAct;	/* Argumento seleccionado actual. */
    EstArgEc *ArgSelSig;	/* Argumento seleccionado siguiente. */
    EstEcxArg Cur;		/* Cursor de la submatriz. */
    TNODE *IdOp;
    int ValIdRefOp;
    TNODE *IdArg;

    /* Se copian ecuaciones hasta que una tenga una operacion. */
    ArgSelAct= PrincArgSel= MatPrinc.ArgEcOrig->SigArg;
    for (;;)
    { ArgSelAct= ArgSelAct->SigEc;
      if (idclass(idref(ArgSelAct->NodoArg)) == value_id)
	CopiaEcMat(&MatPrinc, &Submat);
      else
	break;
    }
    /* Se mueve la ecuacion encontrada. */
    IdOp= ArgSelAct->NodoArg;
    ValIdRefOp= idref(IdOp);
    Cur.EcOrig= Submat.EcOrig;
    Cur.ArgEcOrig= Submat.ArgEcOrig;
    ArgSelSig= ArgSelAct->SigEc;
    MueveEcMat(&MatPrinc, &Cur);
    --NumMaxOp;
    /* Se buscan ecuaciones con esa operacion o una variable. */
    while (ArgSelAct != PrincArgSel)
    { ArgSelAct= ArgSelSig;
      ArgSelSig= ArgSelSig->SigEc;
      if (idclass(idref(ArgSelAct->NodoArg)) == value_id)
      { CopiaEcMat(&MatPrinc, &Cur);
	continue;
      }
      if (idref(ArgSelAct->NodoArg) == ValIdRefOp)
      { MueveEcMat(&MatPrinc, &Cur);
	--NumMaxOp;
	continue;
      }
      MatPrinc.EcOrig= MatPrinc.EcOrig->SigEc;
      MatPrinc.ArgEcOrig= MatPrinc.ArgEcOrig->SigEc;
    }
    if (Submat.EcOrig == NULL)
    { Submat.EcOrig= Cur.EcOrig;
      Submat.ArgEcOrig= Cur.ArgEcOrig;
    }
    /* Se agrega al patron un elemento de tipo operacion. */
    if (EsPrimPat)
      AgrElemPat(PatDato, (EstElemPat *) NULL);
    PatDato->UltElem->Ref= IdOp;
    PatDato->UltElem->Tipo= Operacion;
    /* Sustitucion de la operacion por sus argumentos. */
    IdArg= PrimArgOp(IdOp);
    if (IdArg == NULL)
      /* Operacion sin argumentos. */
      if (Submat.ArgEcOrig->SigArg == Submat.ArgEcOrig)
	/* Ultima columna de la matriz. */
	GenReglasIdPat(&Submat, PatDato, ComPatPrev);
      else
      { /* Quedan mas columnas en la matriz. */
	SuprArgMat(&Submat);
	GenReglasOrd(&Submat, PatDato, ComPatPrev);
      }
    else
    { /* Operacion con argumentos. */
      EstArgEc *ArgPrimEc;	/* Argumento en la primera ecuacion. */
      EstArgEc *ArgEcAct;	/* Argumento en la ecuacion actual. */
      EstArgEc *ArgAgrAct;	/* Argumento agregado actual. */
      EstArgEc *UltArgAgr;	/* Ultimo argumento agregado. */

      /* Agregacion de columnas a la matriz. */
      Cur.EcOrig= Submat.EcOrig->SigEc;
      Cur.ArgEcOrig= Submat.ArgEcOrig->SigEc->SigArg;
      ArgPrimEc= Cur.ArgEcOrig;
      for (;;)
      { Cur.ArgEcOrig->NodoArg= IdArg;
	IdArg= SigArgOp(IdArg);
	if (IdArg == NULL)
	  break;
	AgrArgMat(&Cur);
      }
      /* Relleno de las columnas con argumentos o pseudovariables. */
      ArgEcAct= ArgPrimEc;
      UltArgAgr= Cur.ArgEcOrig;
      for (;;)
      { ArgEcAct= ArgEcAct->SigEc;
	if (ArgEcAct == ArgPrimEc)
	  break;
	ArgAgrAct= ArgEcAct;
	UltArgAgr= UltArgAgr->SigEc;
	IdOp= ArgEcAct->NodoArg;
	if (idclass(idref(IdOp)) == value_id)
	  while (ArgAgrAct != UltArgAgr)
	  { ArgAgrAct= ArgAgrAct->SigArg;
	    ArgAgrAct->NodoArg= IdOp;
	  }
	else
	{ IdArg= PrimArgOp(IdOp);
	  ArgAgrAct->NodoArg= IdArg;
	  while (ArgAgrAct != UltArgAgr)
	  { ArgAgrAct= ArgAgrAct->SigArg;
	    IdArg= SigArgOp(IdArg);
	    ArgAgrAct->NodoArg= IdArg;
	  }
	}
      }
      Submat.ArgEcOrig= UltArgAgr;
      GenReglasOrd(&Submat, PatDato, ComPatPrev);
    }
    if (EsPrimPat)
    { EsPrimPat= FALSE;
      ComPatPrev= -PatDato->NumElem;
    }
  }
  /* Se agrega al patron un elemento de tipo valor (si procede). */
  MatDato->EcOrig= MatPrinc.EcOrig;
  if (MatPrinc.EcOrig != NULL)
  { MatDato->ArgEcOrig= MatPrinc.ArgEcOrig->SigArg;
    PatDato->UltElem->Tipo= Valor;
    GenReglasOrd(MatDato, PatDato, ComPatPrev);
  }
  else
    MatDato->ArgEcOrig= MatPrinc.ArgEcOrig;
  SuprElemPat(PatDato);
}

static void GenOpConArg(OpDato)
/* Genera una operacion con argumentos. */
EstManOp *OpDato;	/* Operacion dato. */
{ static EstPat *PatDato= NULL;
  TNODE *PrimIdArg;
  TNODE *IdArg;
  int NumArg;
  int HayConstrArb;
  char *c;

  aborta_si(OpDato == NULL ||
	    OpDato->Tipo != OpConArg)
  if (PatDato == NULL)
  { PatDato= AsigMem(EstPat, 1);
    InicPat(PatDato);
  }
  /* Generacion de las declaraciones. */
  if (OpcProg.InsCom > 0)
  { Sangra();
    EscComOp(OpDato->Nodo);
  }
  Sangra();
  (void) printf("%s %s ", BEGIN_OPERATION_DEF, OpDato->Id);
  HayConstrArb= !OpReescSiempre(&OpDato->u.MatEc);
  if (HayConstrArb)
    if (OpDato->u.MatEc.EcOrig == NULL)
      (void) printf("%s", BUILD);
    else
      (void) printf("%s", GENERAL);
  else
    (void) printf("%s", REWRITE);
  (void) printf(" %d ", ClTab(sort(iddec(OpDato->Nodo)))->Num);
  IdArg= PrimIdArg= gt_fs(gt_rb(gt_ft(gt_ft(OpDato->Nodo))));
  for (NumArg= 1;; ++NumArg)
    if ((IdArg= gt_rb(IdArg)) == NULL)
      break;
  (void) printf("%d", NumArg);
  IdArg= PrimIdArg;
  do
    (void) printf(" %d", ClTab(idref(IdArg))->Num);
  while ((IdArg= gt_rb(IdArg)) != NULL);
  (void) printf("\n");
  IncSang();
  /* Anotacion "partial". */
  c= partial(iddec(OpDato->Nodo));
  if (c != NULL)
  { char Buf[BUFSIZ];
    char *s;

    s= name(iddec(OpDato->Nodo));
    if (s == NULL)
      s= lexv(iddec(OpDato->Nodo));
    (void) sprintf(Buf, "%s %d %s", s, line(OpDato->Nodo),
				       file(OpDato->Nodo));
    EscAnot(PARTIAL_ANNOTATION, Buf, c);
  }
  /* Generacion de la parte de reescritura. */
  if (OpDato->u.MatEc.EcOrig != NULL)
    GenReglasOrd(&OpDato->u.MatEc, PatDato, 0);
  aborta_si(OpDato->u.MatEc.EcOrig != NULL ||
	    PatDato->NumElem != 0)
  if (HayConstrArb)
  { /* Generacion de la parte de construccion del arbol. */
    Sangra();
    (void) printf("%s %d %d", BUILD, OpDato->Num,
		  ClTab(sort(iddec(OpDato->Nodo)))->Num);
    if (nonconstructor(iddec(OpDato->Nodo)) != STR_ERR)
    { char *s;

      s= name(iddec(OpDato->Nodo));
      if (s == NULL)
	s= lexv(iddec(OpDato->Nodo));
      (void) printf(" %s %s %s %d %s", ANNOTATION, FAIL_ANNOTATION,
				       s, line(OpDato->Nodo),
					  file(OpDato->Nodo));
    }
    (void) printf("\n");
  }
  DecSang();
  Sangra();
  (void) printf("%s\n", END_OPERATION_DEF);
}

void GenDefTipo()
/* Genera la definicion del tipo de datos. */
{ EstManOp *p;

  /* Definicion de operaciones. */
  for (p= PrimOpTab(); p != NULL; p= p->Sig)
    if (v_extern(iddec(p->Nodo)) == STR_ERR)
    { (void) printf("\n");
      if (p->Tipo == OpSinArg)
	GenOpSinArg(p);
      else
	GenOpConArg(p);
    }
}
