/********************************************************************
This file is part of the abs 0.907 distribution.  abs is a spreadsheet
with graphical user interface.

Copyright (C) 1998-2001  André Bertin (Andre.Bertin@ping.be) 

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 if in the same spirit as version 2.

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.

Concact: abs@pi.be
         http://home.pi.be/bertin/abs.shtml

*********************************************************************/


























#include "oper.h"
#include <math.h>
#include "stdlib.h"
#include "stdio.h"
#include "y.tab.h"
#include "libfct.h"		
#include "string.h"
#include "memory.h"

static obj absERROR =
{
  {0}, STRING_CONSTANT, NULL};

obj
mkassign (o1, o2)
     obj o1, o2;
{
  if (o2.type == IDENTIFIER)
    o2 = obj2val (o2);

  if (o2.type == MEMBER)
    o2 = member2val (o2);

  if (o1.type == MEMBER)
    {
      obj oarg[2];
      int member;
      int class = getbaseclass (o1);
      if (class < 0)
	return o1;
      member = getmemberpos (class, o1);
      if (member < 0)
	return o1;
      oarg[0] = o1;
      oarg[1] = o2;
      (arrayclass[class].data[member].setfct) (2, oarg);
      freenocstobj (o1);
      return o1;
    }


  freenocstobj (o1);
  if (o1.type == IDENTIFIER)
    {
      o1eqo2 (&o1, o2);
      return o1;
    }

  
  mkclassassign (o1, o2);

  return o1;
}

obj
mksumassign (o1, o2)
     obj o1, o2;
{
  mkassign (o1, mksum (o1, o2));
  return o1;
}


obj
mkplusplus (o1)
     obj o1;
{
  if (o1.type != IDENTIFIER)
    return o1;

  o1plusplus (&o1);

  return o1;
}
obj
mkminusminus (o1)
     obj o1;
{
  if (o1.type != IDENTIFIER)
    return o1;

  o1moinsmoins (&o1);

  return o1;
}


obj
mksum (o1, o2)
     obj o1, o2;
{
  obj o3;
  o1 = obj2val (o1);
  o2 = obj2val (o2);
  o3 = o1;
  if (o1.type == o2.type)
    {
      switch (o1.type)
	{
	case INTEGER:
	  o3.rec.i += o2.rec.i;
	  return o3;
	case DOUBLE:
	  o3.rec.d += o2.rec.d;
	  return o3;
	case STRING_CONSTANT:	/*concat.. */ ;
	  return o3;
	default:
	  {
	    o3.rec.d = obj2double (o1) + obj2double (o2);
	    o3.type = DOUBLE;
	    return o3;
	  }
	}
    }
  else
    {
      o3.rec.d = obj2double (o1) + obj2double (o2);
      o3.type = DOUBLE;
    }
  return o3;
}

obj
mkdiff (o1, o2)
     obj o1, o2;
{
  obj o3;
  o1 = obj2val (o1);
  o2 = obj2val (o2);
  o3 = o1;

  if (o1.type == o2.type)
    {
      switch (o1.type)
	{
	case INTEGER:
	  o3.rec.i -= o2.rec.i;
	  return o3;
	case DOUBLE:
	  o3.rec.d -= o2.rec.d;
	  return o3;
	case STRING_CONSTANT:	/*concat.. */ ;
	  return o3;
	default:
	  {
	    o3.rec.d = obj2double (o1) - obj2double (o2);
	    o3.type = DOUBLE;
	    return o3;
	  }
	}
    }
  else
    {
      o3.rec.d = obj2double (o1) - obj2double (o2);
      o3.type = DOUBLE;
    }
  return o3;
}


obj
mkuminus (o1)
     obj o1;
{
  obj o3;
  o1 = obj2val (o1);
  o3.type = o1.type;
  o3.label = o1.label;


  switch (o1.type)
    {
    case INTEGER:
      o3.rec.i = -o1.rec.i;
      return o3;
    case DOUBLE:
      o3.rec.d = -o1.rec.d;
      return o3;
    case STRING_CONSTANT:	/*concat.. */ ;
      return o3;
    default:
      {
	o3.rec.d = -obj2double (o1);
	o3.type = DOUBLE;
	return o3;
      }
    }

}

