/***********************************
  (C) Copyright 1992-1993; dit/upm
   Distributed under the conditions stated in the
   TOPO General Public License (see file LICENSE)
 ***********************************
 $Log: tabop.c,v $
 * Revision 1.16  1995/01/17  09:50:13  lotos
 * bug fix: variable initialization
 *
 * Revision 1.15  1993/06/10  14:00:13  lotos
 * new annotation CALL
 *
 * Revision 1.14  1993/03/24  17:51:24  lotos
 * remove options -u and -s, that go into glad
 *
 * Revision 1.13  1993/01/18  18:12:15  lotos
 * distribution issues
 *
 * Revision 1.12  1992/12/02  10:58:33  lotos
 * modify the meaning of -u and -s
 *
 * Revision 1.11  1992/11/17  18:43:18  lotos
 * uses color c_cui rather than c_ui
 *
 * Revision 1.10  1992/10/14  17:43:33  lotos
 * forget about ophuscation
 *
 * Revision 1.9  1992/09/02  15:44:50  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.8  92/01/30  18:10:29  lotos
 * better error reporting
 * 
 * Revision 1.7  92/01/14  15:25:14  lotos
 * distribution issues
 * 
 * Revision 1.6  92/01/13  19:24:40  lotos
 * adaptec to ophuscate
 * 
 * Revision 1.5  91/11/14  20:21:15  lotos
 * fixed a little bug
 * when all equations were of external operations
 * 
 * Revision 1.4  91/10/02  16:49:34  lotos
 * color sort is now in the AT
 * 
 * Revision 1.3  91/05/03  19:51:08  lotos
 * system V adaptation
 * 
 * Revision 1.2  91/04/19  21:15:48  lotos
 * accept specs without data types
 * 
 * Revision 1.1  91/02/06  20:15:06  lotos
 * Initial revision
 * 
 ***********************************/

#ifndef lint
static char rcsid[]= "$Id: tabop.c,v 1.16 1995/01/17 09:50:13 lotos Exp $";
#endif

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

     "tabop.o": modulo de gestion de una tabla de operaciones.

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

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


/* Macros de estado de la tabla. */
#define TAB_NULA	0
#define TAB_INIC	1
#define TAB_COMPL	2


/* Tabla de operaciones. */
EstTabOp _TabOp= { NULL, -1, 0, TAB_NULA, NULL, NULL, NULL, NULL };


static void IntroClTab(NodoSorts)
/* Introduce las clases en la tabla. */
TNODE *NodoSorts;
{ TNODE  *NodoSortIdComm, *NodoId;
  EstManOp *p, **q;

  aborta_si(_TabOp.Estado != TAB_NULA ||
	    NodoSorts == NULL ||
  	    NodoSorts->type != tsorts)
  for (NodoSortIdComm= gt_fs(NodoSorts), q= &_TabOp.LisCl;
       NodoSortIdComm != NULL;
       NodoSortIdComm= gt_rb(NodoSortIdComm))
  { NodoId= gt_fs(NodoSortIdComm);
    aborta_si(NodoId == NULL ||
	      NodoId->type != tsort_identifier)
    /* Creacion y rellenado del nodo. */
    p= AsigMem(EstManOp, 1);
    p->Num= 0;
    { char Buf[BUFSIZ];

      (void) sprintf(Buf, "%s%d", SORT_IDENTIFIER_ROOT,
		     v_cui(iddec(NodoId)));
      p->Id= AsigMem(char, strlen(Buf) + 1);
      (void) strcpy(p->Id, Buf);
    }
    p->Nodo= NodoId;
    p->Tipo= Clase;
    p->u.TramoOp.Princ= NULL;
    p->u.TramoOp.Fin= NULL;
    /* Colocacion del nodo en la lista de clases. */
    *q= p;
    q= &p->Sig;
    /* Introduccion del nodo en la tabla. */
    _TabOp.Elem[iddec(NodoId)]= p;
  }
  *q= NULL;
}

static void IntroOpTab(NodoOps)
/* Introduce las operaciones en la tabla. */
TNODE *NodoOps;
{ TNODE *NodoOp,* NodoOpDes, *NodoId;
  EstManOp *p, **q;

  aborta_si(_TabOp.Estado != TAB_NULA ||
	    NodoOps == NULL ||
  	    NodoOps->type != toperations)
  for (NodoOp= gt_fs(NodoOps), q= &_TabOp.LisOp;
       NodoOp != NULL;
       NodoOp= gt_rb(NodoOp))
    for (NodoOpDes= gt_fs(gt_fs(NodoOp));
	 NodoOpDes != NULL;
	 NodoOpDes= gt_rb(NodoOpDes))
    { NodoId= gt_fs(NodoOpDes);
      aborta_si(NodoId == NULL ||
		NodoId->type != toperation_identifier)
      /* Creacion y rellenado del nodo. */
      p= AsigMem(EstManOp, 1);
      p->Num= 0;
      if (call(iddec(NodoId)) == NULL)
	p->Id= name(iddec(NodoId));
      else
	p->Id= NULL;
      if (p->Id == NULL)
      { char Buf[BUFSIZ];

	(void) sprintf(Buf, "%s%d", OPERATION_IDENTIFIER_ROOT,
		       v_cui(iddec(NodoId)));
	p->Id= AsigMem(char, strlen(Buf) + 1);
	(void) strcpy(p->Id, Buf);
      }
      p->Nodo= NodoId;
      if (class(NodoOp) == const_opn)
      { p->Tipo= OpSinArg;
	p->u.LisEc.EcOrig= NULL;
      }
      else
      { p->Tipo= OpConArg;
	p->u.MatEc.ArgEcOrig= NULL;
	p->u.MatEc.EcOrig= NULL;
      }
      /* Colocacion del nodo en la lista de operaciones. */
      *q= p;
      q= &p->Sig;
      /* Introduccion del nodo en la tabla. */
      _TabOp.Elem[iddec(NodoId)]= p;
    }
  *q= NULL;
}

