/******************************************************
 *      basic.c: Lambda Beta to Ada/C compiler
 ******************************************************/
/***********************************
   (C) Copyright 1992-1993; dit/upm
   Distributed under the conditions stated in the
   TOPO General Public License (see file LICENSE)
 ***********************************
 $Log: basic.c,v $
 * Revision 1.9  1994/12/19  15:15:53  lotos
 * new convention for pieces
 *
 * Revision 1.8  1994/10/03  17:41:35  lotos
 * delete unused function INTelem
 * commented unused code
 *
 * Revision 1.7  1994/01/26  19:15:55  lotos
 * PC does not support filenames stating with aux, prn, etc.
 * son aux.c has been renamed into basic.c
 *
 * Revision 1.6  1993/10/19  19:19:42  lotos
 * ported to BSD/386
 *
 * Revision 1.5  1993/08/02  17:04:29  lotos
 * modificado los castings y tipados de las listas de puertas.
 * Se incrementa el garbage collector cada vez que se comparte
 *   una lista de puertas.
 * Adaptado al nuevo EPS (desaparece funcion get_gte).
 *
 * Revision 1.4  1993/06/16  16:09:08  lotos
 * omlbc.c is no longer a copy from omlbC
 * however, some changes try to keep as much paralelisme as it can
 *          with omlbC code
 * Change table generation
 * INTdup is now a define ('cause cIL was fixed)
 * Change generated code. (Ada for all construction).
 * Adapted to new file names (both input and output)
 * Prettier generated code
 * cleaned basic.c
 * cleaned swbus.h
 * fixed makefile. Only transform.c counter.{c|h} and omlb.cia
 *                 are common with omlbC
 *
 * Revision 2.5  1993/01/18  18:14:46  lotos
 * distribution issues
 *
 * Revision 2.4  1993/01/12  20:20:52  lotos
 * portability issues
 *
 * Revision 2.3  1993/01/11  18:46:29  lotos
 * use DELETE from conf.h
 *
 * Revision 2.2  1993/01/11  18:33:09  lotos
 * overall bug fixing
 * new variable specpar: # of parameters in the lotos spec
 * formal parameters in processes are not compacted any longer
 * reverse -i meaning
 * add -C to remove would-be-generated files
 * generates code for if and use annotations
 * it is valid to split into 1 piece (no effect, really)
 * remove tbil.hh, replaced by conf.h
 *
 * Revision 2.1  1992/11/17  17:37:29  lotos
 * variables are compacted per sort
 * split generated code into several files
 * generates *.hh
 * admit option to change basename
 * adapted to use c_cui's
 * modify sort tables
 * code generation is more rational (needs further polishing ...)
 * adapted to new data type conventions
 * adopt new naming convention
 * include var declaration list in light BUTs
 *
 * Revision 1.3  1992/11/17  17:12:02  lotos
 * added routines to handle unused variables
 * added routines to IT library to enhance its functionality
 *
 * Revision 1.2  1992/09/11  16:48:55  lotos
 * bug fixing
 *
 * Revision 1.1  1992/09/02  16:58:07  lotos
 * Initial revision
 *
 ***********************************/

#ifndef lint
static char rcsid[]= "$Id: basic.c,v 1.9 1994/12/19 15:15:53 lotos Exp $";
#endif

# include "swbus.h"

/* KJT 02/01/23: added function prototypes */
int unlink(const char *pathname);

PUBLIC int
id2ui (idx)
  CLR_TYPE idx;
{
  if ((ATable->data[(int)idx].value0 == (CLR_TYPE)TSORT) ||
      (ATable->data[(int)idx].value0 == (CLR_TYPE)TOPN))
    return (int)ATfind (ATable, (int)idx, c_cui)->value;
  return (int)ATfind (ATable, (int)idx, c_ui)->value;
}

PUBLIC int
id2sort (idx)
  CLR_TYPE idx;
{
  return (int)ATfind(ATable,(int)(ATfind(ATable,(int)(idx),c_sort)->value),c_cui)->value;
}

PUBLIC char*
emalloc (i)
  int i;
{
  char *p;

  p = malloc ((unsigned)i);
  if (p == NULL) {
    (void)fprintf (stderr, "%s: Out of memory\n", progname);
    exit (1);
  }
  return p;
}

PUBLIC FILE*
efopen (filename, mode)
  char* filename, *mode;
{
  FILE* fp;

  if ((fp= fopen (filename, mode)) == NULL) {
    (void) fprintf (stderr, "%s: cannot open file %s mode %s\n",
		    progname, filename, mode);
    exit (1);
  }
  return fp;
}

PUBLIC void
fatal_error (error, nfile, nline)
  char *error, *nfile;
  int  nline;
{
  (void)fprintf (stderr, "%s: %s in file %s at line %d\n",
		 progname, error, nfile, nline);
  exit (1);
}

/* hay_color search for a color c in the SONS of a list r */
/* Of course, if r is NULL, it return FALSE.              */
PUBLIC int
hay_color (c, r)
  int c;
  TNODE *r;
{
  for (r = gt_fs(r); r != NULL; r = gt_rb (r))
    if (find_attr (c, r) != NULL)
      return TRUE;
  return FALSE;
}