obj
mkmult (o1, o2)
     obj o1, o2;
{
  obj o3;
  o1 = obj2val (o1);
  o2 = obj2val (o2);
  o3 = o1;

  if (o1.type == o2.type)
    {
      switch (o1.type)
	{
	case INTEGER:
	  o3.rec.i *= o2.rec.i;
	  return o3;
	case DOUBLE:
	  o3.rec.d *= o2.rec.d;
	  return o3;
	case STRING_CONSTANT:	/*concat.. */ ;
	  return o3;
	default:
	  {
	    o3.rec.d = obj2double (o1) * obj2double (o2);
	    o3.type = DOUBLE;
	    return o3;
	  }
	}
    }
  else
    {
      o3.rec.d = obj2double (o1) * obj2double (o2);
      o3.type = DOUBLE;
    }
  return o3;
}

obj
mkdiv (o1, o2)
     obj o1, o2;
{
  obj o3;
  o1 = obj2val (o1);
  o2 = obj2val (o2);
  o3 = o1;
  absERROR.rec.s = "!DIV0";

  if ((o2.type == INTEGER && o2.rec.i == 0) ||
      (o2.type == DOUBLE && o2.rec.d == 0.0))
    return absERROR;


  if (o1.type == o2.type)
    {
      switch (o1.type)
	{
	case DOUBLE:
	  o3.rec.d /= o2.rec.d;
	  return o3;
	case STRING_CONSTANT:	/*concat.. */ ;
	  return o3;
	default:
	  {
	    if (obj2double (o2) == 0.0)
	      return absERROR;
	    o3.rec.d = obj2double (o1) / obj2double (o2);
	    o3.type = DOUBLE;
	    return o3;
	  }
	}
    }
  else
    {
      if (obj2double (o2) == 0.0)
	return absERROR;
      o3.rec.d = obj2double (o1) / obj2double (o2);
      o3.type = DOUBLE;
    }
  return o3;
}

obj
mkmod (o1, o2)
     obj o1, o2;
{
  obj o3;
  o1 = obj2val (o1);
  o2 = obj2val (o2);
  o3.label = NULL;
  o3.type = DOUBLE;
  absERROR.rec.s = "!DIV0";

  if ((o2.type == INTEGER && o2.rec.i == 0) ||
      (o2.type == DOUBLE && o2.rec.d == 0.0))
    return absERROR;


  if (o1.type == DOUBLE && DOUBLE == o2.type)
    {
      o3.rec.d = fmod (o1.rec.d, o2.rec.d);
      return o3;
    }
  else
    {
      if (obj2double (o2) == 0.0)
	return absERROR;
      o3.rec.d = fmod (obj2double (o1), obj2double (o2));
    }
  return o3;
}

obj
mkintdiv (o1, o2)
     obj o1, o2;
{
  obj o3;
  o1 = obj2val (o1);
  o2 = obj2val (o2);
  o3.label = NULL;
  absERROR.rec.s = "!DIV0";

  if (obj2int (o2) == 0)
    return absERROR;
  o3.rec.i = obj2int (o1) / obj2int (o2);
  o3.type = INTEGER;

  return o3;
}


obj
mkpow (o1, o2)
     obj o1, o2;
{
  obj o3;
  o1 = obj2val (o1);
  o2 = obj2val (o2);
  o3.label = NULL;
  if (o1.type == o2.type)
    {
      switch (o1.type)
	{			
	case DOUBLE:
	  o1.rec.d = pow (o1.rec.d, o2.rec.d);
	  return o3;
	case STRING_CONSTANT:	/*concat.. */ ;
	  return o3;
	default:
	  {
	    o3.rec.d = pow (obj2double (o1), obj2double (o2));
	    o3.type = DOUBLE;
	    return o3;
	  }
	}
    }
  else
    {
      o3.rec.d = pow (obj2double (o1), obj2double (o2));
      o3.type = DOUBLE;
    }
  return o3;

}


obj
mklt (o1, o2)
     obj o1, o2;
{
  obj o3;

  o3.type = INTEGER;
  o3.rec.i = (obj2double (o1) < obj2double (o2)) ? 1 : 0;
  o3.label = NULL;

  return o3;
}

