/*
**
** ETABLE.C	Manipulates a table of tokens.
**
** Originally written 6/89 in ANSI C
**
** Eval is a floating point expression evaluator.
** This file last updated in version 1.10
** For the version number, see eval.h
** Copyright (C) 1993-2003 http://willus.com
**
** 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 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.
**
*/

#include   "eval.h"

static	TOKEN	ttable[MAXINPUT+1];
static	int	ttp;

static BOOLEAN is_operator (int type);
#ifdef DEBUG
static void    print_table (void);
#endif

void clear_table(void)

    {
    ttp=0;
    }


BOOLEAN add_token(TOKENPTR t)

    {
    if (ttp>MAXINPUT)
	{
	printf("Out of expression table space.\n");
	return(0);
	}
    tokcpy(&ttable[ttp],t);
    ttp++;
    return(1);
    }


BOOLEAN table_value(double *ret_val)

    {
    int     i,j,k,nargs,max;
    double  args[MAXARGS];

    max=ttp;
    while (ttp>1)
	{
	for (i=0;i<max && !is_operator((int)ttable[i].type);i++);
	if (i==max)
	    return(eerror("Expression table lacking in operators."));
	if (ttable[i].type==UNARY)
	    nargs=1;
	else if (ttable[i].type==BINARY)
	    nargs=2;
	else
	    nargs=func_nargs(ttable[i].code);
	if (nargs>MAXARGS)
	    return(eerror("Maximum number of function arguments exceeded."));
	for (j=i,k=nargs-1;k>=0;k--)
	    {
	    for (j--;j>=0 && ttable[j].type==VOID;j--);
	    if (j<0)
		return(eerror("Expression table lacking in arguments."));
	    args[k]=ttable[j].value;
	    ttable[j].type=VOID;
	    ttp--;
	    }
	if (!result((int)ttable[i].type,ttable[i].code,args,&ttable[i].value))
	    return(0);
	ttable[i].type=NUMBER;
	}
    if (ttp!=1)
	return(eerror("Expression table unexpectedly empty."));
    for (i=0;i<max && ttable[i].type==VOID;i++);
    if (i==max)
	return(eerror("Internal inconsistency error."));
    if (is_operator((int)ttable[i].type))
	return(eerror("Final expression table result is not a number."));
    (*ret_val)=ttable[i].value;
    return(1);
    }


BOOLEAN result(int type,int code,double *args,double *ret_val)

    {
    switch (type)
	{
	case BINARY:
	    switch (code)
		{
		case ADD:
		    (*ret_val)=args[0]+args[1];
		    return(1);
		case SUBTRACT:
		    (*ret_val)=args[0]-args[1];
		    return(1);
		case DIVIDE:
		case MOD:
		    if (args[1]==0.)
			return(eerror("Divide by zero in expression."));
		    if (code==DIVIDE)
			(*ret_val)=args[0]/args[1];
		    else
			(*ret_val)=args[1]*(args[0]/args[1]
						-(int)(args[0]/args[1]));
		    return(1);
		case MULTIPLY:
		    (*ret_val)=args[0]*args[1];
		    return(1);
		case POWER:
		    if (args[0]==0. && args[1]<0)
			return(eerror("Cannot raise zero to a negative power."));
		    if (args[0]<0 && args[1]!=((int)args[1]))
			return(eerror("Cannot raise a negative number to "
				      "a non-integer power."));
		    (*ret_val)=pow(args[0],args[1]);
		    return(1);
		case OR:
		    (*ret_val)=or(args[0],args[1]);
		    return(1);
		case AND:
		    (*ret_val)=and(args[0],args[1]);
		    return(1);
		case XOR:
		    (*ret_val)=xor(args[0],args[1]);
		    return(1);
		case SHRIGHT:
		    (*ret_val)=args[0]*pow(2.,-args[1]);
		    return(1);
		case SHLEFT:
		    (*ret_val)=args[0]*pow(2.,args[1]);
		    return(1);
		}
	    break;
	case UNARY:
	    (*ret_val)=(code==POSITIVE) ? args[0] :
		       (code==NEGATIVE ? -args[0] : not(args[0]));
	    return(1);
	case FUNCTION:
	    return(func_eval(code,args,ret_val));
	}
    return(0);
    }


static BOOLEAN is_operator(int type)

    {
    return(type==BINARY || type==UNARY || type==FUNCTION);
    }


#ifdef DEBUG
static void print_table(void)

    {
    int     i;

    for (i=0;i<ttp;i++)
	{
	printf("(%d,",ttable[i].type);
	if (ttable[i].type==NUMBER || ttable[i].type==CONSTANT ||
	    ttable[i].type==VARIABLE || ttable[i].type==QUOTE)
	    printf("%g) ",ttable[i].value);
	else
	    printf("%d) ",ttable[i].code);
	}
    printf("\n");
    }
#endif
