
/* 
 * $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred.
 */

/*	Copyright (c) 1984 AT&T	*/
/*	  All Rights Reserved  	*/

/*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T	*/
/*	The copyright notice above does not evidence any   	*/
/*	actual or intended publication of such source code.	*/
#ident "$Header: types.c 1.1 90/01/19 $@(#)types.c	1.1 89/12/01"
/*
 * Types tables are used to hold informations about variables, user types,
 * etc.
 * Types tables are stored on a stack (ty_st) corresponding to C nesting
 * levels.
 * Note that 2 levels are used when entering a function definition : one for
 * the arguments and one for the compound statement
 * Everything lying at bottom of stack is global
 *
 * Types tables are in fact table of tables, to avoid large data structures
 * reallocation. Reference type is (TYPEP) (defined in names.h) which
 * specifies a level (on stack), a table and an offset in table.
 * 
 * A type table entry (node) is an union. Consequently, each node has a type.
 * Functions are used to access entries in a node (types2.c).
 *
 * Each type table has a name table associated with it to retrieve names
 * nodes in the table with the same name are chained (ty_next).
 */

#include "xs.h"
#include "names.h"
#include "stack.h"
#include "types.h"
#include "anal.h"
#include "mfile1.h"
#include "xdefs.h"

extern char * gettxt();

/*
 * Memory allocation saving
 * buffers are never freed, they are put in free lists, according to their
 * types.
 */
static struct ty_buf {
  int ty_nelem;
  struct ty_buf *ty_next;
} *ty_start, *ta_start, *tab_start;

/*
 * Enlarge a type table
 */
static
ty_enlarge(ty)
  TYPETAB *ty;
{
  if (ty->ty_tab == 0){
    /*
     * Allocate a new table of tables
     */
    if (ta_start != 0){
      /*
       * Use previouly free'd table
       */
      ty->ty_tab = (TYPET **)ta_start;
      ty->ty_ntab = ta_start->ty_nelem;
      ta_start = ta_start->ty_next;
    } else {
      /*
       * Allocate a new table
       */
      ty->ty_ntab = TY_T_SIZE;
      if ((ty->ty_tab = (TYPET **)malloc(sizeof(TYPET *) * TY_T_SIZE)) == 0)
        fatal(gettxt("xs:71","Out of memory (types.c (1))"));
    }
  } else if (ty->ty_ltab == ty->ty_ntab){
    /*
     * Enlarge table of tables
     */
    ty->ty_ntab += TY_T_SIZE;
    if ((ty->ty_tab = (TYPET **)realloc((char *)ty->ty_tab, sizeof(TYPET *) * TY_T_SIZE)) == 0)
      fatal(gettxt("xs:72","Out of memory (types.c (2))"));
  }
  /*
   * Allocate a type table
   */
  if (ty_start != 0){
    /*
     * Use a previously free'd type table
     */
    ty->ty_tab[ty->ty_ltab++] = (TYPET *)ty_start;
    ty_start = ty_start->ty_next;
  } else {
    /*
     * Allocate a new type table
     */
    if ((ty->ty_tab[ty->ty_ltab++] = (TYPET *)malloc(sizeof(TYPET)*TY_SIZE)) == 0)
      fatal(gettxt("xs:73","Out of memory (types.c (3))"));
  }
  ty->ty_free = 0;
}

/*
 * Add a new entry in a type table.
 * level is the level on the types stack
 * type is the type of the node
 * subtype is a type in the type for some fast tests on entries
 * subtype is not positionned in ty_new
 * name is the name position returned by na_store.
 */
