/*
    Clif - A C-like Interpreter Framework
    Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997 T. Hruz, L. Koren
    1998 L. Koren

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/
/* 
 * tables.c
 *
 * functions working on symbol tables
 */


#include <stdio.h>
#include <string.h>

#include "global.h"		/* Header of global variables */
#include "config.h"
#if STDC_HEADERS
#include <stdlib.h>
#include <ctype.h>
#else
#ifndef HAVE_ISALPHA
#define isalpha(a) \
(((a) >= 'a' && (a) <= 'z') || ((a) >= 'A' && (a) <= 'Z'))
#endif
#endif
#include "cast.h"		/* Header of used cast operators */
#include "type.h"		/* Header of internal representation
				   of types */
#include "struct.h"		/* Header of globally used structures
				 */
#include "define.h"		/* Clif's memory regions */
#include "mystdio.h"		/* Redefining NULL */
#include "token.h"		/* Header of tokens */
#include "instr.h"		/* Header of structures. Defines size of
				   virtual machine instructions. */
#include "allocx.h"
#include "comp_maint.h"
#include "tables.h"
#include "printfx.h"
#include "flags.h"

#define ANSI_NUMBER_OF_LOCALS 127
#define ANSI_NUMBER_OF_PARAMS 31

extern FILEATTR spf[];
extern int main_defined;

static struct tab *allocate_hastab_loc PROTO((void));
static struct ident_tab_header *
allocate_loc_tables PROTO((struct ident_tab_header *));

/* Clears hash table of local */
/* variables for structure member next */
/* in declaration. */
static void clear_hash_tab_next_declaration PROTO((struct tab *));

/* Clears hash table of local */
/* variables for structure member next. */
static void clear_hash_tab_next PROTO((struct ident_tab_header *,
				       struct tab *)); 

/*
 * Saves useful information about variables and connect the information with
 * the variable name.
 */
static void putstruct PROTO((struct tab *));

/*
 * Saves information into hash table when body of a function is defined.
 */
static void putstruct_body PROTO((struct tab *));

/*
 * Saves useful information about local variables and connect the information
 * with the variable name.
 */
static void putstruct_loc PROTO((struct tab *, int));

/* Looks up the hash table. */
static struct tab *lookup PROTO((char *));

/* Looks up the hash table. */
static struct tab *lookup_tag PROTO((char *));

/* Hash function. */
static unsigned int hash_code PROTO((char *, unsigned int));

/* Looks up the hash table. */
static struct tab *lookup_loc PROTO((char *, struct ident_tab_header *));

/*  Looks up the hash table of labels. */
static struct goto_tab *lookup_goto_table PROTO((char *));

/*
 * Saves useful information about tags.
 */
static void putstruct_tag PROTO((struct tab *));

/*
 * Saves information into hash table when body of a function is defined.
 */
static void putstruct_tag_body PROTO((struct tab *));

/* Function allocates space for variables */
static int allocate_var PROTO((struct internal_type *, char **));

/* \verbatim{tables_c_hastab.tex} */

static struct tab *hastab;	/* Pointer to the hash table. */

/* \verbatim */

/* \verbatim{tables_c_hastab_goto.tex} */

static struct goto_tab *hastab_goto;	/* Pointer to the hash
					   table. */

/* \verbatim */

/* \verbatim{tables_c_typetab.tex} */

static struct ident_tab_header 
*tagtab;			/* Pointer to the table of tags. */

/* \verbatim */

/* \verbatim{tables_c_identtab.tex} */

static struct ident_tab *identtab;   /* Pointer to the table of identifiers. */

/* \verbatim */

/* \verbatim{tables_c_identtab_loc.tex} */

static struct ident_tab_header
*identtab_loc;                /* Pointer to the table of local identifiers. */

/* \verbatim */

static int pi;

/* Type of an operand in an expression.  Length of an expression is
   limited to * 256 operands. */
enum intern_arit_class type_ac[256]; 

void clear_internal_type PROTO((struct internal_type *));
void put_array_subscript PROTO((struct internal_type **));
static void move_offset_aligned PROTO((int *, int));

/* Return offset in the current structure, or -1 if name is not a
   member. */
static int find_member PROTO((char *, struct internal_type *));

static int allocate_struct PROTO((struct internal_type *));
static int allocate_aggregate PROTO((struct internal_type *));

/* Static variables are put into tables. */
static void putstruct_static PROTO((struct ident_tab_loc *));

static int memory_size PROTO((int *, struct internal_type *));
static void check_init_bracket PROTO((int *, struct internal_type *,
				      char *));

int
hastab_init ()
{
  hastab = (struct tab *) callocx (SIZE_HAS, sizeof (struct tab));
  if (NULL == hastab)
    {
      error_message (4000);
      return (0);
    }
#ifdef DEBUG
  printfx ("Hash table allocated\n\n");
#endif

  return 1;
}

int
hastab_goto_init ()
{
  hastab_goto = (struct goto_tab *) callocx (SIZE_HAS_GOTO, 
					     sizeof (struct goto_tab));
  if (NULL == hastab_goto)
    {
      error_message (4000);
      return (0);
    }
#ifdef DEBUG
  printfx ("Hash table for goto's allocated\n\n");
#endif
  return 1;
}



int
identtab_init ()
{
  identtab = (struct ident_tab *) 
    callocx (MAX_IDENT, sizeof (struct ident_tab));
  if (NULL == identtab)
    {
      error_message (4000);
      return (0);
    }
  pi = 0;
  
  return 1;
}


static struct tab *
allocate_hastab_loc ()
{
  struct tab *hastab_loc;
  
  hastab_loc =
    (struct tab *) allocate (SIZE_HAS_LOC * sizeof (struct tab),
			     scope_level > PERM ? BLOCK : PERM);
  if (NULL == hastab_loc)
    {
      error_message (4000);
      return (0);
    }

#ifdef DEBUG
  printfx ("Hash table for local variables allocated\n\n");
#endif

  return hastab_loc;
}


static struct ident_tab_header *
allocate_loc_tables (previous)
  struct ident_tab_header *previous;
{
  struct ident_tab_header *identtab_loc;
  
  identtab_loc = (struct ident_tab_header *)
    allocate (MAX_IDENT_LOC * sizeof (struct ident_tab_loc) + sizeof
	      (struct ident_tab_header),
	      scope_level > PERM ? BLOCK : PERM);
  init_zero ((char *) identtab_loc,
	     MAX_IDENT_LOC * sizeof (struct ident_tab_loc) 
	     + sizeof (struct ident_tab_header));
  
  identtab_loc->scope_level = scope_level; 
  identtab_loc->pi_loc = 0;
  identtab_loc->offset = 0;
  identtab_loc->previous_level = previous;
  identtab_loc->hastab_loc = allocate_hastab_loc ();
  identtab_loc->table = (struct ident_tab_loc *)identtab_loc
    + sizeof (struct ident_tab_header);

  return identtab_loc;
}



/*
 * Clears hash table of local variables.
 */
void
clear_hash_tab_declaration ()
{
  int             i;

  for (i = 0; i < SIZE_HAS_LOC; i++)
    {
      if (NULL != identtab_loc->hastab_loc[i].name)
	{
#if 0
	  free (identtab_loc->hastab_loc[i].name);
#endif
	  identtab_loc->hastab_loc[i].name = NULL;
	  identtab_loc->hastab_loc[i].def = 0;
	  if (NULL != identtab_loc->hastab_loc[i].next)
	    clear_hash_tab_next_declaration (identtab_loc->hastab_loc[i].next);
	}
    }
  identtab_loc->pi_loc = 0;
  return;
}


void
clear_hash_tab ()
{
  int             i;

  if (!identtab_loc || identtab_loc->scope_level < scope_level)
    return;
  
  for (i = 0; i < SIZE_HAS_LOC; i++)
    {
      if (NULL != identtab_loc->hastab_loc[i].name)
	{
	  if (!identtab_loc->hastab_loc[i].count)
	    {
	      text = identtab_loc->hastab_loc[i].name;
	      error_message (6003);
	    }
	  if ((0 == identtab_loc->hastab_loc[i].l_value_flag) &&
	      (0 != identtab_loc->hastab_loc[i].count))
	    {
	      text = identtab_loc->hastab_loc[i].name;
	      error_message (6006);
	    }
#if 0
	  free (identtab_loc->hastab_loc[i].name);
#endif
	  identtab_loc->hastab_loc[i].name = NULL;
	  clear_internal_type ((identtab_loc->table +
				identtab_loc->hastab_loc[i].def)->type);
	  identtab_loc->hastab_loc[i].def = 0;
	  identtab_loc->hastab_loc[i].count = 0;
	  identtab_loc->hastab_loc[i].use_line_number = 0;
	  identtab_loc->hastab_loc[i].l_value_flag = 0;
	  if (NULL != identtab_loc->hastab_loc[i].next)
	    clear_hash_tab_next (identtab_loc,
				 identtab_loc->hastab_loc[i].next);
	}
    }
  identtab_loc->pi_loc = 0;
  identtab_loc = identtab_loc->previous_level;
  
  return;
}


static void
clear_hash_tab_next_declaration (def)
  struct tab     *def;
{
#if 0
  free (def->name);
#endif
  if (NULL != def->next)
    {
      clear_hash_tab_next_declaration (def->next);
    }
#if 0
  free (def);
#endif
  return;
}