static void IntroEcTab(NodoEqs)
/* Introduce las ecuaciones en la tabla. */
TNODE *NodoEqs;
{ TNODE *NodoEqList, *NodoEq;
  TNODE *p, *q;
  EstManEc PrincEc;		/* Principio de las ecuaciones. */
  EstManEc *EcAnt;		/* Ecuacion anterior. */
  EstManEc *EcAct= (&PrincEc);	/* Ecuacion actual. */

  aborta_si(_TabOp.Estado != TAB_NULA ||
	    NodoEqs == NULL ||
	    NodoEqs->type != tequations)
  NodoEqList= gt_fs(gt_ls(NodoEqs));
  aborta_si(NodoEqList== NULL ||
	    NodoEqList->type != tequation_list)
  do
  { NodoEq= gt_fs(gt_ls(NodoEqList));
    aborta_si(NodoEq== NULL ||
	      NodoEq->type != tequation)
    do
    { p= gt_fs(NodoEq);
      aborta_si(p == NULL ||
		p->type != tpremisses &&
		p->type != tsimple_equation)
      if (p->type == tpremisses)
      { q= gt_fs(p);
	p= gt_rb(p);
      }
      else
        q= NULL;
      if (v_extern(idref(OpRaizMEc(gt_fs(p)))) != STR_ERR)
	continue;
      /* Creacion y rellenado del nodo. */
      EcAnt= EcAct;
      EcAct= AsigMem(EstManEc, 1);
      EcAct->Premisas= q;
      EcAct->EcSimple= p;
      /* Colocacion del nodo en la lista de ecuaciones. */
      EcAnt->SigEc= EcAct;
    } while ((NodoEq= gt_rb(NodoEq)) != NULL);
  } while ((NodoEqList= gt_rb(NodoEqList)) != NULL);
  EcAct->SigEc= NULL;
  _TabOp.LisEc= PrincEc.SigEc;
}

void InicTabOp(NodoSpec)
/* Inicializa la tabla de operaciones. */
TNODE *NodoSpec;
{ TNODE *p;
  int i;

  aborta_si(_TabOp.Estado != TAB_NULA ||
	    NodoSpec == NULL)
  if (NodoSpec->type == tspecification)
    for (p= gt_fs(NodoSpec);
	 p->type != tdata_type_definitions;
	 p= gt_rb(p))
      ;
  else
    p= NodoSpec;
  aborta_si(p == NULL ||
	    p->type != tdata_type_definitions)
  p= gt_fs(p);
  if (p != NULL)		/* Hay tipos de datos? */
  { p= gt_ls(gt_ls(p));
    aborta_si(p == NULL ||
	      p->type != tp_specification)
  }
  /* Creacion de la tabla. */
  _TabOp.Max= _TabOp.MaxId= luid(NodoSpec) - 1;
  _TabOp.Elem= AsigMem(EstManOp *, _TabOp.Max + 1);
  for (i= _TabOp.Max; i >= 0; --i)
    _TabOp.Elem[i]= NULL;
  /* Inicializacion de la tabla. */
  _TabOp.Espec= NodoSpec;
  if ((p= gt_fs(p)) != NULL)		/* <sorts>. */
  { IntroClTab(p);
    if ((p= gt_rb(p)) != NULL)		/* <operations>. */
    { IntroOpTab(p);
      if ((p= gt_rb(p)) != NULL)	/* <equations>. */
	IntroEcTab(p);
    }
  }
  _TabOp.Estado= TAB_INIC;
}

