/***********************************
  (C) Copyright 1992-1993; dit/upm
   Distributed under the conditions stated in the
   TOPO General Public License (see file LICENSE)
 ***********************************
 $Log: LDM.c,v $
 * Revision 1.12  1993/05/28  10:41:43  lotos
 * opcion -c tiene niveles
 *
 * Revision 1.11  1993/01/18  18:12:15  lotos
 * distribution issues
 *
 * Revision 1.10  1992/10/14  17:50:18  lotos
 * sort annotation added
 *
 * Revision 1.9  1992/10/14  17:43:30  lotos
 * forget about ophuscation
 *
 * Revision 1.8  1992/09/02  15:44:49  lotos
 * new option to remove externa annotations
 * new option to print and label the equations
 * new debugging options: save modified CAST
 * overall debugging and improvements
 *
 * Revision 1.7  92/01/14  15:25:13  lotos
 * distribution issues
 * 
 * Revision 1.6  92/01/13  19:24:37  lotos
 * adaptec to ophuscate
 * 
 * Revision 1.5  91/11/20  13:15:44  lotos
 * multiple line annotations may be empty
 * 
 * Revision 1.4  91/10/02  16:49:27  lotos
 * color sort is now in the AT
 * 
 * Revision 1.3  91/05/03  19:51:06  lotos
 * system V adaptation
 * 
 * Revision 1.2  91/04/11  18:33:25  lotos
 * cosmetics
 * 
 * Revision 1.1  91/02/06  20:13:29  lotos
 * Initial revision
 * 
 ***********************************/

#ifndef lint
static char rcsid[]= "$Id: LDM.c,v 1.12 1993/05/28 10:41:43 lotos Exp $";
#endif

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

     "LDM.o": modulo basico para generar el lenguaje de LDM.

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

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


void EscComCl(IdCl)
/* Escribe un comentario acerca de una clase. */
TNODE *IdCl;	/* Puntero al nodo con la clase. */
{
  aborta_si(IdCl == NULL ||
	    IdCl->type != tsort_identifier ||
	    gt_ft(IdCl) == NULL ||
	    gt_ft(IdCl)->type != tsort_id_comm)
  (void) printf("%s %s\n", COMMENT, lexv(iddec(IdCl)));
}

void EscComOp(IdOp)
/* Escribe un comentario acerca de una operacion. */
TNODE *IdOp;	/* Puntero al nodo con la operacion. */
{ TNODE *p, *q;

  aborta_si(IdOp == NULL ||
	    IdOp->type != toperation_identifier ||
	    gt_ft(IdOp) == NULL ||
	    gt_ft(IdOp)->type != toperation_descriptor)
  (void) printf("%s ", COMMENT);
  /* Escritura del nombre de la operacion. */
  if (infix(iddec(IdOp)) == 0)
    (void) printf("_%s_", lexv(iddec(IdOp)));
  else
    (void) printf("%s", lexv(iddec(IdOp)));
  (void) printf(":");
  /* Escritura de la clase de los argumentos de la operacion. */
  p= gt_rb(gt_ft(gt_ft(IdOp)));
  if (p->type == targument_list)
  { for (q= gt_fs(p);; (void) printf(","))
    { (void) printf(" %s", lexv(idref(q)));
      q= gt_rb(q);
      if (q == NULL)
	break;
    }
    p= gt_rb(p);
  }
  /* Escritura de la clase del resultado de la operacion. */
  (void) printf(" -> ");
  (void) printf("%s\n", lexv(idref(p)));
}

static void EscVarComRegla(IdVar, EtiqVar)
/* Escribe una variable dentro de un comentario sobre una regla. */
TNODE *IdVar;	/* Puntero a la variable. */
int EtiqVar;	/* Indica si hay que etiquetar la variable. */
{
  aborta_si(NoEstaEnEc(IdVar) ||
	    idclass(idref(IdVar)) != value_id)
  (void) printf("%s", lexv(idref(IdVar)));
  if (EtiqVar)
    (void) printf("[%d]", idref(IdVar));
}