static void
clear_hash_tab_next (tab, def)
  struct ident_tab_header *tab;
  struct tab     *def;
{
  if (!def->count)
    {
      text = def->name;
      error_message (6003);
    }
  if ((0 == def->l_value_flag) && (0 != def->count))
    {
      text = def->name;
      error_message (6006);
    }
#if 0
  free (def->name);
#endif
  clear_internal_type ((tab->table + def->def)->type);
  if (NULL != def->next)
    clear_hash_tab_next (tab, def->next);
#if 0
  free (def);
#endif
  return;
}


void
clear_tag_tab ()
{
  int             i;

  if (! tagtab || tagtab->scope_level < scope_level)
    return;
  
  for (i = 0; i < SIZE_HAS_LOC; i++)
    {
      if (NULL != tagtab->hastab_loc[i].name)
	{
#if 0
	  free (tagtab->hastab_loc[i].name);
#endif
	  tagtab->hastab_loc[i].name = NULL;
	  clear_internal_type ((tagtab->table +
				tagtab->hastab_loc[i].def)->type);
	  tagtab->hastab_loc[i].def = 0;
	  tagtab->hastab_loc[i].count = 0;
	  tagtab->hastab_loc[i].use_line_number = 0;
	  tagtab->hastab_loc[i].l_value_flag = 0;
	  if (NULL != tagtab->hastab_loc[i].next)
	    clear_hash_tab_next (tagtab, tagtab->hastab_loc[i].next);
	}
    }
  tagtab->pi_loc = 0;
  tagtab = tagtab->previous_level;
  
  return;
}

/*
 * Returns address of a global variable.
 */
struct ident_tab *
point (var_name)
  char *var_name;
{
  struct tab     *pa;

  if (NULL == (pa = lookup (var_name)))
    {
      error_message (1000);
      return (NULL);
    }
  else
    {
      pa->count++;
      return (identtab + pa->def);
    }
}


/*
 * Backpatches call of an undefined function during compilation.
 */
int
point_call (func_name)
  char *func_name;
{
  struct tab     *pa;
  struct FIX     *arch;
#if 0
  struct tab *pa_loc = NULL;
  struct ident_tab_header *walk = identtab_loc;

  if (walk)
    {
      while (walk && walk->file_scope != spf[s].name)
	walk = walk->previous_level;
      if (NULL != walk)
	pa_loc = lookup_loc (func_name, walk);
      if (pa_loc != NULL)
	{
	  if (walk->table[pa_loc->def].body);
	  
	}
    }
#endif
  if (NULL == (pa = lookup (func_name)))
    {
      error_message (1000);
      return (-1);
    }
  else
    {
      if (!identtab[pa->def].body)
	{
	  if (NULL == (arch = identtab[pa->def].next))
	    {
	      arch = (struct FIX *) 
		allocate (sizeof (struct FIX), BLOCK);
	      arch->address = kodp;
	      arch->next = NULL;
	      identtab[pa->def].next = arch;
	    } 
	  else
	    {
	      while (NULL != arch->next)
		arch = arch->next;
	      arch->next = (struct FIX *) 
		allocate (sizeof (struct FIX), BLOCK);
	      arch->next->address = kodp;
	      arch->next->next = NULL;
	    }
	}
      return (1);
    }
}


/*
 * Checks table if a variable is in. If not it saves all needed information.
 */
int
has (var_name)
  char *var_name;
{
  struct tab     *np, *arch;

  if (NULL == (np = lookup (var_name)))
    {			/* The variable is not in the table. */
#ifdef DEBUG
      printfx ("New variable included\n");
      printfx ("hash code:%u\n", hash_code (var_name, SIZE_HAS));
#endif
      np = hastab + hash_code (var_name, SIZE_HAS);
      if (NULL == np->name)
	{
	  /* There is no list. */
	  np->name = var_name;
	  np->declaration_line = spf[s].line_counter;
	  putstruct (np);
	}
      else
	{		/* There is a list. */
#ifdef HASH_DEBUG
	  fprintfx (stderr, "variable table chain\n");
#endif
	  do
	    {
	      arch = np;
	      np = np->next;
	    }
	  while (NULL != np);
	  np = (struct tab *) allocate (sizeof (struct tab), PERM);
	  arch->next = np;
	  np->name = var_name;
	  np->declaration_line = spf[s].line_counter;
	  putstruct (np);
	}
      pi++;
      arch = NULL;
      return (1);
    } 
  else
    {			/* The variable is in the table. */
      if (identtab[np->def].body)
	{
	  error_message (1001);	/* Cannot be twice defined. */
	  return (-1);
	} 
      else
	{
	  putstruct_body (np);	/* Function body is now
				 * defined. */
	  if (! strcmp (var_name, "main"))
	    main_defined = 1;
	  return 1;
	}
    }
}


/*
 * Saves useful information about variables and connect the information with
 * the variable name.
 */
static void
putstruct (np)
  struct tab     *np;
{
#ifdef DEBUG
  printfx ("variable name %s is stored\n", np->name);
#endif
  np->def = pi;
#ifdef DEBUG
  printfx ("local pointer:%u is in table\n", np->def);
#endif

  identtab[pi].body = body_flag;
  identtab[pi].next = NULL;
  identtab[pi].adr = NULL;
  identtab[pi].type = typeh[type_spec_count];

  /* If it is a typedef, just put it in the table, do not allocate. */
  if (TYPEDEF_P(typeh[type_spec_count]))
    {
      if (ARRAY_P(typeh[type_spec_count]->output))
	put_array_subscript (&(identtab[pi].type->output));
      return;
    }
  
  switch (typeh[type_spec_count]->attribute.function_class)
    {
    case LOCAL:
    case REMOTE_F:
      if (! identtab[pi].type->output->attribute.memory_size)
	allocate_aggregate (identtab[pi].type->output);
      break;
    case SIMPLE:
      switch (typeh[type_spec_count]->attribute.type_qualifier)
	{
	case CONST_TQ:
	  identtab[pi].adr = identtab[pi].type->attribute.domain;
	  break;
	case VOLATILE_TQ:
	  fprintfx (stderr, "VOLATILE not supported in bookkeeping\n");
	  break;
	default:
	  break;
	}
      identtab[pi].type->attribute.memory_size 
	= allocate_var (identtab[pi].type, &(identtab[pi].adr));
      break;
    case ARRAY:		/* Variables of type array. */
      put_array_subscript (&(identtab[pi].type));
      identtab[pi].body = allocate_aggregate (identtab[pi].type);
      identtab[pi].adr = kodp;
      {
	int i;
	for (i = 0; i < identtab[pi].type->attribute.memory_size;
	     i++)
	  *kodp++ = 0;
      }
      break;
    case ENUM_FC:
      identtab[pi].type->attribute.memory_size 
	= allocate_var (identtab[pi].type, &(identtab[pi].adr));
      break;
    case UNION_FC:		/* Fall through. */
    case STRUCT_FC:
      if (!identtab[pi].body)
	identtab[pi].body = 
	  body_flag = allocate_aggregate (identtab[pi].type);
      identtab[pi].adr = kodp;
      {
	int i;
	for (i = 0; i < identtab[pi].type->attribute.memory_size; i++)
	  *kodp++ = 0;
      }
      break;
    case POINTER:
      identtab[pi].adr = kodp;
      identtab[pi].type->attribute.memory_size = POINTER_SIZE;
      kodp += POINTER_SIZE;
      *(char **)identtab[pi].adr = NULL;
      break;
    case LIB:
      fprintfx (stderr, "LIB not fully supported in book-keeping\n");
      break;
    default:
      fprintfx (stderr, "%s:%d:\n", __FILE__, __LINE__);
      error_message (5002);
      abort ();
    }

#ifdef DEBUG
  printfx ("address %u is in table\n", identtab[pi].adr);
#endif
}


/*
 * Saves information into hash table when body of a function is defined.
 */
static void
putstruct_body (np)
  struct tab     *np;
{
  struct FIX     *arch, *tmp;

  switch (identtab[np->def].type->attribute.function_class)
    {
    case LOCAL:
      identtab[np->def].adr = kodp1;
      identtab[np->def].body = body_flag;
      arch = identtab[np->def].next;
      while (NULL != arch)
	{
	  ((struct OPERAND_1_mi *) (arch->address))->adr = identtab[np->def].adr;
	  tmp = arch;
	  arch = arch->next;
#if 0
	  free (tmp);
#endif
	}
      identtab[np->def].next = NULL;
      break;
    default:
      fprintfx (stderr, "%s:%d:\n", __FILE__, __LINE__);
      error_message (5000);
      abort ();
    }
#ifdef DEBUG
  printfx ("address %u is in table\n", identtab[pi].adr);
#endif
}


/*
 * Looks up the hash table.
 */
static struct tab *
lookup (s)
  char           *s;
{
  struct tab     *ps;

  ps = hastab + hash_code (s, SIZE_HAS);
  if (0 == *(int *) ps)
    return (NULL);
  while (ps->name != s && (NULL != ps->next))
    ps = ps->next;
  if ((NULL == ps->next) && ps->name != s)
    return (NULL);
  else
    return (ps);
}


/* \verbatim{tables_c_hash_code.tex} */

/*
 * Hash function.
 */
static unsigned int
hash_code (s, size)
  char           *s;
  unsigned int size;
{
  int             c = 0;

  while (*s)
    {
      c = c << 1 ^ (*s);
      s++;
    }
  if (0 > c)
    c = (-c);
  return (c % size);
}

/* \verbatim */


/*
 * Returns address of a local variable.
 */
