Skip to content

Commit

Permalink
Prepare lib to be a native class
Browse files Browse the repository at this point in the history
  • Loading branch information
eldy committed Mar 25, 2018
1 parent c50b772 commit 73273f6
Showing 1 changed file with 42 additions and 38 deletions.
80 changes: 42 additions & 38 deletions htdocs/includes/evalmath/evalmath.class.php
@@ -1,5 +1,4 @@
<?php

/*
================================================================================
Expand All @@ -10,7 +9,7 @@
NAME
EvalMath - safely evaluate math expressions
SYNOPSIS
include('evalmath.class.php');
$m = new EvalMath;
Expand All @@ -24,9 +23,9 @@
$m->evaluate('f(x,y) = x^2 + y^2 - 2x*y + 1');
// and then use them
$result = $m->evaluate('3*f(42,a)');
DESCRIPTION
Use the EvalMath class when you want to evaluate mathematical expressions
Use the EvalMath class when you want to evaluate mathematical expressions
from untrusted sources. You can define your own variables and functions,
which are stored in the object. Try it, it's fun!
Expand All @@ -35,13 +34,13 @@
Evaluates the expression and returns the result. If an error occurs,
prints a warning and returns false. If $expr is a function assignment,
returns true on success.
$m->e($expr)
A synonym for $m->evaluate().
$m->vars()
Returns an associative array of all user-defined variables and values.
$m->funcs()
Returns an array of all user-defined functions.
Expand All @@ -63,7 +62,7 @@
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1 Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
Expand All @@ -72,7 +71,7 @@
3. The name of the author may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
Expand All @@ -91,26 +90,29 @@ class EvalMath {
var $suppress_errors = false;
var $last_error = null;
var $last_error_code = null;
var $v = array('e'=>2.71,'pi'=>3.14); // variables (and constants)

var $v = array('e'=>2.71,'pi'=>3.14159); // variables (and constants)
var $f = array(); // user-defined functions
var $vb = array('e', 'pi'); // constants
var $fb = array( // built-in functions
'sin','sinh','arcsin','asin','arcsinh','asinh',
'cos','cosh','arccos','acos','arccosh','acosh',
'tan','tanh','arctan','atan','arctanh','atanh',
'sqrt','abs','ln','log');

function EvalMath() {

/**
* Constructor
*/
function __construct() {
// make the variables a little more accurate
$this->v['pi'] = pi();
$this->v['e'] = exp(1);
}

function e($expr) {
return $this->evaluate($expr);
}

function evaluate($expr) {
$this->last_error = null;
$this->last_error_code = null;
Expand Down Expand Up @@ -151,14 +153,14 @@ function evaluate($expr) {
return $this->pfx($this->nfx($expr)); // straight up evaluation, woo
}
}

function vars() {
$output = $this->v;
unset($output['pi']);
unset($output['e']);
return $output;
}

function funcs() {
$output = array();
foreach ($this->f as $fnn=>$dat)
Expand All @@ -170,23 +172,23 @@ function funcs() {

// Convert infix to postfix notation
function nfx($expr) {

$index = 0;
$stack = new EvalMathStack;
$stack = new EvalMathStack();
$output = array(); // postfix form of expression, to be passed to pfx()
$expr = trim(strtolower($expr));

$ops = array('+', '-', '*', '/', '^', '_');
$ops_r = array('+'=>0,'-'=>0,'*'=>0,'/'=>0,'^'=>1); // right-associative operator?
$ops_r = array('+'=>0,'-'=>0,'*'=>0,'/'=>0,'^'=>1); // right-associative operator?
$ops_p = array('+'=>0,'-'=>0,'*'=>1,'/'=>1,'_'=>1,'^'=>2); // operator precedence

$expecting_op = false; // we use this in syntax-checking the expression
// and determining when a - is a negation

if (preg_match("/[^\w\s+*^\/()\.,-]/", $expr, $matches)) { // make sure the characters are all good
return $this->trigger(4, "illegal character '{$matches[0]}'", $matches[0]);
}

while(1) { // 1 Infinite Loop ;)
$op = substr($expr, $index, 1); // get the first character at the current index
// find out if we're currently at the beginning of a number/variable/function/parenthesis/operand
Expand All @@ -195,7 +197,7 @@ function nfx($expr) {
if ($op == '-' and !$expecting_op) { // is it a negation instead of a minus?
$stack->push('_'); // put a negation on the stack
$index++;
} elseif ($op == '_') { // we have to explicitly deny this, because it's legal on the stack
} elseif ($op == '_') { // we have to explicitly deny this, because it's legal on the stack
return $this->trigger(4, "illegal character '_'", "_"); // but not in the input expression
//===============
} elseif ((in_array($op, $ops) or $ex) and $expecting_op) { // are we putting an operator on the stack?
Expand Down Expand Up @@ -233,7 +235,7 @@ function nfx($expr) {
$index++;
//===============
} elseif ($op == ',' and $expecting_op) { // did we just finish a function argument?
while (($o2 = $stack->pop()) != '(') {
while (($o2 = $stack->pop()) != '(') {
if (is_null($o2)) return $this->trigger(5, "unexpected ','", ","); // oops, never had a (
else $output[] = $o2; // pop the argument expression stuff and push onto the output
}
Expand Down Expand Up @@ -282,11 +284,11 @@ function nfx($expr) {
break;
}
}
while (substr($expr, $index, 1) == ' ') { // step the index past whitespace (pretty much turns whitespace
while (substr($expr, $index, 1) == ' ') { // step the index past whitespace (pretty much turns whitespace
$index++; // into implicit multiplication if no operator is there)
}
}

}
while (!is_null($op = $stack->pop())) { // pop everything off the stack and push onto output
if ($op == '(') return $this->trigger(11, "expecting ')'", ")"); // if there are (s on the stack, ()s were unbalanced
$output[] = $op;
Expand All @@ -296,11 +298,11 @@ function nfx($expr) {

// evaluate postfix notation
function pfx($tokens, $vars = array()) {

if ($tokens == false) return false;
$stack = new EvalMathStack;

$stack = new EvalMathStack();

foreach ($tokens as $token) { // nice and easy
// if the token is a binary operator, pop two values off the stack, do the operation, and push the result back on
if (in_array($token, array('+', '-', '*', '/', '^'))) {
Expand Down Expand Up @@ -355,7 +357,7 @@ function pfx($tokens, $vars = array()) {
if ($stack->count != 1) return $this->trigger(18, "internal error");
return $stack->pop();
}

// trigger an error, but nicely, if need be
function trigger($code, $msg, $info = null) {
$this->last_error = $msg;
Expand All @@ -365,25 +367,27 @@ function trigger($code, $msg, $info = null) {
}
}

// for internal use
/**
* Class for internal use
*/
class EvalMathStack {

var $stack = array();
var $count = 0;

function push($val) {
$this->stack[$this->count] = $val;
$this->count++;
}

function pop() {
if ($this->count > 0) {
$this->count--;
return $this->stack[$this->count];
}
return null;
}

function last($n=1) {
if (isset($this->stack[$this->count-$n])) {
return $this->stack[$this->count-$n];
Expand Down

0 comments on commit 73273f6

Please sign in to comment.