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