static void EscExpComRegla(IdRaiz, EtiqVar)
/* Escribe una expresion dentro de un comentario sobre una regla. */
TNODE *IdRaiz;	/* Puntero a la raiz de la expresion. */
int EtiqVar;	/* Indica si hay que etiquetar variables. */
{ TNODE *IdArg;

  IdArg= PrimArgOp(IdRaiz);
  if (IdArg == NULL)
  { /* Operacion sin argumentos o variable. */
    if (idclass(idref(IdRaiz)) == value_id)
      EscVarComRegla(IdRaiz, EtiqVar);
    else
      (void) printf("%s", lexv(idref(IdRaiz)));
  }
  else
  { /* Operacion con argumentos. */
    if (infix(idref(IdRaiz)) == 0)
    { /* Operacion con notacion infija. */
      for (;;)
      { if (infix(idref(IdArg)) == 0)
	  (void) printf("(");
	EscExpComRegla(IdArg, EtiqVar);
	if (infix(idref(IdArg)) == 0)
	  (void) printf(")");
	IdArg= SigArgOp(IdArg);
	if (IdArg == NULL)
	  break;
	(void) printf(" %s ", lexv(idref(IdRaiz)));
      }
    }
    else
    { /* Operacion con notacion prefijo. */
      (void) printf("%s(", lexv(idref(IdRaiz)));
      for (;;)
      { EscExpComRegla(IdArg, EtiqVar);
	IdArg= SigArgOp(IdArg);
	if (IdArg == NULL)
	  break;
	(void) printf(", ");
      }
      (void) printf(")");
    }
  }
}

static void _EscComRegla(EcDato, EtiqVar)
/* Escribe una regla para incluir en un comentario. */
EstManEc *EcDato;	/* Ecuacion dato. */
int EtiqVar;		/* Indica si hay que etiquetar variables. */
{ TNODE *Premisa, *Miembro;

  aborta_si(EcDato == NULL)
  Premisa= EcDato->Premisas;
  if (Premisa != NULL)
  { /* Hay premisas en la ecuacion. */
    for (;;)
    { /* Miembro izquierdo de una premisa. */
      Sangra();
      (void) printf("%s ", LINE_QUOTE);
      Miembro= gt_fs(Premisa);
      EscExpComRegla(OpRaizMEc(Miembro), EtiqVar);
      (void) printf(" = ");
      /* Miembro derecho de la misma premisa. */
      Miembro= gt_rb(Miembro);
      EscExpComRegla(OpRaizMEc(Miembro), EtiqVar);
      if ((Premisa= gt_rb(Premisa)) == NULL)
	break;
      (void) printf(",\n");
    }
    (void) printf(" =>\n");
  }
  /* Miembro izquierdo de la ecuacion. */
  Sangra();
  (void) printf("%s ", LINE_QUOTE);
  Miembro= gt_fs(EcDato->EcSimple);
  EscExpComRegla(OpRaizMEc(Miembro), EtiqVar);
  (void) printf(" = ");
  /* Miembro derecho de la ecuacion. */
  Miembro= gt_rb(Miembro);
  EscExpComRegla(OpRaizMEc(Miembro), EtiqVar);
  (void) printf(" ;\n");
}

void EscComRegla(EcDato, EtiqVar)
/* Escribe un comentario acerca de una regla. */
EstManEc *EcDato;	/* Ecuacion dato. */
int EtiqVar;		/* Indica si hay que etiquetar variables. */
{
  aborta_si(EcDato == NULL)
  Sangra();
  (void) printf("%s\n", BEGIN_COMMENT);
  IncSang();
  _EscComRegla(EcDato, EtiqVar);
  DecSang();
  Sangra();
  (void) printf("%s\n", END_COMMENT);
}

