freeswitch/src/mod/applications/mod_expr/expreval.c

249 lines
4.7 KiB
C

/*
File: expreval.c
Auth: Brian Allen Vanderburg II
Date: Wednesday, April 30, 2003
Desc: Evaluation routines for the ExprEval library
This file is part of ExprEval.
*/
/* Includes */
#include "exprincl.h"
#include "exprpriv.h"
/* Defines for error checking */
#include <errno.h>
#if (EXPR_ERROR_LEVEL >= EXPR_ERROR_LEVEL_CHECK)
#define EXPR_RESET_ERR() errno = 0
#define EXPR_CHECK_ERR() if (errno) return EXPR_ERROR_OUTOFRANGE
#else
#define EXPR_RESET_ERR()
#define EXPR_CHECK_ERR()
#endif
/* This routine will evaluate an expression */
int exprEval(exprObj * obj, EXPRTYPE * val)
{
EXPRTYPE dummy;
if (val == NULL)
val = &dummy;
/* Make sure it was parsed successfully */
if (!obj->parsedbad && obj->parsedgood && obj->headnode) {
/* Do NOT reset the break count. Let is accumulate
between calls until breaker function is called */
return exprEvalNode(obj, obj->headnode, 0, val);
} else
return EXPR_ERROR_BADEXPR;
}
/* Evaluate a node */
int exprEvalNode(exprObj * obj, exprNode * nodes, int curnode, EXPRTYPE * val)
{
int err;
int pos;
EXPRTYPE d1, d2;
if (obj == NULL || nodes == NULL)
return EXPR_ERROR_NULLPOINTER;
/* Update n to point to correct node */
nodes += curnode;
/* Check breaker count */
if (obj->breakcur-- <= 0) {
/* Reset count before returning */
obj->breakcur = obj->breakcount;
if (exprGetBreakResult(obj)) {
return EXPR_ERROR_BREAK;
}
}
switch (nodes->type) {
case EXPR_NODETYPE_MULTI:
{
/* Multi for multiple expressions in one string */
for (pos = 0; pos < nodes->data.oper.nodecount; pos++) {
err = exprEvalNode(obj, nodes->data.oper.nodes, pos, val);
if (err)
return err;
}
break;
}
case EXPR_NODETYPE_ADD:
{
/* Addition */
err = exprEvalNode(obj, nodes->data.oper.nodes, 0, &d1);
if (!err)
err = exprEvalNode(obj, nodes->data.oper.nodes, 1, &d2);
if (!err)
*val = d1 + d2;
else
return err;
break;
}
case EXPR_NODETYPE_SUBTRACT:
{
/* Subtraction */
err = exprEvalNode(obj, nodes->data.oper.nodes, 0, &d1);
if (!err)
err = exprEvalNode(obj, nodes->data.oper.nodes, 1, &d2);
if (!err)
*val = d1 - d2;
else
return err;
break;
}
case EXPR_NODETYPE_MULTIPLY:
{
/* Multiplication */
err = exprEvalNode(obj, nodes->data.oper.nodes, 0, &d1);
if (!err)
err = exprEvalNode(obj, nodes->data.oper.nodes, 1, &d2);
if (!err)
*val = d1 * d2;
else
return err;
break;
}
case EXPR_NODETYPE_DIVIDE:
{
/* Division */
err = exprEvalNode(obj, nodes->data.oper.nodes, 0, &d1);
if (!err)
err = exprEvalNode(obj, nodes->data.oper.nodes, 1, &d2);
if (!err) {
if (d2 != 0.0)
*val = d1 / d2;
else {
#if (EXPR_ERROR_LEVEL >= EXPR_ERROR_LEVEL_CHECK)
return EXPR_ERROR_DIVBYZERO;
#else
*val = 0.0;
return EXPR_ERROR_NOERROR;
#endif
}
} else
return err;
break;
}
case EXPR_NODETYPE_EXPONENT:
{
/* Exponent */
err = exprEvalNode(obj, nodes->data.oper.nodes, 0, &d1);
if (!err)
err = exprEvalNode(obj, nodes->data.oper.nodes, 1, &d2);
if (!err) {
EXPR_RESET_ERR();
*val = pow(d1, d2);
EXPR_CHECK_ERR();
} else
return err;
break;
}
case EXPR_NODETYPE_NEGATE:
{
/* Negative value */
err = exprEvalNode(obj, nodes->data.oper.nodes, 0, &d1);
if (!err)
*val = -d1;
else
return err;
break;
}
case EXPR_NODETYPE_VALUE:
{
/* Directly access the value */
*val = nodes->data.value.value;
break;
}
case EXPR_NODETYPE_VARIABLE:
{
/* Directly access the variable or constant */
*val = *(nodes->data.variable.vaddr);
break;
}
case EXPR_NODETYPE_ASSIGN:
{
/* Evaluate assignment subnode */
err = exprEvalNode(obj, nodes->data.assign.node, 0, val);
if (!err) {
/* Directly assign the variable */
*(nodes->data.assign.vaddr) = *val;
} else
return err;
break;
}
case EXPR_NODETYPE_FUNCTION:
{
/* Evaluate the function */
if (nodes->data.function.fptr == NULL) {
/* No function pointer means we are not using
function solvers. See if the function has a
type to solve directly. */
switch (nodes->data.function.type) {
/* This is to keep the file from being too crowded.
See exprilfs.h for the definitions. */
#include "exprilfs.h"
default:
{
return EXPR_ERROR_UNKNOWN;
}
}
} else {
/* Call the correct function */
return (*(nodes->data.function.fptr)) (obj,
nodes->data.function.nodes, nodes->data.function.nodecount,
nodes->data.function.refs, nodes->data.function.refcount, val);
}
break;
}
default:
{
/* Unknown node type */
return EXPR_ERROR_UNKNOWN;
}
}
return EXPR_ERROR_NOERROR;
}