
/* 
 * $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: anal.c 1.1 90/01/19 $@(#)anal.c	1.1 89/12/01"
/*
 * Functions used by the parser to build the type table
 */
#include "xs.h"
#include "names.h"
#include "stack.h"
#include "types.h"
#include "anal.h"
#include "xdefs.h"
#include "catalog.h"
#include "mfile1.h"
#include "desc.h"

extern char *gettxt();

/*
 * Create a declarator node to a function name (in a fdeclarator)
 * Always the last in a decl list. i.e. found the first by the parser
 * The name must not be added in the namelist here (null arg to types_new).
 * (it will be added later when declaration is complete)
 * Second arg is the left parenthesis token.
 */
TOKEN
decl_fname(name, lp)
  TOKEN name, lp;
{
  TYPEP aux;
  aux = types_new(NODE_DECL, DECL_FNAME, (char *)0);
  ty_name_new(aux, name.t_name);
  de_flag_new(aux, DECL_FNAME);
  de_next_new(aux, type_null);
  de_off_new(aux, name.t_off);
  de_len_new(aux, name.t_len);
  de_ty_new(aux, at_ty(curattr.t_type));
  lp.t_type = aux;
  lp.t_len += name.t_len;
  lp.t_off = name.t_off;
  return lp;
}

TOKEN
def_attr()
{
  TOKEN resu;
  TYPEP aux;
  aux = types_new(NODE_ATTR, 0, (char *)0);
  at_cl_new(aux, type_null);
  at_ty_new(aux, types_systype(INT));
  resu.t_type = aux;
  return resu;
}

TOKEN
decl_name(name)
  TOKEN name;
{
  name.t_type = types_new(NODE_DECL, DECL_NAME, (char *)0);
  ty_name_new(name.t_type, name.t_name);
  de_flag_new(name.t_type, DECL_NAME);
  de_next_new(name.t_type, type_null);
  de_off_new(name.t_type, name.t_off);
  de_len_new(name.t_type, name.t_len);
  de_ty_new(name.t_type, at_ty(curattr.t_type));
  return name;
}

/*
 * Declare a dummy structure member for bit fields fillers
 */
TOKEN
decl_fake()
{
  TOKEN name;
  name.t_type = types_new(NODE_DECL, DECL_NAME, (char *)0);
  ty_name_new(name.t_type, 0);
  de_flag_new(name.t_type, DECL_NAME);
  de_next_new(name.t_type, type_null);
  de_ty_new(name.t_type, at_ty(curattr.t_type));
  return name;
}
/*
 * Create a declarator node for a pointer and append to the list
 */
TOKEN
decl_ptr(decl)
  TOKEN decl;
{
  TYPEP aux;
  aux = types_new(NODE_DECL, DECL_PTR, (char *)0);
  de_flag_new(aux, DECL_PTR);
  de_next_new(aux, type_null);
  de_ty_new(aux, at_ty(curattr.t_type));
  decl_append(decl.t_type, aux);
  return decl;
}

/*
 * Create a declarator node for a function and append to the list
 */
TOKEN
decl_fct(decl)
  TOKEN decl;
{
  TYPEP aux;
  aux = types_new(NODE_DECL, DECL_FUNC, (char *)0);
  de_flag_new(aux, DECL_FUNC);
  de_next_new(aux, type_null);
  de_ty_new(aux, at_ty(curattr.t_type));
  decl_append(decl.t_type, aux);
  return decl;
}

/*
 * Create a declarator node for an unsized array.
 */
TOKEN
decl_usize(decl, len)
  TOKEN decl;
  int len;
{
  TYPEP aux;

  aux = types_new(NODE_DECL, DECL_ARRAY, (char *)0);
  de_flag_new(aux, DECL_ARRAY);
  de_next_new(aux, type_null);
  de_off_new(aux, decl.t_off);
  de_len_new(aux, len);
  decl.t_len = len;
  de_ty_new(aux, at_ty(curattr.t_type));
  decl_append(decl.t_type, aux);
  return decl;
}

/*
 * create a node for a sized array. the second param is the array index
 */