struct ident_tab_loc *
point_loc (var_name)
  char *var_name;
{
  struct tab     *pa = NULL;
  struct ident_tab_header *walk = identtab_loc;
  struct var_s 
  {
    char *adr;
    int offset;
    char *name;
  };
  extern struct var_s variable[];
  register int count = 0;
  
  if (identtab_loc)
    {
				/* Walk through all tables of locals. */
      while (NULL == (pa = lookup_loc (var_name, walk)))
	{
	  if (walk->previous_level)
	    walk = walk->previous_level;
	  else
	    break;
	}
    }
  if (pa)
    {
      struct ident_tab_header *count_walk = walk->previous_level;
      
				/* First try to find offset of the
				   variable. Only if the level > 0 */
      while (count_walk)
	{
	  count += count_walk->offset;
	  count_walk = count_walk->previous_level;
	}
      pa->count++;
      pa->use_line_number = spf[s].line_counter;
      variable[++set].offset = count;
      return walk->table + pa->def;
    }
  else
    return NULL;
}


/*
 * Checks table if a local variable is in. If not it saves all needed
 * information.
 */
int
has_loc (type, var_name)
  int type;
  char *var_name;
{
  struct tab     *np, *arch;

  if (! identtab_loc || identtab_loc->scope_level < scope_level)
    identtab_loc = allocate_loc_tables (identtab_loc);

  if (NULL == (np = lookup_loc (var_name, identtab_loc)))
    {			/* The variable is not in the table. */
#ifdef DEBUG
      printfx ("New local variable included\n");
      printfx ("hash code:%u\n", hash_code (var_name, SIZE_HAS_LOC));
#endif
      np = identtab_loc->hastab_loc + hash_code (var_name, SIZE_HAS_LOC);
      if (NULL == np->name)
	{
	  /* There is no list. */
	  np->name = var_name;
	  np->declaration_line = spf[s].line_counter;
	  putstruct_loc (np, type);
	}
      else
	{		/* There is a list. */
#ifdef HASH_DEBUG
	  fprintfx (stderr, "local variable table chain\n");
#endif
	  do
	    {
	      arch = np;
	      np = np->next;
	    }
	  while (NULL != np);
	  np = (struct tab *) allocate (sizeof (struct tab), BLOCK);
	  arch->next = np;
	  np->name = var_name;
	  np->declaration_line = spf[s].line_counter;
	  putstruct_loc (np, type);
	}
      identtab_loc->pi_loc++;
      if (identtab_loc->pi_loc > ANSI_NUMBER_OF_LOCALS)
	error_message (6007);
      arch = NULL;
      return 1;
    }
  else
    {			/* The variable is in the table. */
      error_message (1003);
      return -1;
    }
}


/*
 * Saves useful information about local variables and connect the information
 * with the variable name.
 */
static void
putstruct_loc (np, type)
  struct tab     *np;
  int type;
{
#ifdef DEBUG
  printfx ("local variable name %s is stored\n", np->name);
#endif
  np->def = identtab_loc->pi_loc;
#ifdef DEBUG
  printfx ("local pointer:%u is in table\n", np->def);
#endif
  identtab_loc->table[identtab_loc->pi_loc].type =
    typeh[type_spec_count];

  /* If it is a typedef, just put it in the table, do not allocate. */
  if (TYPEDEF_P(typeh[type_spec_count]))
    return;

  if (STATIC_P(typeh[type_spec_count]) && type == VAR)
    putstruct_static (&(identtab_loc->table[identtab_loc->pi_loc]));

  switch (typeh[type_spec_count]->attribute.function_class)
    {
    case SIMPLE:
      if (!typeh[type_spec_count]->attribute.memory_size)
	typeh[type_spec_count]->attribute.memory_size = 
	  allocate_struct (typeh[type_spec_count]);
      switch (typeh[type_spec_count]->attribute.type_qualifier)
	{
	case CONST_TQ:
	  identtab_loc->table[identtab_loc->pi_loc].adr =
	    identtab_loc->table[identtab_loc->pi_loc].type->attribute.domain;
	  np->l_value_flag++;
	  np->count++;
	  return;
	  break;
	case VOLATILE_TQ:
	  fprintfx (stderr, "VOLATILE not supported in bookkeeping\n");
	  break;
	default:
	  break;
	}
      
      switch (type)
	{

	case PAR:
	  if (call_by_reference)
	    {
	      identtab_loc->table[identtab_loc->pi_loc].offset
		= -count[proc];
	      count[proc] -= sizeof (char *);
	    }
	  else if (call_by_value)
	    {
	      if (VOID_P(identtab_loc->table[identtab_loc->pi_loc].type))
		error_message (1012);
	      identtab_loc->table[identtab_loc->pi_loc].offset = -count[proc];
	      move_offset_aligned (&count[proc],
				   - identtab_loc->table[identtab_loc->pi_loc].type->attribute.memory_size);
	    }
	  /* Parameters are always initialized. */
	  np->l_value_flag = 1;
	  if (identtab_loc->pi_loc > ANSI_NUMBER_OF_PARAMS)
	    error_message (6008);
	  break;
	case VAR:
	  if (VOID_P(identtab_loc->table[identtab_loc->pi_loc].type))
	    error_message (1012);
	  move_offset_aligned (&count[proc],
			       - allocate_struct (identtab_loc->table[identtab_loc->pi_loc].type));
	  
	  identtab_loc->table[identtab_loc->pi_loc].offset = count[proc];
	  break;
	default:
	  fprintfx (stderr, "%s:%d:\n", __FILE__, __LINE__);
	  error_message (5002);
	  abort ();
	}
      identtab_loc->table[identtab_loc->pi_loc].type->attribute.function_class = SIMPLE;
      break;
    case ARRAY:		/* Local variable of type array. */
      put_array_subscript (&(identtab_loc->table[identtab_loc->pi_loc].type));
      switch (type)
	{
	case PAR:
	  identtab_loc->table[identtab_loc->pi_loc].offset = -count[proc];
	  /* Parameters are always initialized. */
	  np->l_value_flag = 1;
	  count[proc] -= sizeof (char *);
	  break;
	case VAR:
	  if (SIMPLE ==
	      identtab_loc->table[identtab_loc->pi_loc].type->output->attribute.function_class)
	    switch (typeh[type_spec_count]->output->attribute.arit_class)
	      {
	      case INTEGER:
	      case SIGNED_AC | INTEGER:
		count[proc] -= sizeof (int) * count_arr;
		break;
	      case UNSIGNED_AC | INTEGER:
		count[proc] -= sizeof (unsigned int) * count_arr;
		break;
	      case LONG_AC | INTEGER:
	      case LONG_AC | SIGNED_AC | INTEGER:
		count[proc] -= sizeof (long int) * count_arr;
		break;
	      case SHORT_AC | INTEGER:
	      case SHORT_AC | SIGNED_AC | INTEGER:
		count[proc] -= sizeof (short int) * count_arr;
		break;
	      case LONG_AC | UNSIGNED_AC | INTEGER:
		count[proc] -= sizeof (long unsigned int) * count_arr;
		break;
	      case SHORT_AC | UNSIGNED_AC | INTEGER:
		count[proc] -= sizeof (short unsigned int) * count_arr;
		break;
	      case DOUB:
		count[proc] -= sizeof (double) * count_arr;
		break;
	      case LONG_AC | DOUB:
		count[proc] -= sizeof (long double) * count_arr;
		break;
	      case FLT:
		count[proc] -= sizeof (float) * count_arr;
		break;
	      case CHR:
		/* Moze byt este problem so zarovnanim */
		count[proc] -= sizeof (char) * count_arr;
		break;
	      case SIGNED_AC | CHR:
		count[proc] -= sizeof (signed char) * count_arr;
		break;
	      case UNSIGNED_AC | CHR:
		count[proc] -= sizeof (unsigned char) * count_arr;
		break;
	      case VID:
		error_message (1012);
		return;
	      default:
		fprintfx (stderr, "%s:%d:\n", __FILE__, __LINE__);
		error_message (5000);
		abort ();
	      }
	  else
	    {
	      if (!allocate_aggregate (identtab_loc->table[identtab_loc->pi_loc].type))
		error_message (1024);
	      count[proc] -=
		identtab_loc->table[identtab_loc->pi_loc].type->attribute.memory_size;
	    }
	  identtab_loc->table[identtab_loc->pi_loc].offset = count[proc];
	  break;
	default:
	  fprintfx (stderr, "%s:%d:\n", __FILE__, __LINE__);
	  error_message (5002);
	  abort ();
	}
      identtab_loc->table[identtab_loc->pi_loc].type->attribute.function_class = ARRAY;
      break;
    case ENUM_FC:
      if (!typeh[type_spec_count]->attribute.memory_size
	  && type == PAR)
	error_message (1024);
      else if (!typeh[type_spec_count]->attribute.memory_size)
	typeh[type_spec_count]->attribute.memory_size = 
	  allocate_struct (typeh[type_spec_count]);
      
      switch (type)
	{
	case PAR:
	  identtab_loc->table[identtab_loc->pi_loc].offset = -count[proc];
	  /* Parameters are always initialized. */
	  np->l_value_flag = 1;
	  count[proc] -= sizeof (char *);
	  if (identtab_loc->pi_loc > ANSI_NUMBER_OF_PARAMS)
	    error_message (6008);
	  break;
	case VAR:
	  move_offset_aligned (&count[proc], -sizeof (int));
	  break;
	}
      break;
    case UNION_FC:		/* Fall through. */
    case STRUCT_FC:
      if (!typeh[type_spec_count]->attribute.memory_size)
	allocate_aggregate (typeh[type_spec_count]);
      switch (type)
	{
	case PAR:
	  if (!identtab_loc->table[identtab_loc->pi_loc].type->attribute.memory_size)
	    {
	      text = np->name;
	      error_message (1024);
	    }
	  else
	    {
	      identtab_loc->table[identtab_loc->pi_loc].offset = -count[proc];
	      /* Parameters are always initialized. */
	      np->l_value_flag = 1;
	      count[proc] -= sizeof (char *);
	      if (identtab_loc->pi_loc > ANSI_NUMBER_OF_PARAMS)
		error_message (6008);
	    }
	  break;
	case VAR:
	  if (!body_flag)
	    {
	      text = np->name;
	      error_message (1023);
	    }
	  else
	    {
	      count[proc] -=
		identtab_loc->table[identtab_loc->pi_loc].type->attribute.memory_size;
	      count[proc] -= sizeof(double) - count[proc] %
		sizeof(double);
	      identtab_loc->table[identtab_loc->pi_loc].offset =
		count[proc];
	    }
	  break;
	}
      break;
    case POINTER:
      if (!typeh[type_spec_count]->attribute.memory_size)
	typeh[type_spec_count]->attribute.memory_size =
	  POINTER_SIZE;
      switch (type)
	{
	case PAR:
	  identtab_loc->table[identtab_loc->pi_loc].offset = -count[proc];
	  /* Parameters are always initialized. */
	  np->l_value_flag = 1;
	  count[proc] -= sizeof (char *);
	  if (identtab_loc->pi_loc > ANSI_NUMBER_OF_PARAMS)
	    error_message (6008);
	  break;
	case VAR:
	  if (!body_flag)
	    {
	      text = np->name;
	      error_message (1023);
	    }
	  else
	    {
	      move_offset_aligned (&count[proc], -POINTER_SIZE);
	      identtab_loc->table[identtab_loc->pi_loc].offset =
		count[proc];
	    }
	  break;
	}
      break;
    default:
      fprintfx (stderr, "%s:%d:\n", __FILE__, __LINE__);
      error_message (5002);
      abort ();
    }
  
  identtab_loc->table[identtab_loc->pi_loc].previous =
    identtab_loc->all;
  identtab_loc->all = &(identtab_loc->table[identtab_loc->pi_loc]);

#ifdef DEBUG
  printfx ("loc. address %u is in table\n",
	   identtab_loc->table[identtab_loc->pi_loc].offset);
#endif
}