obj
mkgt (o1, o2)
     obj o1, o2;
{
  obj o3;
  o3.type = INTEGER;
  o3.rec.i = (obj2double (o1) > obj2double (o2)) ? 1 : 0;
  o3.label = NULL;
  return o3;
}

obj
mkge (o1, o2)
     obj o1, o2;
{
  obj o3;
  o3.type = INTEGER;
  o3.rec.i = (obj2double (o1) >= obj2double (o2)) ? 1 : 0;
  o3.label = NULL;
  return o3;
}

obj
mkle (o1, o2)
     obj o1, o2;
{
  obj o3;
  o3.type = INTEGER;
  o3.rec.i = (obj2double (o1) <= obj2double (o2)) ? 1 : 0;
  o3.label = NULL;
  return o3;
}

obj
mkne (o1, o2)
     obj o1, o2;
{
  obj o3;
  o3.type = INTEGER;
  if (objisstring (o1) && objisstring (o2))
    {
      printobj (o1);
      printobj (o2);
      o3.rec.i = (strcmp (obj2string (o1), obj2string (o2)) ? 1 : 0);
      printobj (o3);
    }
  else
    {
      o3.rec.i = (obj2double (o1) != obj2double (o2)) ? 1 : 0;
    }
  o3.label = NULL;

  return o3;
}

obj
mkeq (o1, o2)
     obj o1, o2;
{
  obj o3;
  o3.type = INTEGER;
  if (objisstring (o1) && objisstring (o2))
    {
      o3.rec.i = (strcmp (obj2string (o1), obj2string (o2)) ? 0 : 1);
    }
  else
    {
      o3.rec.i = (obj2double (o1) == obj2double (o2)) ? 1 : 0;
    }
  o3.label = NULL;
  return o3;
}

obj
mkor (o1, o2)
     obj o1, o2;
{
  obj o3;
  o3.type = INTEGER;
  o3.rec.i = (obj2double (o1) != 0 || obj2double (o2) != 0) ? 1 : 0;
  o3.label = NULL;
  return o3;
}

obj
mkand (o1, o2)
     obj o1, o2;
{
  obj o3;
  o3.type = INTEGER;
  o3.rec.i = (obj2double (o1) != 0 && obj2double (o2) != 0) ? 1 : 0;
  o3.label = NULL;
  return o3;
}

obj
mkxor (o1, o2)
     obj o1, o2;
{
  obj o3;
  o3.type = INTEGER;
  o3.rec.i = ((obj2int (o1) == 0 && obj2int (o2) != 0) ||
	      (obj2int (o1) != 0 && obj2int (o2) == 0)) ? 1 : 0;
  o3.label = NULL;
  return o3;
}

obj
mkeqv (o1, o2)
     obj o1, o2;
{
  obj o3;
  o3.type = INTEGER;
  o3.rec.i = (obj2int (o1) == obj2int (o2)) ? 1 : 0;
  o3.label = NULL;
  return o3;
}

obj
mkimp (o1, o2)
     obj o1, o2;
{
  obj o3;
  o3.type = INTEGER;
  o3.rec.i = (!(obj2int (o1) != 0 && obj2int (o2) == 0)) ? 1 : 0;
  o3.label = NULL;
  return o3;
}

obj
mknot (o1)
     obj o1;
{
  obj o3;
  o3.type = INTEGER;
  o3.rec.i = (obj2int (o1) == 0) ? 1 : 0;
  o3.label = NULL;
  return o3;
}

obj
mkconcat (o1, o2)
     obj o1, o2;
{
  obj o3;
  int len = 0;
  char *str1 = obj2string (o1);
  char *str2 = obj2string (o2);
  if (str1 != NULL)
    len += strlen (str1);
  if (str2 != NULL)
    len += strlen (str2);
  
  o3.type = STRING;
  o3.rec.s = (char *) absmalloc ((len + 1) * sizeof (char), "mkconcat:o3.rec.s");

  if (str1 != NULL)
    strcpy (o3.rec.s, str1);
  else
    o3.rec.s[0] = '\0';
  if (str2 != NULL)
    strcat (o3.rec.s, str2);
  o3.label = NULL;
  return o3;
}