/* calculates the number of elements in array 'data', */
/* taking into account that 0 is the 'terminating'    */
/* elements. (it is not a legal value).               */
PUBLIC int
sizeIT (data)
  int *data;
{
  register int j = 0;

  for ( ; data[j] != 0; j++)
    ;
  return j;
}

/* concatenates two lists
 * by means of duplicating BOTH of them.
 * Elements of the second list which exist in the first one
 * are NOT duplicated (i.e., not included).
 */
PUBLIC INTlist
INTmerge (L1, L2)
    INTlist L1;
    INTlist L2;
{
  INTlist start, this, prev, slot;

  if (L1 == NULL)
    return L2;
  if (L2 == NULL)
    return L1;
  prev= NULL;
  for (this= L1; this != NULL; this= this->next) {
/*     slot= new ();
    slot->elt= this->elt;
 As new is not exported by INTlists.c next line substitutes it */
    slot = INTcons (this->elt, (INTlist)NULL);
    if (prev != NULL) {
      prev->next= slot;
      slot->cnt++;
    }
    else
      start= slot;
    prev= slot;
  }
  for (this= L2; this != NULL; this= this->next) {
    if (!INTIsIn (INThead (this), start)) {
/*       slot= new ();
      slot->elt= this->elt;
 As new is not exported by INTlists.c next line substitutes it */
      slot = INTcons (this->elt, (INTlist)NULL);
      if (prev != NULL) {
	prev->next= slot;
	slot->cnt++;
      }
      else
	start= slot;
      prev= slot;
    }
  }
  return start;
}

/* Returns the greater element in list L
 * Fails if 'L' is NULL
 */
PUBLIC int
INTmax (L)
  INTlist L;
{
  int max;

  assert (L != NULL);
  max = L->elt;
  for (L = L->next; L != NULL; L = L->next)
    if (L->elt > max)
      max = L->elt;
  return max;
}

/* Indicates if a value_exp is constant or not */
PUBLIC int
is_cte_ve (r)
  TNODE *r;
{
  assert (r->type == tvalue_exp);

  if (r->sons == NULL)
    return (idclass (takeclr (c_idref, r)) != TVAL); /* TOPN or TVAL */
  for (r = gt_fs (r); r != NULL; r = gt_rb (r))
    if (!is_cte_ve (r))
      return FALSE;
  return TRUE;
}

/*
PUBLIC int*
create_uvt ()
{
  register int *aux, i;

  aux = (int*)emalloc (lastVARnumber * sizeof (int));
  for (i = 0; i < lastVARnumber; i++)
    aux[i] = FALSE;
  return aux;
}

PUBLIC void
init_uvt (r)
  TNODE *r;
{
  int id;

  for (; r != NULL; r = gt_rb (r)) {
    if (r->type == tvalue_exp) {
      id = (int)takeclr (c_idref, r);
      if (idclass (id) != TOPN) {
	assert (id2ui (id) < lastVARnumber);
	used_var_tbl[id2ui(id)] = TRUE;
      }
    }
    init_uvt (r->sons);
  }
}
*/

/* It takes a list of variables identifiers and returns
 * the correspondant list of sorts unique identifiers
 * If vl is NULL, it returns NULL
 */
PUBLIC INTlist
varl2sortl (vl)
  INTlist vl;
{
  INTlist sl = NULL;

  for ( ; vl != NULL; vl = INTtail (vl))
    if (INThead (vl) != 0) /* a ANY SORT in a exit_exp gives a 0 idref */
      sl = INTcons (id2sort ((CLR_TYPE)INThead (vl)), sl);
  return INTrev (sl);
}

/* Calculates the length of a tvarsort.              */
/* It is calculated as the position of the last sort */
/* plus how many variables are of such sort.         */
PUBLIC int
vslength (l)
  tvarsort *l;
{
  if (l == NULL)
    return 0;
  for ( ; l->next != NULL; l = l->next)
    /* take care, it's empty */   ;

  return (l->pos + l->num);
}

/* Calculates the maximun length of all possible var list */
PUBLIC int
totallength ()
{
  int max = 0, but, aux;

  for (but = 0; but < lastBUTnumber; but++) {
    aux = vslength (tvs[but]) + INTlength (paramtbl[but]);
    if (aux > max)
      max = aux;
  }
  return max;
}

PUBLIC tvarsort*
PosVS (l, x)
  tvarsort *l;
  int x;
{
  for ( ; l != NULL; l = l->next)
    if (l->sort == x)
      return l;
  return NULL;
}

PRIVATE int
SortIsInVS (l, x)
  tvarsort *l;
  int x;
{
  for ( ; l != NULL; l = l->next)
    if (l->sort == x)
      return TRUE;
  return FALSE;
}