TOKEN
decl_size(decl, index)
  TOKEN decl;
  int index;
{
  TYPEP aux;
  aux = types_new(NODE_DECL, DECL_SIZE, (char *)0);
  de_flag_new(aux, DECL_SIZE);
  de_next_new(aux, type_null);
  de_in_max_new(aux, index);
  de_ty_new(aux, at_ty(curattr.t_type));
  decl_append(decl.t_type, aux);
  return decl;
}

/*
 * Append a declarator at the end of a declarators list
 */
static
decl_append(list, decl)
  TYPEP list, decl;
{
  TYPEP aux;
  aux = list;
  while (!is_null_type(de_next(aux)))
    aux = de_next(aux);
  de_next_new(aux, decl);
}

/*
 * Create a decl_list node (in a struct/union members declaration)
 */
TOKEN
delist_decl(decl)
  TOKEN decl;
{
  TYPEP aux;
  aux = types_new(NODE_DECL_LIST, 0, (char *)0);

  dl_de_new(aux, decl.t_type);
  dl_next_new(aux, type_null);
  decl.t_type = aux;
  return decl;
}

/*
 * Append a declarator to a declarator list
 */
TOKEN
delist_append(delist, decl)
  TOKEN delist, decl;
{
  TYPEP aux;
  TOKEN ndel;
  aux = delist.t_type;
  ndel = delist_decl(decl);

  if (is_null_type(aux))
    return ndel;
  if (is_null_type(decl.t_type))
    return delist;
  while (!is_null_type(dl_next(aux)))
    aux = dl_next(aux);
  dl_next_new(aux, ndel.t_type);
  return delist;
}

/*
 * Check if a type (system or typedef) is 'char'
 */
bool
is_char(token)
  TOKEN token;
{
  TYPEP tptr;
  tptr = token.t_type;
  
  while (!is_null_type(tptr)){
    switch(ty_flag(tptr)){
    case TYPE_SYSTEM:
      return (ty_sys(tptr) == CHAR);
    case TYPE_TYPEDEF:
      tptr = td_ty(tptr);
      continue;
    default:
      return FALSE;
    }
  }
}

/*
 * Create attributes nodes
 */

/*
 * Class and type
 */
TOKEN
attr_ct(c, t)
  TOKEN c, t;
{
  TYPEP aux;
  aux = types_new(NODE_ATTR, 0, (char *)0);
  at_cl_new(aux, c.t_type);
  at_ty_new(aux, t.t_type);
  at_off_new(aux, t.t_off);
  at_len_new(aux, t.t_len);
  c.t_type = aux;
  return c;
}

/*
 * Type, class, type.
 */
TOKEN
attr_tct(t1, c, t2)
  TOKEN t1, c, t2;
{
  TYPEP aux;
  aux = types_new(NODE_ATTR, 0, (char *)0);
  at_cl_new(aux, c.t_type);
  at_ty_new(aux, is_char(t1) ? t1.t_type : t2.t_type);
  t1.t_type = aux;
  return t1;
}

TOKEN
attr_c(c)
  TOKEN c;
{
  TYPEP aux;
  aux = types_new(NODE_ATTR, 0, (char *)0);
  at_cl_new(aux, c.t_type);
  at_ty_new(aux, types_systype(INT));
  c.t_type = aux;
  return c;
}

/*
 * Type
 */
TOKEN
attr_t(t)
  TOKEN t;
{
  TYPEP aux;
  aux = types_new(NODE_ATTR, 0, (char *)0);
  at_cl_new(aux, type_null);
  at_ty_new(aux, t.t_type);
  at_off_new(aux, t.t_off);
  at_len_new(aux, t.t_len);
  t.t_type = aux;
  return t;
}

/*
 * enum type
 */
TOKEN
enum_type()
{
  TOKEN decl;
  TYPEP aux;
  aux = types_new(NODE_TYPE, TYPE_ENUM, (char *)0);
  ty_flag_new(aux, TYPE_ENUM);
  decl.t_type = aux;
  return decl;
}

/*
 * Allocate a struct or union type node. contents will arrive later
 */
TOKEN
struct_head(type, name)
  TOKEN type, name;
{
  int t_val = type.t_val == STRUCT ? TYPE_STRUCT : TYPE_UNION;
  TYPEP aux;
  aux = types_new(NODE_TYPE, t_val, name.t_name);

  ty_flag_new(aux, t_val);
  ty_name_new(aux, name.t_name);
  su_tl_new(aux, type_null);
  type.t_type = aux;
  return type;
}