/*
 * Looks up the hash table of local variables.
 */
static struct tab *
lookup_loc (s, identtab_loc)
  char           *s;
  struct ident_tab_header *identtab_loc;
{
  struct tab     *ps;

  ps = identtab_loc->hastab_loc + hash_code (s, SIZE_HAS_LOC);
  if (0 == *(int *) ps)
    return NULL;

  while (ps->name != s && NULL != ps->next)
    ps = ps->next;
  if (NULL == ps->next && ps->name != s)
    return NULL;
  else
    return ps;
}


/*
 * Adding information about type specifiers of formal parameters to the hash
 * table. If it was done during declaration checking if it matches the
 * definition.
 */
int
add_spec_to_has ()
{
  struct tab     *pa;

  if (NULL == (pa = lookup (proc_name_text[proc])))
    {
      error_message (1000);
      return (-1);
    }
  else if (NULL == identtab[pa->def].type->input)
    {
      identtab[pa->def].type->input = l_type_spec;
      l_type_spec = NULL;
    }
  else if (-1 == compare2trees (identtab[pa->def].type->input, l_type_spec))
    return (-1);
  
  return (0);
}


/*
 * Adding identifiers of formal parameters to the hash table. If it was done
 * during declaration checking if it matches the definition.
 */

int
add_ident_to_has ()
{
  struct tab     *pa;
  struct ident_list_str *tmp, *tmp1;

  if (NULL == (pa = lookup (proc_name_text[proc])))
    {
      error_message (1000);
      return (-1);
    }
  else if (NULL == identtab[pa->def].list_formal_param)
    {
      identtab[pa->def].list_formal_param = ident_list;
      ident_list = NULL;
    }
  else
    {
      tmp = identtab[pa->def].list_formal_param;
      while ((NULL != ident_list) && (NULL != tmp))
	{
	  if (!strcmp (ident_list->ident, tmp->ident))
	    {
	      tmp = tmp->next;
	      tmp1 = ident_list;
	      ident_list = ident_list->next;
#if 0
	      free (tmp1);
#endif
	    }
	  else
	    {
	      error_message (2005);
	      return (-1);
	    }
	}
      if ((NULL != tmp) || (NULL != ident_list))
	{
	  error_message (2004);
	  return (-1);
	}
    }
  return (0);
}


void
link_function (i)
  int             i;
{
  struct tab     *np;

  if (NULL != (np = lookup (text)))
    {
#ifdef DEBUG
      printfx ("New variable included\n");
      printfx ("hash code:%u\n", hash_code (text, SIZE_HAS));
#endif
      np = hastab + hash_code (text, SIZE_HAS);
      while (NULL != np->name)
	{
	  if (!strcmp (np->name, text))
	    {
	      if (REMOTE_F == 
		  identtab[np->def].type->attribute.function_class)
		{
		  identtab[np->def].adr = (char *)
		    allocate (sizeof (int), PERM);
		  *(int *) identtab[np->def].adr = i;
		  identtab[np->def].body = 1;
		  break;
		}
	      else
		{
		  error_message (6000);
		  return;
		}
	    }
	  np = np->next;
	}
    }
}


void
set_value (var_name)
  char *var_name;
{
  struct tab     *pa;
  struct ident_tab_header *walk = identtab_loc;
      
  if (identtab_loc)
    {
      while  (NULL == (pa = lookup_loc (var_name, walk)))
	{
	  if (walk->previous_level)
	    walk = walk->previous_level;
	  else
	    break;
	}
      if (pa)
	{
	  if ((0 == pa->l_value_flag) &&
	      (pa->use_line_number != spf[s].line_counter))
	    error_message (6006);
	  pa->l_value_flag++;
	}
    }
}


void
fix_and_clear_goto_table ()
{
  int      i;
  extern int error_line_number;
  
  for (i = 0; i < SIZE_HAS_GOTO; i++)
    {
      if (NULL != hastab_goto[i].name)
	{
	  struct goto_adr *arch, *arch_o;
	  struct goto_tab *arch_goto, *arch_goto_o;
	  
	  arch_goto = hastab_goto + i;
	  arch_goto_o = NULL;
	  while (NULL != arch_goto)
	    {
	      if (NULL == arch_goto->gnext)
		{
		  text = arch_goto->name;
		  error_line_number = arch_goto->line_number;
		  error_message (6004);
		  error_line_number = 0;
		}
	      if (NULL == arch_goto->label_adr)
		{
		  text = arch_goto->name;
		  error_line_number = arch_goto->line_number;
		  error_message (3005);
		  error_line_number = 0;
		  return;
		}
	  
	      arch = arch_goto->gnext;
	      while (NULL != arch)
		{
		  ((struct OPERAND_1_ma *)arch->adr)->adr 
		    = arch_goto->label_adr;
		  arch_o = arch;
		  arch = arch->gnext;
#if 0
		  free (arch_o);
#endif
		}

	      /* First time false (special case),
		 any other times true. */
	      if (NULL != arch_goto_o)
		{
		  arch_goto_o = arch_goto;
		  arch_goto = arch_goto->next;
		  /*free (arch_goto_o);*/
		}
	      else
		{
		  /*free (arch_goto->name);
		    free (arch_goto->label_adr);*/
		  arch_goto->name = NULL;
		  arch_goto->label_adr = NULL;
		  arch_goto->line_number = 0;
		  arch_goto->gnext = NULL;
		  arch_goto_o = arch_goto;
		  arch_goto = arch_goto->next;
		}
	    }
	}
    }
}


/*
 * Add a label into hash table if it was not already in. Add address
 * of the goto to the list of goto's. 
 */
int
has_goto (label_name)
  char *label_name;
{
  struct goto_tab     *np;

  if (NULL == (np = lookup_goto_table  (label_name)))
    {			/* The label is not in the table. */
#ifdef DEBUG
      printfx ("New label included\n");
      printfx ("hash code:%u\n", hash_code (label_name, SIZE_HAS_GOTO));
#endif
      np = hastab_goto + hash_code (label_name, SIZE_HAS_GOTO);
      if (NULL == np->name)
	{		/* There is no list. */
	  np->name = label_name;
	  np->gnext = (struct goto_adr *)
	    allocate (sizeof (struct goto_adr), PERM);
	  np->gnext->adr = kodp;
	  np->gnext->line_number = spf[s].line_counter;
	}
      else
	{		/* There is a list. */
	  struct goto_tab *arch;
#ifdef HASH_DEBUG
	  fprintfx (stderr, "label table chain\n");
#endif
	  do
	    {
	      arch = np;
	      np = np->next;
	    }
	  while (NULL != np);
	  np = (struct goto_tab *)
	    allocate (sizeof (struct goto_tab), PERM);
	  arch->next = np;
	  np->name = label_name;
	  np->gnext = (struct goto_adr *)
	    allocate (sizeof (struct goto_adr), PERM);
	  np->gnext->adr = kodp;
	  np->gnext->line_number = spf[s].line_counter;
	  arch = NULL;
	}
      return (1);
    }
  else
    {			/* The label is in the table. */
      if (NULL != np->gnext)
	{
	  struct goto_adr *arch, *arch_o;
	  
	  arch = np->gnext;
	  do
	    {
	      arch_o = arch;
	      arch = arch->gnext;
	    }
	  while (NULL != arch);
	  arch = (struct goto_adr *)
	    allocate (sizeof (struct goto_adr), PERM);
	  arch_o->gnext = arch;
	  arch->adr = kodp;
	  arch->line_number = spf[s].line_counter;
	  arch_o = NULL;
	}
      else
	{
	  np->gnext = (struct goto_adr *)
	    allocate (sizeof (struct goto_adr), PERM);
	  np->gnext->adr = kodp;
	  np->gnext->line_number = spf[s].line_counter;
	}
      return (1);
    }
}