static TYPEP
ty_new(level, type, subtype, name)
  int level;
  int type, subtype;
  char *name;
{
  TYPEP tptr, tptr2, prev;
  TYPETAB *ty = (TYPETAB *)st_elem(ty_st, level);
  int tab;
  
  if (ty->ty_ntab == 0 || ty->ty_free == TY_SIZE)
    ty_enlarge(ty);

  tab = ty->ty_ltab - 1;
  ty->ty_tab[tab][ty->ty_free].ty_stype = type;
  ty->ty_tab[tab][ty->ty_free].ty_sname = name;
  ty->ty_tab[tab][ty->ty_free].ty_snext = type_null;
  tptr.ty_level = level;
  tptr.ty_offset = ty->ty_free++;
  tptr.ty_tab = tab;
  if (name != 0){
    /*
     * a name is associated with the node. must check some conditions on 
     * previously existing nodes with same name
     */
    if (!is_null_type(prev = na_isin(ty->ty_nam, name))){
      /*
       * Nodes with same name are already in the table. Scan the list
       */
      tptr2 = prev;
      do {
        if (ty_type(tptr2) == type){
          /*
           * Found a node with same type than new one
           */
          switch(type){
          case NODE_TYPE:
            if (subtype == ty_flag(tptr2)){
              if ((subtype == TYPE_STRUCT || subtype == TYPE_UNION) &&
                  is_null_type(su_tl(tptr2)))
                /*
                 * struct/union definition, but name was already declared
                 */
                return tptr2;
	      if (is_typedef){
		/*
		 * typedef redefinition
		 */
		return tptr2;
	      }
              uerror(gettxt("xs:74","%s redefinition(5)"), ty_name(tptr2));
              return tptr2;
            }
            break;
          case NODE_IDENT:
	    /*
	     * Identifier redefinition (var, func name,...)
	     */
            uerror(gettxt("xs:75","%s redefinition(6)"), ty_name(tptr2));
            return tptr2;
          case NODE_DECL:
            break;
	  default:
	    fatal(gettxt("xs:76","Unexpected named node"));
          }
          break;
        }
        prev = tptr2;
        tptr2 = ty_next(tptr2);
      } while (!is_null_type(tptr2));
      ty_next_new(prev, tptr);
    } else
      (void)na_add(name, ty->ty_nam, tptr);
  }
  return tptr;
}

/*
 * Free a type table
 */
static void
ty_free(ty)
  TYPETAB *ty;
{
  register int i;
  struct ty_buf *ptr;
  if (ty->ty_tab != 0){
    /*
     * Free associated type tables
     */
    for (i = 0 ; i < ty->ty_ltab ; i++){
      /*
       * Insert type table in free list
       */
      ptr = (struct ty_buf *)ty->ty_tab[i];
      ptr->ty_next = ty_start;
      ty_start = ptr;
    }
    /*
     * Insert table of type table in free list
     */
    ptr = (struct ty_buf *)ty->ty_tab;
    ptr->ty_nelem = ty->ty_ntab;
    ptr->ty_next = ta_start;
    ta_start = ptr;
  }
  if (ty->ty_nam != 0)
    /*
     * Free the associated name table
     */
    na_free(ty->ty_nam);
  /*
   * Insert type table header in free list
   */
  ptr = (struct ty_buf *)ty;
  ptr->ty_next = tab_start;
  tab_start = ptr;
}

/*
 * Create a new type table
 */
static TYPETAB *
ty_creat()
{
  TYPETAB *newtbl;

  if (tab_start != 0){
    /*
     * Use previously use type table header
     */
    newtbl = (TYPETAB *)tab_start;
    tab_start = tab_start->ty_next;
  } else {
    /*
     * Allocate a new type table header
     */
    if ((newtbl = (TYPETAB *)malloc(sizeof(TYPETAB))) == 0)
      fatal(gettxt("xs:77","Out of memory (types.c (4))"));
  }
  newtbl->ty_free = 0;
  newtbl->ty_max = 0;
  newtbl->ty_tab = 0;
  newtbl->ty_ntab = 0;
  newtbl->ty_ltab = 0;
  newtbl->ty_nam = na_creat();
  return newtbl;
}

/*
 * Types stack handling
 */

/*
 * Create the types stack. Init values with basic system types and classes
 */