/*
 * define a new struct/union type (add the type_dcl_list)
 */
TOKEN
struct_def(name, decl)
  TOKEN name, decl;
{
  su_tl_new(name.t_type, decl.t_type);
  return name;
}

/*
 * struct decl without parameter list : try to locate in the table
 */
TOKEN
struct_decl(type, name)
  TOKEN type, name;
{
  int t_val = type.t_val == STRUCT ? TYPE_STRUCT : TYPE_UNION;

  if (is_null_type(type.t_type = tdl_locate(t_val, name.t_name)))
    return struct_head(type, name);

  return type;
}

/*
 * Create a type_declaration (in a struct/union definition)
 */
TOKEN
tdl_create(type, delist)
  TOKEN type, delist;
{
  TYPEP aux;
  aux = types_new(NODE_T_DCL_LIST, 0, (char *)0);

  tl_ty_new(aux, type.t_type);
  tl_dl_new(aux, delist.t_type);
  tl_next_new(aux, type_null);
  delist.t_type = aux;
  return delist;
}

/*
 * Append to a type_dcl_list.
 * Caution : value to append could be empty
 */
TOKEN
tdl_append(tdlist, tdl)
  TOKEN tdlist, tdl;
{
  TYPEP tptr;

  if (is_null_type(tdlist.t_type))
    return tdl;
  
  if (is_null_type(tdl.t_type))
    return tdlist;
  
  tptr = tdlist.t_type;
  while (!is_null_type(tl_next(tptr)))
    tptr = tl_next(tptr);
  tl_next_new(tptr, tdl.t_type);
  return tdlist;
} 

/*
 * Declare a nfdeclarator identifier. Could be a typedef.
 * Attributes are in curattr.
 */
