/* **************************************************************************
*
* --- 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