/* 
 * Add a label into hash table. If it was in, produce error
 * message. Add address of the label to the structure.
 */
int
has_label (label_name)
  char *label_name;
{
  struct goto_tab     *np;

  if (NULL == (np = lookup_goto_table (label_name)))
    {			/* The label is not in the table. */
#ifdef DEBUG
      printfx ("New label included\n");
      printfx ("hash code:%u\n", hash_code (label_name, SIZE_HAS_GOTO));
#endif
      np = hastab_goto + hash_code (label_name, SIZE_HAS_GOTO);
      if (NULL == np->name)
	{		/* There is no list. */
	  np->name = text;
	  np->label_adr = kodp;
	  np->line_number = spf[s].line_counter;
	}
      else
	{		/* There is a list. */
	  struct goto_tab *arch;
#ifdef HASH_DEBUG
	  fprintfx (stderr, "label table chain\n");
#endif
	  do
	    {
	      arch = np;
	      np = np->next;
	    }
	  while (NULL != np);
	  np = (struct goto_tab *)
	    allocate (sizeof (struct goto_tab), PERM);
	  arch->next = np;
	  np->name = text;
	  np->label_adr = kodp;
	  np->line_number = spf[s].line_counter;
	  arch = NULL;
	}
      return (1);
    }
  else
    {			/* The label is in the table. */
      if (NULL == np->label_adr)
	{
	  np->label_adr = kodp;
	  np->line_number = spf[s].line_counter;
	  return (1);
	}
      else
	{
	  error_message (3004);
	  return (-1);
	}
    }
}



/*
 * Looks up the hash table of labels. 
 */
static struct goto_tab *
lookup_goto_table (s)
  char           *s;
{
  struct goto_tab     *ps;

  ps = hastab_goto + hash_code (s, SIZE_HAS_GOTO);
  if (0 == *(int *) ps)
    return (NULL);

  while (ps->name != s && NULL != ps->next)
    ps = ps->next;
  if (NULL == ps->next && ps->name != s)
    return (NULL);
  else
    return (ps);
}


/*
 * Adjust memory position for a type.
 */
void
align_memory (p, n)
  char **p;
  int n;
{
#ifdef HAVE_ASSERT_H
  assert ((n > 0 ? n : -n) <= MAX_CELL_MEMORY_SIZE);
#endif

  while ((long)*p % n)
    (n > 0) ? (*p += sizeof (char)) : (*p -= sizeof (char));
}


int
scope_offset_get ()
{
  if (identtab_loc && !proc)
    return -identtab_loc->offset;
  return 0;
}


int
scope_offset_set (off)
  int off;
{
  if (identtab_loc)
    {
#ifdef HAVE_ASSERT_H
      assert (off < 0);
#endif

      identtab_loc->offset = off;
				/* It must be aligned because of the
				   stack. */
      identtab_loc->offset -= 
	-off % sizeof(double) > 0 ? sizeof(double) - (-off % sizeof (double)) : 0;
      return -identtab_loc->offset;
    }
  return 0;
}

static void
move_offset_aligned (what, size)
  int *what, size;
{
#ifdef HAVE_ASSERT_H
  assert ((size > 0 ? size : -size) <= MAX_CELL_MEMORY_SIZE);
#endif
  
  while ((long) *what % size)
    size > 0 ? (*what += sizeof (char)) : (*what -= sizeof (char));

  *what += size;
}


/*
 * Looks up the hash table.
 */
static struct tab *
lookup_tag (s)
  char           *s;
{
  struct tab     *ps;
  
  ps = tagtab->hastab_loc + hash_code (s, SIZE_HAS_LOC);
  if (0 == *(int *) ps)
    return NULL;

  while (ps->name != s && NULL != ps->next)
    ps = ps->next;
  if ((NULL == ps->next) && ps->name != s)
    return NULL;
  else
    return ps;
}


int
has_tag (tag_only, tag_name)
  int tag_only;
  char *tag_name;
{
  struct tab     *pa = NULL, *arch;
  struct ident_tab_header *walk;

  if (! tagtab || tagtab->scope_level < scope_level)
    tagtab = allocate_loc_tables (tagtab);

  walk = tagtab;
  if (tag_only)
    {
      while (NULL == (pa = lookup_loc (tag_name, walk)))
	{
	  if (walk->previous_level)
	    walk = walk->previous_level;
	  else 
	    break;
	}
    }
  else
    pa = lookup_loc (tag_name, walk);
  
  if (! pa)
    {			/* The variable is not in the table. */
#ifdef DEBUG
      printfx ("New tag included\n");
      printfx ("hash code:%u\n", hash_code (tag_name, SIZE_HAS_LOC));
#endif
      pa = walk->hastab_loc + hash_code (tag_name, SIZE_HAS_LOC);
      if (NULL == pa->name)
	{
	/* There is no list. */
	  pa->name = tag_name;
	  putstruct_tag (pa);
	}
      else
	{		/* There is a list. */
#ifdef HASH_DEBUG
	  fprintfx (stderr, "tag table chain\n");
#endif
	  do
	    {
	      arch = pa;
	      pa = pa->next;
	    }
	  while (NULL != pa);
	  pa = (struct tab *) allocate (sizeof (struct tab), PERM);
	  arch->next = pa;
	  pa->name = tag_name;
	  putstruct_tag (pa);
	}
      walk->pi_loc++;
      arch = NULL;
      return 0;
    } 
  else if (walk->table[pa->def].body && !tag_only) 
                                /* The variable is in the table. */
    {
				/* Cannot be twice defined. */
      if (walk->table[pa->def].type->attribute.function_class !=
	  typeh[type_spec_count]->attribute.function_class)
	error_message (1026);
      else if (STRUCT_P(walk->table[pa->def].type))
	error_message (1017);
      else if (UNION_P(walk->table[pa->def].type))
	error_message (1018);
      else if (ENUM_P(walk->table[pa->def].type))
	error_message (1019);
      return -1;
    } 
  else if (! tag_only)
    {
      if (walk == tagtab)
	{
	  putstruct_tag_body (pa);
				/* Function body is now
				 * defined. */
	  return walk->table[pa->def].body;
	}
      else
	return 0;
    }
  else
    {
      body_flag = walk->table[pa->def].body;
      if (! walk->table[pa->def].body &&
	  struct_union_enum_name[suen_count] != tag_name)
	error_message (1023);
      
      typeh[type_spec_count] = walk->table[pa->def].type;
      return 1;
    }
}


static void
putstruct_tag (np)
  struct tab *np;
{
#ifdef DEBUG
  printfx ("tag name %s is stored\n", np->name);
#endif
  np->def = tagtab->pi_loc;
#ifdef DEBUG
  printfx ("local pointer:%u is in table\n", np->def);
#endif

  tagtab->table[np->def].body = body_flag;
  tagtab->table[np->def].adr = NULL;
  tagtab->table[np->def].type = typeh[type_spec_count];
}

static void
putstruct_tag_body (np)
  struct tab *np;
{
  if (COMPILE_P)
    return;
  tagtab->table[np->def].body =
    body_flag = allocate_aggregate (tagtab->table[np->def].type);
}


/* Adding information about tag specifiers of struct, union or enum
 * fields to the hash table. 
 */
int
add_spec_to_tag ()
{
  struct tab     *pa;

  if (NULL == (pa = lookup_tag (proc_name_text[proc])))
    {
      error_message (1000);
      return -1;
    }
  else if (TYPEDEF_P(tagtab->table[pa->def].type)
	   && NULL == tagtab->table[pa->def].type->input)
    {
      tagtab->table[pa->def].type->output->input = l_type_spec;
      l_type_spec = NULL;
    }
  else if (! TYPEDEF_P(tagtab->table[pa->def].type)
	   && NULL == tagtab->table[pa->def].type->input)
    {
      tagtab->table[pa->def].type->input = l_type_spec;
      l_type_spec = NULL;
    }
  else
    {
      text = proc_name_text[proc];
      switch (tagtab->table[pa->def].type->attribute.function_class)
	{
	case STRUCT_FC:
	  error_message (1017);
	  break;
	case UNION_FC:
	  error_message (1018);
	  break;
	case ENUM_FC:
	  error_message (1019);
	  break;
	default:
	  fprintfx (stderr, "%s:%d:\n", __FILE__, __LINE__);
	  error_message (5000);
	  abort ();
	}
      return -1;
    }
  return 0;
}


/* Adding identifiers of struct, union or enum fields to the hash
 * table. 
 */