TYPEP 
ident_nf(nf)
  TOKEN nf;
{
  TYPEP aux, attr, class, type, decl;
  char *name = ty_name(nf.t_type);
  TOKEN taux;
  attr = curattr.t_type;
  
  if (!is_null_type(class = at_cl(attr)) && cl_val(class) == TYPEDEF){
    typedef_add(attr, nf.t_type);
    return type_null;
  }
  if (!is_null_type(class) && cl_val(class) == EXTERN){
    aux = g_ident_isin(name);
    if (!is_null_type(aux)){
      if (id_flag(aux) & IDENT_STRINIT){
        TYPEP de, ty;
        de = de_next(nf.t_type);
        if (ty_flag(at_ty(attr)) == TYPE_TYPEDEF){
          act_e_replace(at_off(attr), at_len(attr), "\nchar");
          de = nf.t_type;
        }
        act_e_replace(de_off(de), de_len(de), " *%s", name);
      } else {
        if (id_flag(aux) & IDENT_ARRAY){
          TYPEP ptr, prev, new, de, ty;
          new = g_types_new(NODE_CHAIN, 0, 0);
          de = nf.t_type;
          if (!is_null_type(de = de_next(de)) && de_flag(de) == DECL_ARRAY &&
            is_null_type(de_next(de))){
            ec_off_new(new, de_off(de));
            ec_len_new(new, de_len(de));
            ec_typedef_new(new, FALSE);
            ec_next_new(new, type_null);
          } else if (is_null_type(de_next(nf.t_type)) && 
                     ty_flag(ty = at_ty(attr)) == TYPE_TYPEDEF && 
                      !is_null_type(de = de_next(last_de(ty))) && 
                  de_flag(de) == DECL_ARRAY && is_null_type(de_next(de))){
            de = nf.t_type;
            ec_off_new(new, at_off(attr));
            ec_len_new(new, at_len(attr));
            ec_a_off_new(new, de_off(de));
            ec_a_len_new(new, de_len(de));
            ec_next_new(new, type_null);
            ec_typedef_new(new, TRUE);
          } else {
            uerror(gettxt("xs:7","%s redeclaration"), name);
            return type_null;
          }
          prev = ptr = id_ec(aux);
          while (!is_null_type(ptr)){
            prev = ptr;
            ptr = ec_next(ptr);
          }
          if (is_null_type(prev))
            id_ec_new(aux, new);
          else
            ec_next_new(prev, new);
        }
      }
      return type_null;
    }
    aux = g_types_new(NODE_IDENT, 0, name);
  } else {
    if (!is_null_type(aux = ident_isin(name))){
      if (!(id_flag(aux) & IDENT_EXTERN)){
        uerror(gettxt("xs:8","%s redefinition(1)"), name);
        return type_null;
      }      
    } else {
      aux = types_new(NODE_IDENT, 0, name);
      id_ec_new(aux, type_null);
    }
  }
  ty_name_new(aux, name);
  attr = curattr.t_type;
  id_at_new(aux, attr); 
  id_de_new(aux, nf.t_type);
  id_re_new(aux, type_null);
  if (is_null_type(class))
    id_flag_new(aux, IDENT_DEF);
  else if (cl_val(class) == EXTERN){
    TOKEN taux;
    taux.t_type = at_ty(attr);
    id_flag_new(aux, IDENT_EXTERN);
    if (is_char(taux)){
      TYPEP de, ty;
      de = nf.t_type;
      if (!is_null_type(de = de_next(de)) && de_flag(de) == DECL_ARRAY &&
        is_null_type(de_next(de))){
        TYPEP new;
        /*
         * Found a name followed by an unsized array with no next element
         * and type is character : this is an unsized characters array
         */
        id_flag_new(aux, id_flag(aux) | IDENT_ARRAY);
        new = g_types_new(NODE_CHAIN, 0, 0);
        ec_off_new(new, de_off(de));
        ec_len_new(new, de_len(de));
        ec_next_new(new, type_null);
        ec_typedef_new(new, FALSE);
        id_ec_new(aux, new);
      } else if (is_null_type(de_next(nf.t_type)) && 
          ty_flag(ty = at_ty(attr)) == TYPE_TYPEDEF && 
          !is_null_type(de = de_next(last_de(ty))) && 
          de_flag(de) == DECL_ARRAY && is_null_type(de_next(de))){
        TYPEP new;
        /*
         * Same case as above for a typedef
         */
        de = nf.t_type;
        id_flag_new(aux, id_flag(aux) | IDENT_ARRAY);
        new = g_types_new(NODE_CHAIN, 0, 0);
        ec_off_new(new, at_off(attr));
        ec_len_new(new, at_len(attr));
        ec_a_off_new(new, de_off(de));
        ec_a_len_new(new, de_len(de));
        ec_next_new(new, type_null);
        ec_typedef_new(new, TRUE);
        id_ec_new(aux, new);
       }
    }
  } else if (cl_val(class) == STATIC)
    id_flag_new(aux, IDENT_DEF|IDENT_STATIC);
  else
    id_flag_new(aux, IDENT_DEF);
  type = at_ty(attr);
  taux.t_type = type;
  return aux;
}

/*
 * Declare a function identifier
 */
void
ident_f(f)
  TOKEN f;
{
  TYPEP aux, attr, class;
  char *name = ty_name(f.t_type), flag;
  attr = curattr.t_type;
  
  if (!is_null_type(class = at_cl(attr)) && cl_val(class) == TYPEDEF){
    typedef_add(attr, f.t_type);
    return;
  }

  if (!is_null_type(aux = g_ident_isin(name))){
    if (!((flag = id_flag(aux)) & IDENT_FUNC)){
      uerror(gettxt("xs:9","%s redefinition(2)"), name);
      return;
    }
    return;
  } else
    aux = g_types_new(NODE_IDENT, 0, name);
  ty_name_new(aux, name);
  attr = curattr.t_type;
  id_at_new(aux, attr);
  id_de_new(aux, f.t_type);
  id_re_new(aux, type_null);
  if (!is_null_type(class) && cl_val(class) == STATIC)
    id_flag_new(aux, IDENT_STATIC|IDENT_FUNC);
  else
    id_flag_new(aux, IDENT_FUNC);
}

/*
 * Define a function. Ouput function start marker for messages file.
 */
