/*  **************************************************************************
 * 
 * --- File: eval.c
 * 
 * --- Purpose: routines for evaluating mathematical expressions (and a few
 * 		commands).
 * 
 * --- Copyright (C) Guido Gonzato, guido@ibogeo.df.unibo.it
 * 
 * --- Last updated: 8 January 1999
 *
 * 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.
 * 
 * ************************************************************************ */

#include <stdio.h>
#include <math.h>
#include "gexpr.h"

#define	ZERO	1E-10F

/* ----- */

static double factor(void);
static double term(void);
static double simple_expression(void);
static double logical_expression(void);

/* ----- */

/* factor() reads a factor from stdin: simply a digit or an expression 
 * in this program, but more generically a factor can be a digit, a 
 * constant, or a function.
 */

static double factor(void)
{
  
  TOKEN  tok;
  double s, a1, a2;
  short n_args;
  
  s = a1 = a2 = 0.0;	/* just to please -Wall ;-) */
  tok = read_token();
  
  if (tok.type == T_DIGIT)
    s = tok.value;

  else
    
  if (tok.type == T_CONST)
    s = tok.value;
  
  else
    
  /* check if it's an expresssion */
  
  if (tok.type == T_OPEN_PAR) {
    s = simple_expression();
    token_read = TRUE; /* true, because simple_expression() stops when it
			* finds an operator or a ).  */
    tok = read_token();
    check_token(tok.type, T_CLOSED_PAR);
  }
  
  else
    
  /* check if it's a function */
  
  if (tok.type == T_FUNCTION) {
    n_args = tok.args;
    tok = read_token();
    check_token(tok.type, T_OPEN_PAR);
    a1 = simple_expression();
    token_read = TRUE;
    tok = read_token();
    if (n_args == 1)
      check_token(tok.type, T_CLOSED_PAR);
    else {
      check_token(tok.type, T_COMMA);
      a2 = simple_expression();
      token_read = TRUE;
      tok = read_token();
      check_token(tok.type, T_CLOSED_PAR);
    } /* else */
    s = function_value(n_args, a1, a2);
  }
  
  else
  
  if (tok.type == T_EOL)
    error("factor expected", tok.type);

  else  /* all the rest is wrong */
    error("unknown factor", tok.type);
  
  return (s);

} /* factor() */

/* ----- */

/* term() reads a subexpression made of multiplications and/or divisions. */

static double term(void)
{
  
  double t1, t2;
  TOKEN  f;
  
  t1 = factor();
  f = read_token();
  
  while (f.type == T_OP_MULT || f.type == T_OP_DIV) {
    t2 = factor();
    if (f.type == T_OP_MULT)
      t1 = t1 * t2;
    else
      if (fabs(t2) > ZERO)
	t1 = t1 / t2;
      else
        error("division by zero", T_OP_DIV);
    f = read_token();
  }
  
  return(t1);
  
  /* term() stops when it finds a token it doesn't use */
  
} /* term() */

/* ----- */

/* simple_expression() reads an expression made of sums and/or
 * subtractions */

static double simple_expression(void)
{
  
  double s1, s2;
  TOKEN f;
  
  f = read_token(); /* check unary minus */
  
  if (f.type == T_OP_MINUS) 
    s1 = - term();
  else {
    token_read = TRUE; /* there's a '-' pending */
    s1 = term();
  }
  
  /* use last token read */
  
  token_read = TRUE; /* term() stops at operators */
  
  f = read_token();
  
  while (f.type == T_OP_PLUS || f.type == T_OP_MINUS) {
    s2 = term();
    s1 = (f.type == T_OP_PLUS ? s1 + s2 : s1 - s2);
    token_read = TRUE;
    f = read_token();
  }
  
  return(s1);
  
  /* simple_expression() stops when it finds a token it doesn't use */
  
} /* simple_expression() */

/* ----- */

/* logical_expression() reads a logical expression made of comparisons */

static double logical_expression(void)
{
  double s1, s2;
  TOKEN f;
  
  s1 = simple_expression();
  token_read = TRUE;
  f = read_token();
  
  if (f.type == T_EQ || f.type == T_GE || f.type == T_GT || 
      f.type == T_LE || f.type == T_LT) {
    s2 = simple_expression();
    switch (f.type) {
     case T_EQ:
      s1 = (s1 == s2);
      break;
     case T_GE:
      s1 = (s1 >= s2);
      break;
     case T_GT:
      s1 = (s1 > s2);
      break;
     case T_LE:
      s1 = (s1 <= s2);
      break;
     case T_LT:
      s1 = (s1 < s2);
     default:
      ; /* do nothing */
    } /* switch */
  }

  return (s1);  

} /* logical_expression() */

/* ----- */

/* expression() reads a complete expression */

double expression(void)
{
  
  double e;
  TOKEN tok;
  
  e = logical_expression();
  token_read = TRUE;
  tok = read_token();	/* the last token must be T_EOL */
  
  check_token(tok.type, T_EOL);

  return(e);
  
} /* expression() */

/* ----- */

/* --- End of file eval.c --- */


syntax highlighted by Code2HTML, v. 0.9.1