void
types_creat()
{
  /*
   * Create stack and push first level (global types)
   */
  ty_st = st_creat();
  types_push();
  
  /*
   * Create typ_attr : default attributes for a type (see type_declaration
   * entry in cgram.y)
   */
  typ_attr = types_new(NODE_ATTR, 0, 0);
  at_cl_new(typ_attr,type_null);
  at_ty_new(typ_attr, type_null);
  
  /*
   * Create system types table
   */
  types_do_new();
  types_do_systype(CHAR, "char");
  types_do_systype(DOUBLE, "double");
  types_do_systype(FLOAT, "float");
  types_do_systype(INT, "int");
  types_do_systype(LONG, "long");
  types_do_systype(SHORT, "short");
  types_do_systype(UNSIGNED, "unsigned");
  types_do_systype(UNDEF, "void");
  
  /*
   * Create storage classes table
   */
  types_do_class(AUTO);
  types_do_class(EXTERN);
  types_do_class(FORTRAN);
  types_do_class(REGISTER);
  types_do_class(STATIC);
  types_do_class(TYPEDEF);
}

/*
 * free the types stack
 */
void
types_free()
{
  register int i;
  int nelem;
  
  if (ty_st == 0)
    return;

  nelem = st_nelem(ty_st);
  for (i = 0 ; i < nelem ; i++)
    ty_free((TYPETAB *)st_elem(ty_st, i));
  st_free(ty_st);
  ty_st = 0;
}

/*
 * push a new level on the types stack
 */
void
types_push()
{
  st_push(ty_st, (char *)ty_creat());
}

/*
 * pop last level from types stack
 */
void
types_pop()
{
  ty_free((TYPETAB *)st_pop(ty_st));
}

/*
 * Add a new node on top of types stack
 */
TYPEP
types_new(type, subtype, name)
  int type, subtype;
  char *name;
{
  return ty_new(types_nelem() - 1, type, subtype, name);
}

/*
 * Add a new node on bottom of types stack. For function declaration/definition
 * And extern declarations
 */
TYPEP
g_types_new(type, subtype, name)
  int type, subtype;
  char *name;
{
  return ty_new(0, type, subtype, name);
}

/*
 * classes & system types handling : Keep a table with the address of entries
 * in the types table
 */
static struct {
  TYPEP ty;
  int val;
} sys_t[NSYSENTRIES], sys_c[NCLASSENTRIES];
static int sys_types;
static int sys_classes;

static
types_do_new()
{
  sys_types = sys_classes = 0;
}

static
types_do_systype(nr, name)
  int nr;
  char *name;
{
  TYPEP new;
  new = types_new(NODE_TYPE, TYPE_SYSTEM, na_store(name));
  ty_flag_new(new, TYPE_SYSTEM);
  ty_sys_new(new, nr);
  sys_t[sys_types].val = nr;
  sys_t[sys_types].ty = new;
  sys_types++;
}

static
types_do_class(nr)
  int nr;
{
  sys_c[sys_classes].ty = types_new(NODE_CLASS, 0, (char *)0);
  cl_val_new(sys_c[sys_classes].ty, nr);
  sys_c[sys_classes].val = nr;
  sys_classes++;
}

/*
 * Return typep to system type
 */
TYPEP
types_systype(nr)
  int nr;
{
  register int i;

  for (i = 0 ; i < sys_types ; i++)
    if (sys_t[i].val == nr)
      return sys_t[i].ty;
}

/*
 * return typep to storage class
 */
TYPEP
types_class(nr)
  int nr;
{
  register int i;
  for (i = 0 ; i < sys_classes ; i++)
    if (sys_c[i].val == nr)
      return sys_c[i].ty;
}

/*
 * Check if a name is a type.
 * Scan the whole stack, since most compilers consider a type as being
 * local
 */
TYPEP
types_check(name)
  char *name;
{
  int flag;
  TYPEP tptr;
  register int i;
  int nelem = st_nelem(ty_st);

  if (no_type)
    return type_null;

  for (i = nelem - 1 ; i >= 0 ; i--){
    if (!is_null_type(tptr = na_isin(((TYPETAB *)st_elem(ty_st, i))->ty_nam, name))){
      while (!is_null_type(tptr)){
        if (ty_type(tptr) == NODE_TYPE && ((flag = ty_flag(tptr)) == TYPE_SYSTEM
            || flag == TYPE_TYPEDEF)){
          return tptr;
        }
        tptr = ty_next(tptr);
      }
    }
  }
  return type_null;
}