int
add_ident_to_tag ()
{
  struct tab     *pa;

  if (NULL == (pa = lookup_tag (proc_name_text[proc])))
    {
      error_message (1000);
      return (-1);
    }
  else if (NULL == tagtab->table[pa->def].list_formal_param)
    {
      tagtab->table[pa->def].list_formal_param = ident_list;
      ident_list = NULL;
    }
  else
    {
      text = proc_name_text[proc];
      switch (tagtab->table[pa->def].type->attribute.function_class)
	{
	case STRUCT_FC:
	  error_message (1017);
	  break;
	case UNION_FC:
	  error_message (1018);
	  break;
	case ENUM_FC:
	  error_message (1019);
	  break;
	default:
	  fprintfx (stderr, "%s:%d:\n", __FILE__, __LINE__);
	  error_message (5000);
	  abort ();
	}
      return -1;
    }
  return 0;
}


/* Allocates place for a variable in the Clif's main memory. Semantic
   for all combinations of variables permitted by ANSI standard. */
static int
allocate_var (type, address)
  struct internal_type *type;
  char **address;
{
  int             char_array_size, count_help = 0;

  if (CONST_TQ == type->attribute.type_qualifier)
    {
      switch (type->attribute.arit_class)
	{
	case INTEGER:
	case SIGNED_AC | INTEGER:
	  return (sizeof (int));
	  break;
	case UNSIGNED_AC | INTEGER:
	  return (sizeof (unsigned int));
	  break;
	case LONG_AC | INTEGER:
	case LONG_AC | SIGNED_AC | INTEGER:
	  return (sizeof (long int));
	  break;
	case SHORT_AC | INTEGER:
	case SHORT_AC | SIGNED_AC | INTEGER:
	  return (sizeof (short int));
	  break;
	case LONG_AC | UNSIGNED_AC | INTEGER:
	  return (sizeof (long unsigned int));
	  break;
	case SHORT_AC | UNSIGNED_AC | INTEGER:
	  return (sizeof (short unsigned int));
	  break;
	case DOUB:
	  return (sizeof (double));
	  break;
	case LONG_AC | DOUB:
	  return (sizeof (long double));
	  break;
	case FLT:
	  return (sizeof (float));
	  break;
	case CHR:
	  return (sizeof (char));
	  break;
	case SIGNED_AC | CHR:
	  return (sizeof (signed char));
	  break;
	case UNSIGNED_AC | CHR:
	  return (sizeof (unsigned char));
	  break;
	default:
	  fprintfx (stderr, "%s:%d:\n", __FILE__, __LINE__);
	  error_message (5000);
	  abort ();
	}
    }
  
  switch (type->attribute.function_class)
    {
    case SIMPLE:
      switch (type->attribute.arit_class)
	{
	case INTEGER:
	case SIGNED_AC | INTEGER:
	  align_memory (&kodp, sizeof(int));
	  *address = kodp;

	  /* Integer variable. */
		      
	  CCI kodp = (int) 0;
	  kodp += sizeof (int);
	  return (sizeof (int));
	  break;
	case UNSIGNED_AC | INTEGER:
	  align_memory (&kodp, sizeof(unsigned int));
	  *address = kodp;
	  CCUI kodp = (unsigned int) 0;
	  kodp += sizeof (unsigned int);
	  return (sizeof (unsigned int));
	  break;
	case LONG_AC | INTEGER:
	case LONG_AC | SIGNED_AC | INTEGER:
	  align_memory (&kodp, sizeof(long int));
	  *address = kodp;
	  CCLI kodp = (long int) 0;
	  kodp += sizeof (long int);
	  return (sizeof (long int));
	  break;
	case SHORT_AC | INTEGER:
	case SHORT_AC | SIGNED_AC | INTEGER:
	  align_memory (&kodp, sizeof(short int));
	  *address = kodp;
	  CCSI kodp = (short int) 0;
	  kodp += sizeof (short int);
	  return (sizeof (short int));
	  break;
	case LONG_AC | UNSIGNED_AC | INTEGER:
	  align_memory (&kodp, sizeof(long unsigned int));
	  *address = kodp;
	  CCLUI kodp = (long unsigned int) 0;
	  kodp += sizeof (long unsigned int);
	  return (sizeof (long unsigned int));
	  break;
	case SHORT_AC | UNSIGNED_AC | INTEGER:
	  align_memory (&kodp, sizeof(short unsigned int));
	  *address = kodp;
	  CCSUI kodp = (short unsigned int) 0;
	  kodp += sizeof (short unsigned int);
	  return (sizeof (short unsigned int));
	  break;
	case DOUB:
	  align_memory (&kodp, sizeof(double));
	  *address = kodp;
		      
	  /* Double variable. */
	  CCD kodp = (double) 0;
	  kodp += sizeof (double);
	  return (sizeof (double));
	  break;
	case LONG_AC | DOUB:
	  align_memory (&kodp, sizeof(long double));
	  *address = kodp;
	  CCLD kodp = (long double) 0;
	  kodp += sizeof (long double);
	  return (sizeof (long double));
	  break;
	case FLT:
	  align_memory (&kodp, sizeof(float));
	  *address = kodp;
		      
	  /* Float variable. */
	  CCF kodp = (float) 0;
	  kodp += sizeof (float);
	  return (sizeof (float));
	  break;
	case CHR:
	  *address = kodp;

	  /* Variable of type char. */
	  CCC kodp = (char) 0;
	  kodp += sizeof (char);
	  return (sizeof (char));
	  break;
	case SIGNED_AC | CHR:
	  *address = kodp;
	  CCSC kodp = (signed char) 0;
	  kodp += sizeof (signed char);
	  return (sizeof (signed char));
	  break;
	case UNSIGNED_AC | CHR:
	  *address = kodp;
	  CCUC kodp = (unsigned char) 0;
	  kodp += sizeof (unsigned char);
	  return (sizeof (unsigned char));
	  break;
	default:
	  fprintfx (stderr, "%s:%d:\n", __FILE__, __LINE__);
	  error_message (5000);
	  abort ();
	}
      break;
    case ARRAY:
      switch (type->output->attribute.arit_class)
	{
	case INTEGER:
	case SIGNED_AC | INTEGER:
	  *address = kodp;
	  count_help = count_arr - 1;
	  while (count_help)
	    {
	      CCI(kodp + count_help * sizeof (int)) = (int) 0;
	      count_help--;
	    }
	  kodp += count_arr * sizeof (int);
	  return (count_arr * sizeof (int));
	  break;
	case UNSIGNED_AC | INTEGER:
	  *address = kodp;
	  count_help = count_arr - 1;
	  while (count_help)
	    {
	      CCUI(kodp + count_help * sizeof (unsigned int)) =
		(unsigned int) 0;
	      count_help--;
	    }
	  kodp += count_arr * sizeof (unsigned int);
	  return (count_arr * sizeof (unsigned int));
	  break;
	case LONG_AC | INTEGER:
	case LONG_AC | SIGNED_AC | INTEGER:
	  *address = kodp;
	  count_help = count_arr - 1;
	  while (count_help)
	    {
	      CCLI(kodp + count_help * sizeof (long int)) =
		(long int) 0;
	      count_help--;
	    }
	  kodp += count_arr * sizeof (long int);
	  return (count_arr * sizeof (long int));
	  break;
	case SHORT_AC | INTEGER:
	case SHORT_AC | SIGNED_AC | INTEGER:
	  *address = kodp;
	  count_help = count_arr - 1;
	  while (count_help)
	    {
	      CCSI(kodp + count_help * sizeof (short int)) =
		(short int) 0;
	      count_help--;
	    }
	  kodp += count_arr * sizeof (short int);
	  return (count_arr * sizeof (short int));
	  break;
	case LONG_AC | UNSIGNED_AC | INTEGER:
	  *address = kodp;
	  count_help = count_arr - 1;
	  while (count_help)
	    {
	      CCLUI(kodp + count_help * sizeof (long unsigned int)) =
		(long unsigned int) 0;
	      count_help--;
	    }
	  kodp += count_arr * sizeof (long unsigned int);
	  return (count_arr * sizeof (long unsigned int));
	  break;
	case SHORT_AC | UNSIGNED_AC | INTEGER:
	  *address = kodp;
	  count_help = count_arr - 1;
	  while (count_help)
	    {
	      CCSUI(kodp + count_help * sizeof (short unsigned int)) =
		(short unsigned int) 0;
	      count_help--;
	    }
	  kodp += count_arr * sizeof (short unsigned int);
	  return (count_arr * sizeof (short unsigned int));
	  break;
	case DOUB:
	  *address = kodp;
	  count_help = count_arr - 1;
	  while (count_help)
	    {
	      CCD(kodp + count_help * sizeof (double)) = (double) 0;
	      count_help--;
	    }
	  kodp += count_arr * sizeof (double);
	  return (count_arr * sizeof (double));
	  break;
	case LONG_AC | DOUB:
	  *address = kodp;
	  count_help = count_arr - 1;
	  while (count_help)
	    {
	      CCLD(kodp + count_help * sizeof (long double)) =
		(long double) 0;
	      count_help--;
	    }
	  kodp += count_arr * sizeof (long double);
	  return (count_arr * sizeof (long double));
	case FLT:
	  *address = kodp;
	  count_help = count_arr - 1;
	  while (count_help)
	    {
	      CCF(kodp + count_help * sizeof (float)) = (float) 0;
	      count_help--;
	    }
	  kodp += count_arr * sizeof (float);
	  return (count_arr * sizeof (float));
	  break;
	case CHR:
	  *address = kodp;
	  count_help = count_arr - 1;
	  while (count_help)
	    {
	      CCC(kodp + count_help * sizeof (char)) = (char) 0;
	      count_help--;
	    }
	  char_array_size = count_arr * sizeof (char);

	  /*
	   * Alignment of char array size.
	   */
	  if (char_array_size & MASKA)
	    {
	      kodp += (4 - (char_array_size & MASKA) +
			char_array_size);
	      return (4 - (char_array_size & MASKA) +
		      char_array_size);
	    }
	  else
	    {
	      kodp += char_array_size;
	      return (char_array_size);
	    }
	  break;
	case SIGNED_AC | CHR:
	  *address = kodp;
	  count_help = count_arr - 1;
	  while (count_help)
	    {
	      CCSC(kodp + count_help * sizeof (signed char)) =
		(signed char) 0;
	      count_help--;
	    }
	  char_array_size = count_arr * sizeof (signed char);

	  /*
	   * Alignment of char array size.
	   */
	  if (char_array_size & MASKA)
	    {
	      kodp += (4 - (char_array_size & MASKA) +
			char_array_size);
	      return (4 - (char_array_size & MASKA) +
		      char_array_size);
	    }
	  else
	    {
	      kodp += char_array_size;
	      return (char_array_size);
	    }
	  break;
	case UNSIGNED_AC | CHR:
	  *address = kodp;
	  count_help = count_arr - 1;
	  while (count_help)
	    {
	      CCUC(kodp + count_help * sizeof (unsigned char)) =
		(unsigned char) 0;
	      count_help--;
	    }
	  char_array_size = count_arr * sizeof (unsigned char);

	  /*
	   * Alignment of char array size.
	   */
	  if (char_array_size & MASKA)
	    {
	      kodp += (4 - (char_array_size & MASKA) +
			char_array_size);
	      return (4 - (char_array_size & MASKA) +
		      char_array_size);
	    }
	  else
	    {
	      kodp += char_array_size;
	      return (char_array_size);
	    }
	  break;
	default:
	  fprintfx (stderr, "%s:%d:\n", __FILE__, __LINE__);
	  error_message (5000);
	  abort ();
	}
      break;
    case ENUM_FC:
      if (INTEGER == type->attribute.arit_class)
	{
	  align_memory (&kodp, sizeof(int));
	  *address = kodp;
	  CCI             kodp = (int) 0;
	  kodp += sizeof (int);
	  return (sizeof (int));
	}
      else
	{
	  fprintfx (stderr, "%s:%d:\n", __FILE__, __LINE__);
	  error_message (5000);
	  abort ();
	}
      break;
    default:
      fprintfx (stderr, "%s:%d:\n", __FILE__, __LINE__);
      error_message (5000);
      abort ();
    }
  return (0);
}


