/*********************************************************
 *  symbol table manager
 *  a binary tree is used
 *********************************************************/
/***********************************
  (C) Copyright 1992-1993; dit/upm
   Distributed under the conditions stated in the
   TOPO General Public License (see file LICENSE)
 ***********************************
$Log: symtab.c,v $
 * Revision 1.10  1993/01/18  18:10:25  lotos
 * distribution issues
 *
 * Revision 1.9  1993/01/12  20:19:47  lotos
 * portability issues
 *
 * Revision 1.8  1992/02/21  17:12:51  lotos
 * adapted to new lfe
 * better presentation of reports
 *
 * Revision 1.7  92/01/14  15:23:10  lotos
 * distribution issues
 *
 * Revision 1.6  92/01/13  19:06:03  lotos
 * copyright notice
 *
 * Revision 1.5  91/02/28  17:18:55  lotos
 * rule 'premiss ::= _value_expression' removed
 *
 * Revision 1.4  90/10/30  09:38:30  lotos
 * adapted to new CAST
 *
 * Revision 1.3  90/07/06  20:33:43  lotos
 * add option -n to list single types
 *
 * Revision 1.2  90/06/04  10:42:39  lotos
 * types are classified into
 * basic: not importing any other
 * constructed: importing others (via union, rename, or act)
 * used by others
 * not used by any other
 * those build by renaming of other
 * those built by actualizing other
 *
 * options are mutually exclusive
 *
 * Revision 1.1  90/05/11  12:53:41  lotos
 * Initial revision
 *
 ***********************************/

#ifndef lint
static char rcsid[]= "$Id: symtab.c,v 1.10 1993/01/18 18:10:25 lotos Exp $";
#endif

# include "swbus.h"

/* KJT 20/01/23: added function prototypes */
PUBLIC int CINTis_in (char *s, TYPEDEPEND *l);

PRIVATE char* coding_class[] = {
  "",
  "",
  "<RENAMED>",
  "<ACTUALIZED>",
};

PRIVATE int       indent_level = 0;

PUBLIC TUSEDNODE *tusedroot = NULL; /* list of types used somewhere */
PUBLIC SNODE     *tsroot = NULL;

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

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

/*KJT 20/01/23: added "int" type */
PUBLIC int CINTis_in (s, l)
  char       *s;
  TYPEDEPEND *l;
{
  while (l != NULL) {
    if (!strcmp (s, l->name))
      return TRUE;
    l = l->next;
  }
  return FALSE;
}

PUBLIC INTlist
INT2cons (s1, s2, t)
  int s1, s2;
  INTlist t;
{
  return INTcons (s1, INTcons (s2, t));
}

PUBLIC int
NotIn (iddec, root)
  int iddec;
  TUSEDNODE* root;
{
  while (root != NULL && root->iddec < iddec) {
    root = root->next;
  }
  if ((root != NULL) && (root->iddec == iddec))
    return FALSE;
  return TRUE;
}

PRIVATE TUSEDNODE*
create_tnode (iddec)
  int iddec;
{
  TUSEDNODE* t;

  t = (TUSEDNODE *) emalloc (sizeof (TUSEDNODE));
  t->iddec = iddec;
  t->next = NULL;
  return t;
}

PRIVATE SNODE*
new_tsnode (typename, iddec)
  char *typename;
  int  iddec;
{
  SNODE* s;

  s= (SNODE*) emalloc (sizeof (SNODE));
  s->typename   = typename; /* maybe strdup (typename) */
  s->iddec      = iddec;
  s->line       = 0;
  s->left       = NULL;
  s->right      = NULL;
  s->typexr     = NULL;
  s->type_class =0;
  return s;
}

PUBLIC void
addonetype (iddec)
  int iddec;
{
  TUSEDNODE* n;
  TUSEDNODE* aux;

  if (tusedroot != NULL && iddec == tusedroot->iddec)
    return;
  if (tusedroot == NULL || iddec < tusedroot->iddec) {
    n= create_tnode (iddec);
    n->next= tusedroot;
    tusedroot= n;
    return;
  }
  aux = tusedroot;
  while (aux->next != NULL && iddec > aux->next->iddec)
    aux= aux->next;
  if (aux->next != NULL && iddec == aux->next->iddec)
    return;
  n= create_tnode (iddec);
  n->next= aux->next;
  aux->next= n;
}

/*
 Given a symbol entry,
 add a new line occurrence
 lines are introduced in normal order
*/

/* puttypexr takes some information about a type and stores it as a node */
/* of the root tree. It has the following parameters:                    */
/*   - typename: the name of the type                                    */
/*   - iddec: the unique identifier of a type. It is a declaration       */
/*   - line: in which line the type is declared. I think it is not       */
/*           a usefull information in this tool                          */
/*   - typexr: It is a list of typenames of the types needed to built    */
/*             the type represented by iddec.                            */
/*   - typeclass: It indicates if the type is a union, renaming          */
/*                or actualizing                                         */

PUBLIC SNODE*
puttypexr (typename, iddec, line, typexr, type_class)
  char       *typename;
  int        iddec, line, type_class;
  TYPEDEPEND *typexr;
{
  SNODE* p;
  SNODE* q;
  SNODE* n;
  int    test= 1;

  if (tsroot == NULL)
      tsroot= new_tsnode ("", -1);

  p= tsroot;
  q= tsroot->right;

  while (q != NULL) {
    p= q;
    test= strcmp (typename, q->typename);
	  /* The only reason to compare between lexv as string is */
	  /* to hold the items in alphabetic order                */
    if (test == 0) {
      test= iddec - q->iddec;
    }
    if (test == 0) {
      q->line = line;
      q->type_class = type_class;
      q->typexr = typexr;
      return q;
    }
    if (test < 0)
      q= p->left;
    else
      q= p->right;
  }
				/* comes to this point if
				   lexv does not yet exist */
  n= new_tsnode (typename, iddec);
  if (test > 0)
    p->right = n;
  else
    p->left = n;

  n->line = line;
  n->type_class = type_class;
  n->typexr = typexr;
  return n;
}