PRIVATE tvarsort*
AddVS (t, sort, amount)
  tvarsort *t;
  int sort, amount;
{
  tvarsort *auxt = NULL, *inx;

  auxt = (tvarsort*)emalloc (sizeof (tvarsort));
  auxt->pos  = -3;     /* still not known */
  auxt->sort = sort;   /* The sort */
  auxt->num  = amount; /* How many of this sort */
  auxt->next = NULL;
  if (t == NULL)
    return auxt;
  if (t->next == NULL) {
    t->next = auxt;
    return t;
  }
  for (inx = t; inx->next != NULL; inx = inx->next)
    ;                         /* inx points to the penultimun */
  inx->next = auxt;         /* New element becomes the last one */
  return t;
}

PRIVATE int
NumVS (s, l)
  int s;
  INTlist l;
{
  register int i = 0;

  for (; l != NULL; l = INTtail (l))
    if (INThead (l) == s)
      i++;
  return i;
}

PRIVATE tvarsort*
dotvs (sortl)
  INTlist sortl;
{
  tvarsort *t = NULL, *it = NULL;
  int sort;

  for ( ; sortl != NULL; sortl = INTtail (sortl)) {
    sort = INThead (sortl);
    if (SortIsInVS (t, sort)) {
      it = PosVS (t, sort);
      if (NumVS (sort, sortl) > it->num)
	it->num = NumVS (sort, sortl);
    }
    else
      t = AddVS (t, sort, NumVS (sort, sortl));
  }
  return t;
}

/* Given a but number and a list of sorts, it updates */
/* the 'tvs' table to compact variables by sorts.     */
PUBLIC void
uptvs (butnum, sortlist)
  int butnum;
  INTlist sortlist;
{
  tvarsort *this = NULL, *it = NULL;
  INTlist inx;
  int sort;

  if (sortlist != NULL) {
    if (tvs[butnum] == NULL) { /* This is the first sort_list for this but */
      tvs[butnum] = dotvs (sortlist);
    }
    else {                          /* the lists are ordered by sorts */
      this = tvs[butnum];
      for (inx = sortlist; inx != NULL; inx = INTtail (inx)) {
	sort = INThead (inx);
	if (SortIsInVS (this, sort)) {
	  it = PosVS (this, sort);
	  if (NumVS (sort, sortlist) > it->num)
	    it->num = NumVS (sort, sortlist);
	}
	else                     /* There wasn't; Should be built up */
	  this = AddVS (this, sort, NumVS (sort, sortlist));
      }
      tvs[butnum] = this;
    }
  }
}

/* It updates the 'pos' field in the 'tvs' table. */
PUBLIC void
uptvs_position ()
{
  int j;
  tvarsort *aux = NULL;

  for (j = 0 ; j < lastBUTnumber; j++) {
    if (tvs[j] != NULL) {
      tvs[j]->pos = 0;                   /* The first set of variables */
      for (aux = tvs[j]; aux->next != NULL; aux = aux->next)
	aux->next->pos = aux->pos + aux->num;
    }
  }
}

PUBLIC char*
mkstr (n)
  int n;
{
  static char s[20];

  (void) sprintf (s, "%0*u", split_digits, n);
  return s;
}

/* It generates the names of the files in which code will be  */
/* written. It produces the name for headers (ended in ".a")  */
/* and the name for the source code itself (ended in "_b.a"). */
/* It takes into account if several files have to be produced */
/* for the code, in which case, it only generates the name    */
/* for the first part. The global variables "incname" and     */
/* "codename" will held the generated names.                  */
/* In case the code should be splitted, further calls to      */
/* "mkstr" are needed.                                        */
PUBLIC void
genfilenames ()
{
  int kk, longitud;

  if (split_flag) {
    for (split_digits = 0, kk = split_parts - 1;
	 kk > 0;
	 kk = kk / 10, split_digits++ )
      ;
    split_counter++;
    longitud = strlen (basename) + split_digits + 6;
  }
  else
    longitud = strlen (basename) + 6;

  incname  = emalloc (longitud*sizeof(char));
  codename = emalloc (longitud*sizeof(char));

  (void)sprintf (incname, "%s.a", basename);
  (void)sprintf (codename, "%s_b.a", basename);
}

/* It removes all files which would have been produced */
/* with the rest of the options.                       */
PUBLIC void
remove_files ()
{
  int inx;

  genfilenames ();
  if (debuging)
    (void)fprintf (stdout, "Removing header file \"%s\"\n", incname);
  (void) unlink (incname);

  if (!split_flag) {
    if (debuging)
      (void)fprintf (stdout, "Removing code file  \"%s\"\n", codename);
    (void) unlink (codename);
  }
  else {
    if (debuging)
      (void)fprintf (stdout, "Removing part 0, code file name \"%s\"\n",
		     codename);
    (void) unlink (codename);

    for (inx = 1; inx < split_parts; inx++) {
      (void)sprintf (codename, "%s%s.a", basename, mkstr (inx));
      if (debuging)
	(void)fprintf (stdout, "Removing part %d, code file name \"%s\"\n",
		       inx, codename);
      (void) unlink (codename);
    }
  }
}