void ComplTabOp()
/* Completa la tabla de operaciones. */
{ EstManOp *p;
  EstManOp *q, **qt;
  EstManEc *r, *rl;
  EstArgEc *s, *si;
  TNODE *IdOp, *IdArg;

  aborta_si(_TabOp.Estado != TAB_INIC)
  /* Revision de la tabla. */
  if (_TabOp.MaxId > _TabOp.Max)
  { del_luid(_TabOp.Espec);
    add_luid(_TabOp.Espec, _TabOp.MaxId + 1);
  }
  /* Agrupacion de las operaciones en tramos. */
  for (q= PrimOpTab(); q != NULL; q= q->Sig)
  { p= ClTab(sort(iddec(q->Nodo)));
    if (p->u.TramoOp.Princ == NULL)
      p->u.TramoOp.Fin= p->u.TramoOp.Princ= q;
    else
      p->u.TramoOp.Fin= p->u.TramoOp.Fin->Sig= q;
  }
  /* Agrupacion de las ecuaciones por operaciones. */
  for (r= PrimEcTab(); r != NULL; r= rl)
  { IdOp= OpRaizMEc(gt_fs(r->EcSimple));
    aborta_si(v_extern(idref(IdOp)) != STR_ERR)
    q= OpTab(idref(IdOp));
    rl= r->SigEc;
    if (q->Tipo == OpSinArg)
      if (q->u.LisEc.EcOrig == NULL)
	InicLisEc(&q->u.LisEc, r);
      else
	AgrEcLis(&q->u.LisEc, r);
    else
      if (q->u.MatEc.EcOrig == NULL)
      { InicMatEcxArg(&q->u.MatEc, r);
	IdArg= PrimArgOp(IdOp);
	for (;;)
	{ q->u.MatEc.ArgEcOrig->NodoArg= IdArg;
	  if ((IdArg= SigArgOp(IdArg)) == NULL) break;
	  AgrArgMat(&q->u.MatEc);
	}
      }
      else
      { AgrEcMat(&q->u.MatEc, r);
	s= si= q->u.MatEc.ArgEcOrig;
	IdArg= PrimArgOp(IdOp);
	do
	{ s= s->SigArg;
	  s->NodoArg= IdArg;
	  IdArg= SigArgOp(IdArg);
	} while (s != si);
      }
  }
  _TabOp.LisEc= NULL;
  /* Numeracion de clases, y enlace de tramos de operaciones. */
  for (p= PrimClTab(),
       qt= &_TabOp.LisOp; p != NULL; p= p->Sig)
  { p->Num= -v_cui(iddec(p->Nodo));
    if ((q= p->u.TramoOp.Princ) != NULL)
    { *qt= q;
      qt= &p->u.TramoOp.Fin->Sig;
    }
  }
  *qt= NULL;
  /* Numeracion de operaciones. */
  for (q= PrimOpTab(); q != NULL; q= q->Sig)
    q->Num= v_cui(iddec(q->Nodo));
  _TabOp.Estado= TAB_COMPL;
}

TNODE *_RaizEspec()
/* Devuelve el nodo raiz de la especificacion. */
{
  aborta_si(_TabOp.Estado == TAB_NULA)
  return _TabOp.Espec;
}

int _UltIdTab()
/* Devuelve el ultimo identificador de la tabla. */
/* (Su numero de identificacion unico).          */
{
  aborta_si(_TabOp.Estado == TAB_NULA)
  return _TabOp.MaxId;
}

void _RegIdTab()
/* Registra un nuevo identificador en la tabla. */
{
  aborta_si(_TabOp.Estado == TAB_NULA)
  ++_TabOp.MaxId;
}

EstManOp *_OpTab(Pos)
/* Devuelve una operacion de la tabla. */
int Pos;
{
  aborta_si(_TabOp.Estado == TAB_NULA ||
	    Pos < 0 ||
	    Pos > _TabOp.Max ||
	    _TabOp.Elem[Pos] == NULL ||
	    (_TabOp.Estado == TAB_INIC? _TabOp.Elem[Pos]->Num != 0
				      : _TabOp.Elem[Pos]->Num <= 0) ||
	    _TabOp.Elem[Pos]->Tipo != OpSinArg &&
	    _TabOp.Elem[Pos]->Tipo != OpConArg)
  return _TabOp.Elem[Pos];
}

EstManOp *_PrimOpTab()
/* Devuelve la primera operacion de la tabla. */
{
  aborta_si(_TabOp.Estado == TAB_NULA)
  return _TabOp.LisOp;
}

EstManOp *_ClTab(Pos)
/* Devuelve una clase de la tabla. */
int Pos;
{
  aborta_si(_TabOp.Estado == TAB_NULA ||
	    Pos < 0 ||
	    Pos > _TabOp.Max ||
	    _TabOp.Elem[Pos] == NULL ||
	    (_TabOp.Estado == TAB_INIC? _TabOp.Elem[Pos]->Num != 0
				      : _TabOp.Elem[Pos]->Num >= 0) ||
	    _TabOp.Elem[Pos]->Tipo != Clase)
  return _TabOp.Elem[Pos];
}

EstManOp *_PrimClTab()
/* Devuelve la primera clase de la tabla. */
{
  aborta_si(_TabOp.Estado == TAB_NULA)
  return _TabOp.LisCl;
}

EstManEc *_PrimEcTab()
/* Devuelve la primera ecuacion de la tabla. */
{
  aborta_si(_TabOp.Estado == TAB_NULA)
  return _TabOp.LisEc;
}
