94    public $v = array(
'e' => 2.71,
'pi' => 3.14); 
 
   96    public $vb = array(
'e', 
'pi'); 
 
   98        'sin',
'sinh',
'arcsin',
'asin',
'arcsinh',
'asinh',
 
   99        'cos',
'cosh',
'arccos',
'acos',
'arccosh',
'acosh',
 
  100        'tan',
'tanh',
'arctan',
'atan',
'arctanh',
'atanh',
 
  101        'sqrt',
'abs',
'ln',
'log');
 
  107        $this->v[
'pi'] = pi();
 
  108        $this->v[
'exp'] = exp(1);
 
  110        $this->v[
'e'] = exp(1); 
 
  115    public function e($expr)
 
  123        $expr = preg_replace_callback(
 
  124            "/(\\d{0,1})e(-{0,1}\\d+)/is",
 
  126                return $hit[1] . ((strlen($hit[1])) ? 
'*' : 
'') . 
'10^(' . $hit[2] . 
')';
 
  131        $this->last_error = 
null;
 
  133        if (substr($expr, -1, 1) == 
';') {
 
  134            $expr = substr($expr, 0, strlen($expr) - 1);
 
  138        if (preg_match(
'/^\s*([a-z]\w*)\s*=\s*(.+)$/', $expr, $matches)) {
 
  139            if (in_array($matches[1], $this->vb)) { 
 
  140                return $this->
trigger(
"cannot assign to constant '$matches[1]'");
 
  142            if (($tmp = $this->
pfx($this->
nfx($matches[2]))) === 
false) {
 
  145            $this->v[$matches[1]] = $tmp; 
 
  146            return $this->v[$matches[1]]; 
 
  149        } elseif (preg_match(
'/^\s*([a-z]\w*)\s*\(\s*([a-z]\w*(?:\s*,\s*[a-z]\w*)*)\s*\)\s*=\s*(.+)$/', $expr, $matches)) {
 
  151            if (in_array($matches[1], $this->fb)) { 
 
  152                return $this->
trigger(
"cannot redefine built-in function '$matches[1]()'");
 
  154            $args = explode(
",", preg_replace(
"/\s+/", 
"", $matches[2])); 
 
  155            if (($stack = $this->
nfx($matches[3])) === 
false) {
 
  158            for (
$i = 0; 
$i < count($stack); 
$i++) { 
 
  160                if (preg_match(
'/^[a-z]\w*$/', 
$token) and !in_array(
$token, $args)) {
 
  161                    if (array_key_exists(
$token, $this->v)) {
 
  164                        return $this->
trigger(
"undefined variable '$token' in function definition");
 
  168            $this->f[$fnn] = array(
'args' => $args, 
'func' => $stack);
 
  172            return $this->
pfx($this->
nfx($expr)); 
 
  187        foreach ($this->f as $fnn => $dat) {
 
  188            $output[] = $fnn . 
'(' . implode(
',', $dat[
'args']) . 
')';
 
  196    public function nfx($expr)
 
  201        $expr = trim(strtolower($expr));
 
  203        $ops = array(
'+', 
'-', 
'*', 
'/', 
'^', 
'_');
 
  204        $ops_r = array(
'+' => 0,
'-' => 0,
'*' => 0,
'/' => 0,
'^' => 1); 
 
  205        $ops_p = array(
'+' => 0,
'-' => 0,
'*' => 1,
'/' => 1,
'_' => 1,
'^' => 2); 
 
  207        $expecting_op = 
false; 
 
  210        if (preg_match(
"/[^\w\s+*^\/()\.,-]/", $expr, $matches)) { 
 
  211            return $this->
trigger(
"illegal character '{$matches[0]}'");
 
  215            $op = substr($expr, 
$index, 1); 
 
  217            $ex = preg_match(
'/^([01]+[bB]|[\da-fA-F]+[hH]|[a-z]\w*\(?|\d+(?:\.\d*)?|\.\d+|\()/', substr($expr, 
$index), $match);
 
  219            if ($op == 
'-' and !$expecting_op) { 
 
  222            } elseif ($op == 
'_') { 
 
  223                return $this->
trigger(
"illegal character '_'"); 
 
  225            } elseif ((in_array($op, $ops) or $ex) and $expecting_op) { 
 
  231                while ($stack->count > 0 and ($o2 = $stack->last()) and in_array($o2, $ops) and ($ops_r[$op] ? $ops_p[$op] < $ops_p[$o2] : $ops_p[$op] <= $ops_p[$o2])) {
 
  237                $expecting_op = 
false;
 
  239            } elseif ($op == 
')' and $expecting_op) { 
 
  240                while (($o2 = $stack->pop()) != 
'(') { 
 
  242                        return $this->
trigger(
"unexpected ')'");
 
  247                if (preg_match(
"/^([a-z]\w*)\($/", $stack->last(2), $matches)) { 
 
  249                    $arg_count = $stack->pop(); 
 
  251                    if (in_array($fnn, $this->fb)) { 
 
  252                        if ($arg_count > 1) {
 
  253                            return $this->
trigger(
"too many arguments ($arg_count given, 1 expected)");
 
  255                    } elseif (array_key_exists($fnn, $this->f)) {
 
  256                        if ($arg_count != count($this->f[$fnn][
'args'])) {
 
  257                            return $this->
trigger(
"wrong number of arguments ($arg_count given, " . count($this->f[$fnn][
'args']) . 
" expected)");
 
  260                        return $this->
trigger(
"internal error");
 
  265            } elseif ($op == 
',' and $expecting_op) { 
 
  266                while (($o2 = $stack->pop()) != 
'(') {
 
  268                        return $this->
trigger(
"unexpected ','");
 
  275                if (!preg_match(
"/^([a-z]\w*)\($/", $stack->last(2), $matches)) {
 
  276                    return $this->
trigger(
"unexpected ','");
 
  278                $stack->push($stack->pop() + 1); 
 
  281                $expecting_op = 
false;
 
  283            } elseif ($op == 
'(' and !$expecting_op) {
 
  288            } elseif ($ex and !$expecting_op) { 
 
  289                $expecting_op = 
true;
 
  291                if (preg_match(
"/^([a-z]\w*)\($/", $val, $matches)) { 
 
  292                    if (in_array($matches[1], $this->fb) or array_key_exists($matches[1], $this->f)) { 
 
  296                        $expecting_op = 
false;
 
  306            } elseif ($op == 
')') { 
 
  307                return $this->
trigger(
"unexpected ')'");
 
  308            } elseif (in_array($op, $ops) and !$expecting_op) {
 
  309                return $this->
trigger(
"unexpected operator '$op'");
 
  311                return $this->
trigger(
"an unexpected error occured");
 
  313            if (
$index == strlen($expr)) {
 
  314                if (in_array($op, $ops)) { 
 
  315                    return $this->
trigger(
"operator '$op' lacks operand");
 
  320            while (substr($expr, 
$index, 1) == 
' ') { 
 
  324        while (!is_null($op = $stack->pop())) { 
 
  326                return $this->
trigger(
"expecting ')'");
 
  334    public function pfx($tokens, $vars = array())
 
  336        if ($tokens == 
false) {
 
  342        foreach ($tokens as 
$token) { 
 
  344            if (in_array(
$token, array(
'+', 
'-', 
'*', 
'/', 
'^'))) {
 
  345                if (is_null($op2 = $stack->pop())) {
 
  346                    return $this->
trigger(
"internal error");
 
  348                if (is_null($op1 = $stack->pop())) {
 
  349                    return $this->
trigger(
"internal error");
 
  351                include_once 
"class.ilMath.php";
 
  361                                                return $this->
trigger(
"division by zero");
 
  368            } elseif (
$token == 
"_") {
 
  369                $stack->push(-1 * $stack->pop());
 
  371            } elseif (preg_match(
"/^([a-z]\w*)\($/", 
$token, $matches)) { 
 
  373                if (in_array($fnn, $this->fb)) { 
 
  374                    if (is_null($op1 = $stack->pop())) {
 
  375                        return $this->
trigger(
"internal error");
 
  377                    $fnn = preg_replace(
"/^arc/", 
"a", $fnn); 
 
  380                    } elseif ($fnn == 
'ln') {
 
  384                    $stack->push($fnn($op1)); 
 
  385                } elseif (array_key_exists($fnn, $this->f)) { 
 
  388                    for (
$i = count($this->f[$fnn][
'args']) - 1; 
$i >= 0; 
$i--) {
 
  389                        if (is_null($args[$this->f[$fnn][
'args'][
$i]] = $stack->pop())) {
 
  390                            return $this->
trigger(
"internal error");
 
  393                    $stack->push($this->
pfx($this->f[$fnn][
'func'], $args)); 
 
  399                } elseif (($hex = $this->
from_hexbin($token)) !== 
false) {
 
  401                } elseif (array_key_exists(
$token, $this->v)) {
 
  402                    $stack->push($this->v[
$token]);
 
  403                } elseif (array_key_exists(
$token, $vars)) {
 
  404                    $stack->push($vars[
$token]);
 
  406                    return $this->
trigger(
"undefined variable '$token'");
 
  411        if ($stack->count != 1) {
 
  412            return $this->
trigger(
"internal error");
 
  414        return $stack->pop();
 
  420        $this->last_error = $msg;
 
  421        if (!$this->suppress_errors) {
 
  422            trigger_error($msg, E_USER_WARNING);
 
  431        if (strtoupper(substr(
$token, -1, 1)) == 
'H') {
 
  434        if (strtoupper(substr(
$token, -1, 1)) == 
'B') {
 
  455        if ($this->count > 0) {
 
  465        if (isset($this->stack[$this->count - 
$n])) {
 
  466            return $this->stack[$this->count - 
$n];
 
An exception for terminatinating execution or to throw for unit testing.
pfx($tokens, $vars=array())
static _mul($left_operand, $right_operand, $scale=50)
static _div($left_operand, $right_operand, $scale=50)
static _pow($left_operand, $right_operand, $scale=50)
static _sub($left_operand, $right_operand, $scale=50)
static _add($left_operand, $right_operand, $scale=50)