/*
    Clif - A C-like Interpreter Framework
    Copyright (C) 1998, 2000 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.

*/

struct var_s
{
  char *adr;
  int offset;
  char *name;
};

#include <stdio.h>
#include "allocx.h"
#include "flags.h"
#include "global.h"
#include "tables.h"
#include "type.h"
#include "struct.h"
#include "comp_maint.h"
#include "instr.h"
#include "geninstr.h"
#include "pso.h"

/* Lookup in tables of local variables, if the variable is not found
   in the table of global variables. Setting of addresses for code
   generation. */
void
lookup_tables (var_name, variable)
  char *var_name;
  struct var_s variable[];
{
  struct ident_tab_loc *loc_var;
  if (NULL == (loc_var = point_loc (var_name)))
    {
      struct ident_tab *var;
      var = point (var_name);
      if (NULL == var)
	COMPILE_ONLY;
      if ((STRUCT_P(var->type)
	   || UNION_P(var->type))
	  && -1 == add_to_ident_list ())
	COMPILE_ONLY;
      variable[++set].adr = var->adr;
      variable[set].name = var_name;
      variable[set].offset = 0;
      type_com[set] = var->type;
    }
  else
    {
      /* Address is non NULL only if the
	 local variable is declared static. */
      if (NULL != loc_var->adr)
	{
	  variable[set].offset = 0;
	  variable[set].adr = loc_var->adr;
	  variable[set].name = var_name;
	}
      else
	{
	  /* First part of the offset is set in the
	     point_loc function. */
	  variable[set].offset += loc_var->offset;
	  variable[set].adr = NULL;
	  variable[set].name = var_name;
	}
      type_com[set] = loc_var->type;
    }
  if (NULL == type_com[set]->output)
    type_ac[set] = type_com[set]->attribute.arit_class;
  else if (LOCAL_P(type_com[set])
	   || REMOTE_P(type_com[set]))
    {
      type_ac[set] =
	type_com[set]->output->attribute.arit_class;
      proc_name_text[++proc] = text;
    }
  else if (ARRAY_P(type_com[set]))
    {
      type_ac[set] =
	type_com[set]->output->attribute.arit_class;
      array_subscript (type_com[set]->input);
    }
  else if (POINTER_P(type_com[set]))
    type_ac[set] = LONG_AC | INTEGER;
  kodp4 = kodp;
  if (0 < variable[set].offset)
    {
      if (call_by_value)
	{
	  if (ARRAY_P(type_com[set]))
	    {
	      GEN_PUSHArr(variable[set].offset);
	    }
	  else
	    {
	      GEN_PUSHAr(variable[set].offset);
	    }
	}
      else if (call_by_reference)
	{
	  GEN_PUSHArr(variable[set].offset);
	}
      GENCODE;
    }
  else if (0 > variable[set].offset)
    {
      GEN_PUSHAr(variable[set].offset); GENCODE;
    }
  else if (! LOCAL_P(type_com[set])
	   && ! REMOTE_P(type_com[set]))
    {
      GEN_PUSHA(variable[set].adr); GENCODE;
    }
}


/* The typedef structure (only the beginning part) is copied, if
   any non simple part was inserted, i.e. pointer, function, array,
   struct, etc. */
void
typedef_copy (type)
  struct internal_type *type;
{
  typeh[type_spec_count] = (struct internal_type *) 
    allocate (sizeof(struct internal_type), 
	      scope_level > PERM ? BLOCK : PERM);
  init_zero ((char *)typeh[type_spec_count],
	     sizeof(struct internal_type));
  typeh[type_spec_count]->attribute.function_class =
    SIMPLE;
  typeh[type_spec_count]->attribute.type_qualifier =
    UNDEF_TQ;
  typeh[type_spec_count]->attribute.arit_class =
    UNUSED_AC;
  typeh[type_spec_count]->attribute.storage_class_specifier =
    TYPEDEF_SC;
  typeh[type_spec_count]->output = type;
}


/* For cast operator, size of operand is returned. */
int
set_memory_size (arit_class)
  enum intern_arit_class arit_class;
{
  switch (arit_class)
    {
    case INTEGER:
    case SIGNED_AC | INTEGER:
      return sizeof (int);
    case UNSIGNED_AC | INTEGER:
      return sizeof (unsigned int);
    case LONG_AC | INTEGER:
    case LONG_AC | SIGNED_AC | INTEGER:
      return sizeof (long int);
    case SHORT_AC | INTEGER:
    case SHORT_AC | SIGNED_AC | INTEGER:
      return sizeof (short int);
    case LONG_AC | UNSIGNED_AC | INTEGER:
      return sizeof (long unsigned int);
    case SHORT_AC | UNSIGNED_AC | INTEGER:
      return sizeof (short unsigned int);
    case DOUB:
      return sizeof (double);
    case LONG_AC | DOUB:
      return sizeof (long double);
    case FLT:
      return sizeof (float);
    case CHR:
      /* Moze byt este problem so zarovnanim */
      return sizeof (char);
    case SIGNED_AC | CHR:
      return sizeof (signed char);
    case UNSIGNED_AC | CHR:
      return sizeof (unsigned char);
    case VID:
    default:
      return 0;
    }
  return 0;
}