void EscAnotRegla(EcDato)
/* Escribe una anotacion acerca de una regla. */
EstManEc *EcDato;	/* Ecuacion dato. */
{ EstManEc EcOrig;
  TNODE *RaizEc;

  aborta_si(EcDato == NULL)
  RaizEc= gt_ft(EcDato->EcSimple);
  if ((RaizEc= oveq(RaizEc)) != TND_ERR)
  { EcOrig.SigEc= NULL;
    EcOrig.Premisas= gt_fs(RaizEc);
    if (EcOrig.Premisas->type == tpremisses)
    { EcOrig.EcSimple= gt_rb(EcOrig.Premisas);
      EcOrig.Premisas= gt_fs(EcOrig.Premisas);
    }
    else
    { EcOrig.EcSimple= EcOrig.Premisas;
      EcOrig.Premisas= NULL;
    }
    EcDato= &EcOrig;
  }
  RaizEc= gt_ft(EcDato->EcSimple);
  Sangra();
  (void) printf("%s %s %d %d %s\n", BEGIN_ANNOTATION, RULE_ANNOTATION,
		eqno(RaizEc), line(RaizEc), file(RaizEc));
  IncSang();
  _EscComRegla(EcDato, FALSE);
  DecSang();
  Sangra();
  (void) printf("%s\n", END_ANNOTATION);
}

static void EscTexAnot(Tex)
/* Escribe el texto de una anotacion. */
char *Tex;
{ char *p;
  int l;

  aborta_si(Tex == NULL)
  for (;*Tex != '\0'; Tex= p)
  { p= strchr (Tex, '\n');
    if (p == NULL)
    { l= strlen(Tex);
      p= Tex + l;
    }
    else
      l= p++ - Tex;
    Sangra();
    (void) printf("%s %.*s\n", LINE_QUOTE, l, Tex);
  }
}

void EscAnot(IdAnot, CabAnot, TexAnot)
/* Escribe una anotacion. */
char *IdAnot;
char *CabAnot;
char *TexAnot;
{
  aborta_si(IdAnot == NULL ||
	    *IdAnot == '\0')
  aborta_si(CabAnot == NULL ||
	    TexAnot == NULL)
  Sangra();
  (void) printf("%s %s", BEGIN_ANNOTATION, IdAnot);
  if (*CabAnot != '\0')
    (void) printf(" %s", CabAnot);
  (void) printf("\n");
  IncSang();
  EscTexAnot(TexAnot);
  DecSang();
  Sangra();
  (void) printf("%s\n", END_ANNOTATION);
}

static int _EscRefExp(IdOp)
/* Escribe la referencia a una expresion (fragmento). */
TNODE *IdOp;	/* Puntero al nodo con la operacion. */
{ TNODE *p;
  int i;

  p= OpArg(IdOp);
  if (p == NULL)
    return FALSE;
  if (_EscRefExp(p))
    (void) printf(" ");
  for (p= PrimArgOp(p), i= 1; p != IdOp; ++i)
    p= SigArgOp(p);
  (void) printf("%d", i);
  return TRUE;
}

void EscRefExp(IdRaiz)
/* Escribe la referencia a una expresion. */
TNODE *IdRaiz;	/* Puntero a la raiz de la expresion. */
{ int ExpEsc;

  ExpEsc= _EscRefExp(IdRaiz);
  aborta_si(!ExpEsc)
}

void EscExp(IdRaiz)
/* Escribe una expresion. */
TNODE *IdRaiz;	/* Puntero a la raiz de la expresion. */
{ TNODE *IdArg;
  int i;

  if (idclass(idref(IdRaiz)) == value_id)
  { Sangra();
    (void) printf("%s %s %d\n", ANNOTATION, SORT_ANNOTATION,
		  ClTab(sort(idref(IdRaiz)))->Num);
    Sangra();
    (void) printf("%s ", VALUE_EVAL);
    EscRefExp(pvar(IdRaiz));
    if (OpcProg.InsCom > 1)
    { (void) printf(" %s ", COMMENT);
      EscVarComRegla(IdRaiz, TRUE);
    }
    (void) printf("\n");
  }
  else
  { for (IdArg= PrimArgOp(IdRaiz), i= 0; IdArg != NULL; ++i)
      IdArg= SigArgOp(IdArg);
    Sangra();
    (void) printf("%s ", OPERATION_EVAL);
    (void) printf("%s", OpTab(idref(IdRaiz))->Id);
    (void) printf(" %d\n", i);
    IncSang();
    for (IdArg= PrimArgOp(IdRaiz);
	 IdArg != NULL;
	 IdArg= SigArgOp(IdArg))
      EscExp(IdArg);
    DecSang();
  }
}