static int
allocate_struct (type)
  struct internal_type *type;
{
  int char_array_size;

  switch (type->attribute.function_class)
    {
    case SIMPLE:
      switch (type->attribute.arit_class)
	{
	case INTEGER:
	case SIGNED_AC | INTEGER:
	  return (sizeof (int));
	  break;
	case UNSIGNED_AC | INTEGER:
	  return (sizeof (unsigned int));
	  break;
	case LONG_AC | INTEGER:
	case LONG_AC | SIGNED_AC | INTEGER:
	  return (sizeof (long int));
	  break;
	case SHORT_AC | INTEGER:
	case SHORT_AC | SIGNED_AC | INTEGER:
	  return (sizeof (short int));
	  break;
	case LONG_AC | UNSIGNED_AC | INTEGER:
	  return (sizeof (long unsigned int));
	  break;
	case SHORT_AC | UNSIGNED_AC | INTEGER:
	  return (sizeof (short unsigned int));
	  break;
	case DOUB:
	  return (sizeof (double));
	case LONG_AC | DOUB:
	  return (sizeof (long double));
	  break;
	case FLT:
	  return (sizeof (float));
	case CHR:
	  return (sizeof (char));
	case SIGNED_AC | CHR:
	  return (sizeof (signed char));
	  break;
	case UNSIGNED_AC | CHR:
	  return (sizeof (unsigned char));
	  break;
	case VID:
	  return 0;
	default:
	  fprintfx (stderr, "%s:%d:\n", __FILE__, __LINE__);
	  error_message (5000);
	  abort ();
	}
      break;
    case ARRAY:
      switch (type->output->attribute.arit_class)
	{
	case INTEGER:
	case SIGNED_AC | INTEGER:
	  return (count_arr * sizeof (int));
	  break;
	case UNSIGNED_AC | INTEGER:
	  return (count_arr * sizeof (unsigned int));
	  break;
	case LONG_AC | INTEGER:
	case LONG_AC | SIGNED_AC | INTEGER:
	  return (count_arr * sizeof (long int));
	  break;
	case SHORT_AC | INTEGER:
	case SHORT_AC | SIGNED_AC | INTEGER:
	  return (count_arr * sizeof (short int));
	  break;
	case LONG_AC | UNSIGNED_AC | INTEGER:
	  return (count_arr * sizeof (long unsigned int));
	  break;
	case SHORT_AC | UNSIGNED_AC | INTEGER:
	  return (count_arr * sizeof (short unsigned int));
	  break;
	case DOUB:
	  return (count_arr * sizeof (double));
	case LONG_AC | DOUB:
	  return (count_arr * sizeof (long double));
	  break;
	case FLT:
	  return (count_arr * sizeof (float));
	case CHR:
	  char_array_size = count_arr * sizeof (char);

	  /*
	   * Alignment of char array size.
	   */
	  if (char_array_size & MASKA)
	    return (4 - (char_array_size & MASKA) +
		    char_array_size);
	  else
	    return (char_array_size);
	  break;
	case SIGNED_AC | CHR:
	  char_array_size = count_arr * sizeof (signed char);
	  /*
	   * Alignment of char array size.
	   */
	  if (char_array_size & MASKA)
	    return (4 - (char_array_size & MASKA) +
		    char_array_size);
	  else
	    return (char_array_size);
	  break;
	case UNSIGNED_AC | CHR:
	  char_array_size = count_arr * sizeof (unsigned char);
	  /*
	   * Alignment of char array size.
	   */
	  if (char_array_size & MASKA)
	    return (4 - (char_array_size & MASKA) +
		    char_array_size);
	  else
	    return (char_array_size);
	  break;
	case VID:
	  return 0;
	default:
	  fprintfx (stderr, "%s:%d:\n", __FILE__, __LINE__);
	  error_message (5000);
	  abort ();
	}
      break;
    case ENUM_FC:
      return (sizeof (int));
      break;
    case POINTER:
      return (POINTER_SIZE);
      break;
    default:
      fprintfx (stderr, "%s:%d:\n", __FILE__, __LINE__);
      error_message (5000);
      abort ();
    }
  return 0;
}


/* Return offset in the current structure, or -1 if name is not a
   member. */
static int
find_member (name, type_to_find)
  char *name;
  struct internal_type *type_to_find;
{
  int offset = 0;

  for (; type_to_find != NULL &&
	 strcmp (name, type_to_find->field_name);
       type_to_find = type_to_find->arity)
    ;

  if (NULL == type_to_find)
    {
      text = name;
      error_message (2008);
      return (-1);
    }
  offset = type_to_find->offset;

  type_com[set] = type_to_find;
  if (POINTER_P(type_com[set]))
    type_ac[set] = LONG_AC | INTEGER;
  else
    type_ac[set] = type_to_find->attribute.arit_class;
  return (offset);
}


int
offset_aggregate_ident ()
{
  return (find_member (text, type_com[set]));
}

static int
allocate_aggregate (type)
  struct internal_type *type;
{
  struct internal_type *walk = type->input;
  int size = 0;
  int first_align =0;

  if (TYPEDEF_P(type) && ! type->attribute.memory_size)
    {
      type->attribute.memory_size
	= allocate_aggregate (type->output);
      return 1;
    }

  if (SIMPLE_P(type) && ! type->attribute.memory_size)
    {
      type->attribute.memory_size = allocate_struct (type);
      return 1;
    }
  
  if (ENUM_P(type) && ! type->attribute.memory_size)
    {
      type->attribute.memory_size = allocate_struct (type);
      return 1;
    }

  if (NULL == walk)
    return 0;
  