/*
 * Return a struct/union parameter list
 */
TYPEP
tdl_locate(type, name)
  int type;
  char *name;
{
  TYPEP tptr;
  register int i;
  int nelem = st_nelem(ty_st);

  for (i = nelem - 1 ; i >= 0 ; i--){
    if (!is_null_type(tptr = na_isin(((TYPETAB *)st_elem(ty_st, i))->ty_nam, name))){
      while (!is_null_type(tptr)){
        if (ty_type(tptr) == NODE_TYPE && ty_flag(tptr) == type)
          return tptr;
        tptr = ty_next(tptr);
      }
    }
  }
  return type_null;
}

/*
 * Check if an identier exists
 */
TYPEP
ident_isin(name)
  char *name;
{
  TYPETAB *tp = (TYPETAB *)st_top(ty_st);
  TYPEP tptr;
  
  if (tp->ty_tab == 0)
    return type_null;
    
  if (is_null_type(tptr = na_isin(tp->ty_nam, name)))
    return type_null;
  while (!is_null_type(tptr)){
    if (ty_type(tptr) == NODE_IDENT)
      return tptr;
    tptr = ty_next(tptr);
  }
  return type_null;
}

/*
 * Check if a global identier exists. For functions identifiers.
 */
TYPEP
g_ident_isin(name)
  char *name;
{
  TYPETAB *tp = (TYPETAB *)st_bot(ty_st);
  TYPEP tptr;
  
  if (tp->ty_tab == 0)
    return type_null;
    
  if (is_null_type(tptr = na_isin(tp->ty_nam, name)))
    return type_null;
  while (!is_null_type(tptr)){
    if (ty_type(tptr) == NODE_IDENT)
      return tptr;
    tptr = ty_next(tptr);
  }
  return type_null;
}

/*
 * Check if an identifier is declared. Return the stack level.
 */
TYPEP
a_ident_isin(name, lev)
  char *name;
  int *lev;
{
  TYPEP tptr;
  TYPETAB *ty;
  register int i;
  
  for (i = st_nelem(ty_st) - 1 ; i >= 0 ; i--){
    ty = (TYPETAB *)st_elem(ty_st, i);
    if (ty->ty_tab != 0 && !is_null_type(tptr = na_isin(ty->ty_nam, name))){
      while (!is_null_type(tptr)){
        if (ty_type(tptr) == NODE_IDENT){
          if (lev != 0)
            *lev = i;
          return tptr;
        }
        tptr = ty_next(tptr);
      }
    }
  }
  if (lev != 0)
    *lev == -1;
  return type_null;
}

/*
 * Check if an identifier is global
 */
bool
is_global(id)
  TYPEP id;
{
  return (id.ty_level == 0);
}    

/*
 * global identifiers scanning (for symtab generation)
 */
static TYPETAB *id_tab;
static TYPEP id_ty;

void
types_rewind()
{
  if ((id_tab = (TYPETAB *)st_bot(ty_st)) == 0)
    return;
  id_ty.ty_level = 0;
  id_ty.ty_offset = -1;
  id_ty.ty_tab = 0;
}

TYPEP
types_next()
{
  if (id_tab == 0)
    return type_null;

  do {
    if (id_ty.ty_tab == id_tab->ty_ltab - 1){
      if (id_ty.ty_offset >= id_tab->ty_free - 1)
        id_ty = type_null;
      else
        id_ty.ty_offset++;
    } else {
      if (id_ty.ty_offset >= TY_SIZE - 1){
        id_ty.ty_tab++;
        id_ty.ty_offset = 0;
      } else
        id_ty.ty_offset++;
    }
  } while (!is_null_type(id_ty) && ty_type(id_ty) != NODE_IDENT);

  return id_ty;
}

/*
 * Return the nr of levels on the types stack
 */
types_nelem()
{
  return st_nelem(ty_st);
}