PUBLIC SNODE*
name_search (name)            /* search for a type (TTYPE) called name */
  char  *name;
{
  SNODE* p;
  SNODE* q;
  int test= 1;

  assert (tsroot != NULL);

  p= tsroot;
  q= tsroot->right;

  while (q != NULL) {
    p= q;
    test= strcmp (name, q->typename);
    if (test == 0)
      return q;
    if (test < 0)
      q= p->left;
    else
      q= p->right;
  }
		     /* comes to this point if lexv does not yet exist */
  (void) fprintf (stderr, "search failed, type ''%s'' not found\n", name);
  exit(1);
  return q;	/* to shut lint off */
}

PRIVATE SNODE*
search (typename, iddec)            /* search for a declaration (dec) */
  char *typename;                   /* of the type (TTYPE) typename */
  int  iddec;
{
  SNODE* p;
  SNODE* q;
  int test= 1;

  if (tsroot == NULL) {
    (void) fprintf (stderr, "search failed, null tree\n");
    exit(1);
    }

  p= tsroot;
  q= tsroot->right;

  while (q != NULL) {
    p= q;
    test= strcmp (typename, q->typename);
    if (test == 0) {
      test = iddec - q->iddec;
    }
    if (test == 0)
      return q;
    if (test < 0)
      q= p->left;
    else
      q= p->right;
  }
		     /* comes to this point if lexv does not yet exist */
  (void) fprintf (stderr, "search failed, node not found\n");
  exit(1);
  return q;	/* to shut lint off */
}

PRIVATE void
print_indent ()
{
  int i;

  for (i = 1; i <= indent_level; i++)
    (void) fprintf (stdout, "-  ");
  (void) fprintf (stdout, "-  ");
}


PRIVATE void
search_item (aux, categ)
  TYPEDEPEND *aux;
  char       *categ;
{
  SNODE* t1;
  int pr = TRUE;

  while (aux != NULL) {
    t1 = search (aux->name, aux->iddec);
    if (pr) {
      print_item (t1, categ);
      pr = FALSE;
    }
    else print_item (t1, "");
    aux = aux->next;
  }
  indent_level--;
}

/* pretty printer */

PUBLIC void
print_item (t, categ)
  SNODE* t;
  char * categ;
{
  print_indent ();
  (void) fprintf (stdout, "%s %s\n", t->typename, categ);
  if (t->typexr != NULL) {
    indent_level++;
    search_item (t->typexr, coding_class[t->type_class]);
  }
}

/*
   traverses the symbol table
   while printing each item
*/

PRIVATE void
traverse (t, type_not_used, type_used, constructed,
	  basic, renames, actualizes, imported_type, indirect_types,
	  imported)
  SNODE   *t;
  int     type_not_used, type_used, constructed,
	  basic, renames, actualizes, imported_type;
  STRlist indirect_types;
  char    *imported;
{
  while (t != NULL) {
    traverse (t->left, type_not_used, type_used, constructed,
	      basic, renames, actualizes, imported_type, indirect_types,
	      imported);
    if (basic) {		/* basic types */
      if (t->typexr == NULL)
	(void) fprintf (stdout, "%s\n", t->typename);
    }
    else if (constructed) {	/* types using others */
      if (t->typexr != NULL)
	(void) fprintf (stdout, "%s\n", t->typename);
    }
    else if (type_not_used) {	/* types not used */
      if (NotIn (t->iddec, tusedroot))
	(void) fprintf (stdout, "%s\n", t->typename);
    }
    else if (type_used) {	/* types used */
      if (!NotIn (t->iddec, tusedroot))
	(void) fprintf (stdout, "%s\n", t->typename);
    }
    else if (renames) {		/* types which renames another */
      if (t->type_class == RENAMED)
	(void) fprintf (stdout, "%s\n", t->typename);
    }
    else if (actualizes) {	/* types which actualizes another */
      if (t->type_class == ACTUALIZED)
	(void) fprintf (stdout, "%s\n", t->typename);
    }
    else if (imported_type) {	/* types which depends on one */
      if (CINTis_in (imported, t->typexr)) {
	int i;
	for (i=0; i < indent_level; i++)
	  (void) fprintf (stdout, "  ");
	if (indent_level == 0)
	  (void) fprintf (stdout, "------------------\n");
	(void) fprintf (stdout, "%s\n", t->typename);
	indirect_types = STRcons (t->typename, indirect_types, TRUE);
      }
      while (indirect_types != NULL) {
	indent_level++;
	print_ts (type_not_used, type_used, constructed, basic,
		  renames, actualizes, imported_type,
		  STRhead(indirect_types));
	indent_level--;
	indirect_types = STRtail (indirect_types);
      }
    }
    else {					/* all types, full info */
	(void) fprintf (stdout, "\n      ------------  %s ------------\n",
			t->typename);
	print_item (t, "");
      }
    t= t->right;
  }
}

PUBLIC void
print_ts (type_not_used, type_used, constructed,
	  basic, renames, actualizes, imported_type, imported)
    int type_not_used, type_used, constructed,
	basic, renames, actualizes, imported_type;
    char *imported;
{
  STRlist indirect_types = NULL;	/* to mantain the list of */
					/* types which depends indirectly */
					/* on a given one */

  traverse (tsroot->right, type_not_used, type_used, constructed,
	    basic, renames, actualizes, imported_type, indirect_types,
	    imported);
}