  switch (type->attribute.function_class)
    {
    case ARRAY:
    {
      if (!type->output->attribute.memory_size)
	allocate_aggregate (type->output);
      size = 1;
      if (0 >= ((struct range *)walk->attribute.domain)->upper)
	return 0;
      while (walk)
	{
	  size *= (((struct range *) walk->attribute.domain)->upper
	    - ((struct range *) walk->attribute.domain)->lower);
	  walk->attribute.memory_size =
	    size * type->output->attribute.memory_size;
	  walk = walk->arity;
	}
      type->attribute.memory_size = size
	* type->output->attribute.memory_size;
    }
    break;
    case STRUCT_FC:
      while (walk)
	{
	  if (!walk->attribute.memory_size)
	    {
	      if (ARRAY_P(walk) || STRUCT_P(walk))
		allocate_aggregate (walk);
	      else
		walk->attribute.memory_size += allocate_struct (walk);
	    }
	  type->attribute.memory_size
	    += walk->attribute.memory_size;
	  /* First structure member must be always aligned. */
	  if (!first_align)
	    first_align = 
	      walk->attribute.memory_size > MAX_ALIGNMENT ?
	      MAX_ALIGNMENT : walk->attribute.memory_size;
	  /* We have to find out if the alignment occured. */
	  if (walk->attribute.memory_size <= MAX_ALIGNMENT)
	    size = type->attribute.memory_size %
	      walk->attribute.memory_size;
	  else
	    size = type->attribute.memory_size % MAX_ALIGNMENT;
	  if (size > 0 
	      && walk->attribute.memory_size <= MAX_ALIGNMENT)
	    type->attribute.memory_size +=
	      walk->attribute.memory_size - size;
	  else if (size > 0)
	    type->attribute.memory_size +=
	      MAX_ALIGNMENT - size;
	  walk->offset = type->attribute.memory_size -
	    walk->attribute.memory_size;
	  walk = walk->arity;
	}
      size = type->attribute.memory_size % first_align;
      if (size > 0)
	/* If the size of the structure is not aligned according to
	   the first structure member, do it now. If it wouldn't be
	   aligned, then it cannot be in the array. */
	type->attribute.memory_size += first_align - size;
      break;
    case UNION_FC:
      while (walk)
	{
	  if (!walk->attribute.memory_size)
	    {
	      if (ARRAY_P(walk) || STRUCT_P(walk))
		allocate_aggregate (walk);
	      else
		walk->attribute.memory_size = allocate_struct (walk);
	    }
	  if (type->attribute.memory_size < walk->attribute.memory_size)
	    {
	      type->attribute.memory_size
		= walk->attribute.memory_size;
	      /* We have to find out if the alignment occured. */
	      if (walk->attribute.memory_size <= MAX_ALIGNMENT)
		size = type->attribute.memory_size %
		  walk->attribute.memory_size;
	      else
		size = type->attribute.memory_size % MAX_ALIGNMENT;
	      if (size > 0 
		  && walk->attribute.memory_size <= MAX_ALIGNMENT)
		type->attribute.memory_size +=
		  walk->attribute.memory_size - size;
	      else if (size > 0)
		type->attribute.memory_size +=
		  MAX_ALIGNMENT - size;
	    }
	  walk = walk->arity;
	}
      break;
    default:
      fprintfx (stderr, "%s:%d:\n", __FILE__, __LINE__);
      error_message (5002);
      abort ();
      break;
    }
  return 1;
}


/* Static variables are put into tables. */
static void
putstruct_static (type)
  struct ident_tab_loc *type;
{
  switch (type->type->attribute.function_class)
    {
    case LOCAL:
    case REMOTE_F:
      break;
    case SIMPLE:
      switch (type->type->attribute.type_qualifier)
	{
	case CONST_TQ:
	  type->adr = type->type->attribute.domain;
	  break;
	case VOLATILE_TQ:
	  fprintfx (stderr, "VOLATILE not supported in bookkeeping\n");
	  break;
	default:
	  break;
	}
      type->type->attribute.memory_size 
	= allocate_var (type->type, &(type->adr));
      break;
    case ARRAY:		/* Variables of type array. */
      put_array_subscript (&(type->type));
      type->body = allocate_aggregate (type->type);
      type->adr = kodp;
      {
	int i;
	for (i = 0; i < type->type->attribute.memory_size;
	     i++)
	  *kodp++ = 0;
      }
      break;
    case ENUM_FC:
      type->type->attribute.memory_size 
	= allocate_var (type->type, &(type->adr));
      break;
    case STRUCT_FC:
      if (!type->body)
	type->body = 
	  body_flag = allocate_aggregate (type->type);
      type->adr = kodp;
      {
	int i;
	for (i = 0; i < type->type->attribute.memory_size; i++)
	  *kodp++ = 0;
      }
      break;
    case UNION_FC:
      if (!type->body)
	type->body =
	  body_flag = allocate_aggregate (type->type);
      type->adr = kodp;
      {
	int i;
	for (i = 0; i < type->type->attribute.memory_size; i++)
	  *kodp++ = 0;
      }
      break;
    case POINTER:
      type->adr = kodp;
      kodp += POINTER_SIZE;
      *(char **)type->adr = NULL;
      break;
    case LIB:
      fprintfx (stderr, "LIB not fully supported in book-keeping\n");
      break;
    default:
      fprintfx (stderr, "%s:%d:\n", __FILE__, __LINE__);
      error_message (5002);
      abort ();
    }
}


/* The enter_file_scope and exit_file_scope have special meaning. They
 are used in file scope static variables. */
void
enter_file_scope ()
{
  if (!identtab_loc)
    identtab_loc = allocate_loc_tables (identtab_loc);

  if (identtab_loc->file_scope != spf[s].name)
    identtab_loc->file_scope = spf[s].name;
}


void
exit_file_scope ()
{
  if (identtab_loc && identtab_loc->file_scope == spf[s].name)
    identtab_loc->file_scope = NULL;
}


/* If the name is declared as typedef return it as TYPENAME token -
   true (1); IDENT - false (0), otherwise. */
int
typedef_p (name)
  char *name;
{
  struct tab *pa = NULL;
  struct ident_tab_header *walk = identtab_loc;
  
  if (! typedef_f)
    return 0;
  
  if (identtab_loc)
    {
      /* Walk through all tables of locals. */
      while (NULL == (pa = lookup_loc (name, walk)))
	{
	  if (walk->previous_level)
	    walk = walk->previous_level;
	  else
	    break;
	}
    }
  if (pa && TYPEDEF_P((walk->table + pa->def)->type))
    return 1;
  else if (NULL == pa)
    {
      pa = lookup (name);
      if (pa && TYPEDEF_P((identtab + pa->def)->type))
	return 1;
    }
  return 0;
}

/* Returns the declaration line of a variable. Called from
   error_message function. */
int
get_declaration_line (name)
  char *name;
{
  struct tab *pa = NULL;
  struct ident_tab_header *walk = identtab_loc;
  
  if (identtab_loc)
    {
      /* Walk through all tables of locals. */
      while (NULL == (pa = lookup_loc (name, walk)))
	{
	  if (walk->previous_level)
	    walk = walk->previous_level;
	  else
	    break;
	}
    }
  if (pa)
    return pa->declaration_line;

  pa = lookup (name);
  if (pa)
    return pa->declaration_line;
  return 0;
}


/* Walk recursively through the type tree. Return the size of the
   subtype. */
static int
memory_size (level, walk)
  int *level;
  struct internal_type *walk;
{
  int result = 0;
  
  if (! *level && walk->attribute.memory_size)
    return walk->attribute.memory_size;

  if (*level && ! result && walk->output)
    {
      *level -= 1;
      result = memory_size (level, walk->output);
      if (ARRAY_P(walk) &&
	  ! (STRUCT_P(walk->output) || UNION_P(walk->output)))
	{
	  /* If the array has as fields structures or unions, we must
	     walk down the subtypes to know the sizes. */
	  *level += 1;
	  result = 0;
	}
    }

  if (*level && ! result && walk->input)
    {
      if (! ARRAY_P(walk))
	*level -= 1;
      result = memory_size (level, walk->input);
    }
  
  if (*level && ! result && walk->arity)
    {
      *level -= 1;
      result = memory_size (level, walk->arity);
    }

  return result;
}


/* Find out if the number of brackets is equal to the number of
   subtypes declared in the type, i.e. the initialization expression
   is fully bracketed. */
static void
check_init_bracket (level, walk, buf)
  int *level;
  struct internal_type *walk;
  char *buf;
{
  /* Trying to reconstruct the initializer in the case of an error. */
  if (STRUCT_P(walk) && 
      (strlen (walk->input->field_name) + strlen (buf) < BUFSIZ - 1))
    {
      strcat (buf, ".");
      strcat (buf, walk->input->field_name);
    }
  else if ((ARRAY_P(walk) || walk->arity) && (strlen (buf) + 4 < BUFSIZ))
    strcat (buf, "[0]");

  if (walk->output)
    {
      *level += 1;
      check_init_bracket (level, walk->output, buf);
      if (ARRAY_P(walk))
	{
	  int i = strlen (buf) - 1;
	  if (']' == buf[i])
	    buf[i - 2] = '\0';
	  *level -= 1;
	}
    }
  if (walk->input)
    {
      *level += 1;
      check_init_bracket (level, walk->input, buf);
      if (walk->arity)
	*level -= 1;
    }
  if (walk->arity)
    {
      *level += 1;
      check_init_bracket (level, walk->arity, buf);
    }
}

/* Wrapper to error reporting and memory size. */
int
get_memory_size (level, walk, initializer_number)
  int level;
  struct internal_type *walk;
  int initializer_number;
{
  char buf[BUFSIZ];
  static int aggregate_level;
  int j;
  
  if (1 == initializer_number)
    {
      aggregate_level = 0;
      if (strncpy (buf, text, BUFSIZ))
	check_init_bracket (&aggregate_level, walk, buf);
      if (aggregate_level > level)
	error_message (6030, buf);
    }

  if (1 == level)
    j = 1;
  else
    j = aggregate_level - level;
  return memory_size (&j, walk);
}


/* Recursive funtion. Returns the size of the field in struct or
   union. Called during variable initialization. */
int
get_field_size (pos, walk)
  int *pos;
  struct internal_type *walk;
{
  int result = 0;
  
  if (SIMPLE_P(walk) && walk->attribute.memory_size)
    {
      result =  walk->attribute.memory_size;
      (*pos)--;
    }

  if (*pos && !SIMPLE_P(walk) && walk->output)
    result = get_field_size (pos, walk->output);

  if (*pos && (STRUCT_P(walk) || UNION_P(walk)) && walk->input)
    result = get_field_size (pos, walk->input);
  
  return result;
}


/* If the local variable was not initialized, usage counter is reset. */
void
noninitialized_loc (var_name)
  char *var_name;
{
  struct tab     *pa = NULL;
  
  if (identtab_loc)
    pa = lookup_loc (var_name, identtab_loc);

  if (pa)
    {
      pa->count--;
      pa->use_line_number = 0;
    }
}