static void _EscPatron(UltElemPat)
/* Escribe un patron (fragmento). */
EstElemPat *UltElemPat;	/* Ultimo elemento del patron. */
{
  if (UltElemPat == NULL)
    return;
  aborta_si(UltElemPat->Ref == NULL ||
	    UltElemPat->Tipo != Operacion &&
            UltElemPat->Tipo != Valor)
  _EscPatron(UltElemPat->Ant);
  Sangra();
  if (UltElemPat->Tipo == Operacion)
    (void) printf("%s %d", OPERATION_MATCH,
		  OpTab(idref(UltElemPat->Ref))->Num);
  else
    (void) printf("%s", VALUE_MATCH);
  (void) printf(" ");
  EscRefExp(UltElemPat->Ref);
  if (OpcProg.InsCom > 0 && UltElemPat->Tipo == Operacion)
    (void) printf(" %s %s", COMMENT, lexv(idref(UltElemPat->Ref)));
  (void) printf("\n");
}

static void EscPatron(PatDato, ComPatPrev)
/* Escribe un patron. */
EstPat *PatDato;	/* Patron dato. */
int ComPatPrev;		/* Elementos comunes con el patron previo. */
{ int SimPatPrev;	/* Elementos similares con el patron previo. */

  aborta_si(PatIncorr(PatDato) ||
	    (ComPatPrev >= 0? PatDato->NumElem < ComPatPrev
			    : PatDato->NumElem < -ComPatPrev))
  Sangra();
  (void) printf("%s", BEGIN_PATTERN);
  SimPatPrev= ComPatPrev >= 0? 0: 1;
  if (ComPatPrev < 0)
    ComPatPrev= -ComPatPrev - 1;
  (void) printf(" %d %d\n", ComPatPrev, SimPatPrev);
  IncSang();
  _EscPatron(PatDato->UltElem);
  DecSang();
  Sangra();
  (void) printf("%s\n", END_PATTERN);
}

void EscRegla(EcDato, PatDato, ComPatPrev)
/* Escribe una regla. */
EstManEc *EcDato;	/* Ecuacion dato. */
EstPat *PatDato;	/* Patron dato. */
int ComPatPrev;		/* Elementos comunes con el patron previo. */
{ TNODE *Premisa;	/* Puntero a una premisa. */
  TNODE *MiemEc;	/* Puntero a un miembro de una ecuacion. */
  TNODE *PrimOpPrem;	/* Primera operacion de una premisa. */

  aborta_si(EcDato == NULL ||
	    PatIncorr(PatDato) ||
	    (ComPatPrev >= 0? PatDato->NumElem < ComPatPrev
			    : PatDato->NumElem < -ComPatPrev))
  Sangra();
  (void) printf("%s", BEGIN_RULE);
  if (OpcProg.EtiqReg)
    (void) printf(" %d", eqno(gt_ft(EcDato->EcSimple)));
  (void) printf("\n");
  IncSang();
  if (OpcProg.InsCom > 1)
    EscComRegla(EcDato, TRUE);
  EscPatron(PatDato, ComPatPrev);
  for (Premisa= EcDato->Premisas;
       Premisa != NULL;
       Premisa= gt_rb(Premisa))
  { Sangra();
    (void) printf("%s\n", BEGIN_CONDITION);
    IncSang();
    Sangra();
    MiemEc= gt_fs(Premisa);
    PrimOpPrem= OpRaizMEc(MiemEc);
    (void) printf("%s %s 2 %d\n", OPERATION_EVAL, EQUAL,
		  ClTab(sort(idref(PrimOpPrem)))->Num);
    IncSang();
    EscExp(PrimOpPrem);
    MiemEc= gt_rb(MiemEc);
    EscExp(OpRaizMEc(MiemEc));
    DecSang();
    DecSang();
    Sangra();
    (void) printf("%s\n", END_CONDITION);
  }
  Sangra();
  (void) printf("%s\n", BEGIN_REPLACEMENT);
  IncSang();
  MiemEc= gt_rb(gt_fs(EcDato->EcSimple));
  EscExp(OpRaizMEc(MiemEc));
  DecSang();
  Sangra();
  (void) printf("%s\n", END_REPLACEMENT);
  DecSang();
  Sangra();
  (void) printf("%s\n", END_RULE);
}