void
func_def(decl)
  TOKEN decl;
{
  TYPEP aux, attr, class;
  char *name = ty_name(decl.t_type), flag;
  attr = curattr.t_type;
  
  if (!is_null_type(class = at_cl(attr)) && cl_val(class) == TYPEDEF){
    uerror(gettxt("xs:10","%s unexpected class word"), name);
    return;
  }

  if (!is_null_type(aux = g_ident_isin(name))){
    if (!((flag = id_flag(aux)) & IDENT_FUNC)){
      uerror(gettxt("xs:11","%s redeclaration"), name);
      return;
    } else if (flag & IDENT_DEF){
      uerror(gettxt("xs:12","%s redefinition(3)"), name);
      return;
    }
  } else {
    aux = g_types_new(NODE_IDENT, 0, name);
    ty_name_new(aux, name);
    attr = curattr.t_type;
    id_at_new(aux, attr);
    id_de_new(aux, decl.t_type);
    id_re_new(aux, type_null);
  }
  if (!is_null_type(class) && cl_val(class) == STATIC)
    id_flag_new(aux, IDENT_STATIC|IDENT_FUNC|IDENT_DEF);
  else
    id_flag_new(aux, IDENT_FUNC|IDENT_DEF);
  msg_f_start(fd_msg, name);
}

/*
 * Mark a function as used. Declare it if necessary
 */
void
use_func(name)
  TOKEN name;
{
  TYPEP aux;
  aux = g_ident_isin(name.t_name);
  
  if (is_null_type(aux)){
    aux = g_types_new(NODE_IDENT, 0, name.t_name);
    ty_name_new(aux, name.t_name);
    id_flag_new(aux, IDENT_FUNC|IDENT_USE);
    id_at_new(aux, type_null);
    id_re_new(aux, type_null);
  } else {
    if (!(id_flag(aux) & IDENT_FUNC)){
      uerror(gettxt("xs:13","%s not a function name"), name.t_name);
      return;
    }
    id_flag_new(aux,id_flag(aux) | IDENT_USE);
  }
}

/*
 * Mark an identifier as used. Can even be a function name
 */
void
use_name(name)
  TOKEN name;
{
  TYPEP aux;
  
  if (is_init && !do_init)
    return;
    
  if (is_null_type(aux = a_ident_isin(name.t_name, (int *)0))){
    uerror(gettxt("xs:14","%s undefined"), name.t_name);
    return;
  }
  id_flag_new(aux, id_flag(aux) | IDENT_USE);
}

/*
 * Add a typedef
 */
void
typedef_add(attr, decl)
  TYPEP attr, decl;
{
  TYPEP aux;
  is_typedef = TRUE;
  aux = types_new(NODE_TYPE, TYPE_TYPEDEF, ty_name(decl));
  is_typedef = FALSE;
  ty_flag_new(aux, TYPE_TYPEDEF);
  td_ty_new(aux, at_ty(attr));
  td_de_new(aux, decl);
}

/*
 * Return the name of a type. To allow types redeclaration
 */
TOKEN
type_name(type)
  TOKEN type;
{
  if (ty_flag(type.t_type) != TYPE_TYPEDEF){
    uerror(gettxt("xs:15","syntax error: type name unexpected(3)"));
    return NIL;
  }
  type.t_name = ty_name(td_de(type.t_type));
  return type;
}

/*
 * Declare a member of enumeration as an identifier (to avoid error messages
 * about undefined vars).
 */
moe_dcl(name)
  TOKEN name;
{
  TYPEP aux, aux2;
  
  if (!is_null_type(ident_isin(name.t_name))){
    uerror(gettxt("xs:16","%s redefinition(4)"), name);
    return 0;
  }

  aux = types_new(NODE_IDENT, 0, name.t_name);
  aux2 = types_new(NODE_ATTR, 0, (char *)0);
  at_cl_new(aux2, type_null);
  at_ty_new(aux2, types_systype(INT));
  ty_name_new(aux, name.t_name);
  id_at_new(aux, aux2);
  id_flag_new(aux, IDENT_ENUM);
}

/*
 * Return actual declarator for a typedef series (for unsized arrays only)
 */
TYPEP last_de(ty)
  TYPEP ty;
{
  TYPEP de;
  for (de = td_de(ty), ty = td_ty(ty) ; is_null_type(de_next(de)) && 
    ty_flag(ty) == TYPE_TYPEDEF; de = td_de(ty), ty = td_ty(ty));
  return de;
}
