152    $this->last_error = 
null;
 
  153    $this->last_error_code = 
null;
 
  155    if (substr($expr, - 1, 1) == 
';') {
 
  156      $expr = substr($expr, 0, strlen($expr) - 1); 
 
  161    if (preg_match(
'/^\s*([a-z]\w*)\s*=\s*(.+)$/', $expr, $matches)) {
 
  162      if (in_array($matches[1], $this->vb)) { 
 
  163        return $this->
trigger(1, 
"cannot assign to constant '$matches[1]'", $matches[1]);
 
  165      if (($tmp = $this->
pfx($this->
nfx($matches[2]))) === 
false) {
 
  168      $this->v[$matches[1]] = $tmp; 
 
  169      return $this->v[$matches[1]]; 
 
  172    } elseif (preg_match(
'/^\s*([a-z]\w*)\s*\(\s*([a-z]\w*(?:\s*,\s*[a-z]\w*)*)\s*\)\s*=\s*(.+)$/', $expr, $matches)) {
 
  174      if (in_array($matches[1], $this->fb)) { 
 
  175        return $this->
trigger(2, 
"cannot redefine built-in function '$matches[1]()'", $matches[1]);
 
  177      $args = explode(
",", preg_replace(
"/\s+/", 
"", $matches[2])); 
 
  178      if (($stack = $this->
nfx($matches[3])) === 
false) {
 
  181      $nbstack = count($stack);
 
  182      for ($i = 0; $i < $nbstack; $i++) { 
 
  184        if (preg_match(
'/^[a-z]\w*$/', $token) and !in_array($token, $args)) {
 
  185          if (array_key_exists($token, $this->v)) {
 
  186            $stack[$i] = $this->v[$token];
 
  188            return $this->
trigger(3, 
"undefined variable '$token' in function definition", $token);
 
  192      $this->f[$fnn] = array(
'args' => $args, 
'func' => $stack);
 
  196      return $this->
pfx($this->
nfx($expr)); 
 
 
  235  private function nfx($expr)
 
  240    $expr = trim(strtolower($expr));
 
  242    $ops = array(
'+', 
'-', 
'*', 
'/', 
'^', 
'_');
 
  243    $ops_r = array(
'+' => 0, 
'-' => 0, 
'*' => 0, 
'/' => 0, 
'^' => 1); 
 
  244    $ops_p = array(
'+' => 0, 
'-' => 0, 
'*' => 1, 
'/' => 1, 
'_' => 1, 
'^' => 2); 
 
  246    $expecting_op = 
false; 
 
  250    if (preg_match(
"/[^\w\s+*^\/()\.,-]/", $expr, $matches)) { 
 
  251      return $this->
trigger(4, 
"illegal character '".$matches[0].
"'", $matches[0]);
 
  255      $op = substr($expr, $index, 1); 
 
  258      $ex = preg_match(
'/^([a-z]\w*\(?|\d+(?:\.\d*)?|\.\d+|\()/', substr($expr, $index), $match);
 
  260      if ($op == 
'-' and !$expecting_op) { 
 
  263      } elseif ($op == 
'_') { 
 
  264        return $this->
trigger(4, 
"illegal character '_'", 
"_"); 
 
  266      } elseif ((in_array($op, $ops) or $ex) and $expecting_op) { 
 
  272        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])) {
 
  273          $output[] = $stack->pop(); 
 
  278        $expecting_op = 
false;
 
  280      } elseif ($op == 
')' and $expecting_op) { 
 
  281        while (($o2 = $stack->pop()) != 
'(') { 
 
  283            return $this->
trigger(5, 
"unexpected ')'", 
")");
 
  288        if (preg_match(
"/^([a-z]\w*)\($/", $stack->last(2), $matches)) { 
 
  290          $arg_count = $stack->pop(); 
 
  291          $output[] = $stack->pop(); 
 
  292          if (in_array($fnn, $this->fb)) { 
 
  293            if ($arg_count > 1) {
 
  294              return $this->
trigger(6, 
"wrong number of arguments ($arg_count given, 1 expected)", array($arg_count, 1));
 
  296          } elseif (array_key_exists($fnn, $this->f)) {
 
  297            if ($arg_count != count($this->f[$fnn][
'args'])) {
 
  298              return $this->
trigger(6, 
"wrong number of arguments ($arg_count given, ".count($this->f[$fnn][
'args']).
" expected)", array($arg_count, count($this->f[$fnn][
'args'])));
 
  301            return $this->
trigger(7, 
"internal error");
 
  306      } elseif ($op == 
',' and $expecting_op) { 
 
  307        while (($o2 = $stack->pop()) != 
'(') {
 
  309            return $this->
trigger(5, 
"unexpected ','", 
","); 
 
  315        if (!preg_match(
"/^([a-z]\w*)\($/", $stack->last(2), $matches)) {
 
  316          return $this->
trigger(5, 
"unexpected ','", 
",");
 
  318        $stack->push($stack->pop() + 1); 
 
  321        $expecting_op = 
false;
 
  323      } elseif ($op == 
'(' and !$expecting_op) {
 
  328      } elseif ($ex and !$expecting_op) { 
 
  329        $expecting_op = 
true;
 
  331        if (preg_match(
"/^([a-z]\w*)\($/", $val, $matches)) { 
 
  332          if (in_array($matches[1], $this->fb) or array_key_exists($matches[1], $this->f)) { 
 
  336            $expecting_op = 
false;
 
  344        $index += strlen($val);
 
  346      } elseif ($op == 
')') { 
 
  347        return $this->
trigger(5, 
"unexpected ')'", 
")");
 
  348      } elseif (in_array($op, $ops) and !$expecting_op) {
 
  349        return $this->
trigger(8, 
"unexpected operator '$op'", $op);
 
  351        return $this->
trigger(9, 
"an unexpected error occured");
 
  353      if ($index == strlen($expr)) {
 
  354        if (in_array($op, $ops)) { 
 
  355          return $this->
trigger(10, 
"operator '$op' lacks operand", $op);
 
  360      while (substr($expr, $index, 1) == 
' ') { 
 
  364    while (!is_null($op = $stack->pop())) { 
 
  366        return $this->
trigger(11, 
"expecting ')'", 
")"); 
 
 
  381  private function pfx($tokens, $vars = array())
 
  385    foreach ($tokens as $token) { 
 
  388      if (in_array($token, array(
'+', 
'-', 
'*', 
'/', 
'^'))) {
 
  389        if (is_null($op2 = $stack->pop())) {
 
  390          return $this->
trigger(12, 
"internal error");
 
  392        if (is_null($op1 = $stack->pop())) {
 
  393          return $this->
trigger(13, 
"internal error");
 
  397            $stack->push($op1 + $op2);
 
  400            $stack->push($op1 - $op2);
 
  403            $stack->push($op1 * $op2);
 
  407              return $this->
trigger(14, 
"division by zero");
 
  409            $stack->push($op1 / $op2);
 
  412            $stack->push(pow($op1, $op2));
 
  416      } elseif ($token == 
"_") {
 
  417        $stack->push(-1 * $stack->pop());
 
  419      } elseif (preg_match(
"/^([a-z]\w*)\($/", $token, $matches)) { 
 
  421        if (in_array($fnn, $this->fb)) { 
 
  422          if (is_null($op1 = $stack->pop())) {
 
  423            return $this->
trigger(15, 
"internal error");
 
  425          $fnn = preg_replace(
"/^arc/", 
"a", $fnn); 
 
  429          eval(
'$stack->push('.$fnn.
'($op1));'); 
 
  430        } elseif (array_key_exists($fnn, $this->f)) { 
 
  433          for ($i = count($this->f[$fnn][
'args']) - 1; $i >= 0; $i--) {
 
  434            if (is_null($args[$this->f[$fnn][
'args'][$i]] = $stack->pop())) {
 
  435              return $this->
trigger(16, 
"internal error");
 
  438          $stack->push($this->
pfx($this->f[$fnn][
'func'], $args)); 
 
  442        if (is_numeric($token)) {
 
  443          $stack->push($token);
 
  444        } elseif (array_key_exists($token, $this->v)) {
 
  445          $stack->push($this->v[$token]);
 
  446        } elseif (array_key_exists($token, $vars)) {
 
  447          $stack->push($vars[$token]);
 
  449          return $this->
trigger(17, 
"undefined variable '$token'", $token);
 
  454    if ($stack->count != 1) {
 
  455      return $this->
trigger(18, 
"internal error");
 
  457    return $stack->pop();
 
 
  468  public function trigger($code, $msg, $info = 
null)
 
  470    $this->last_error = $msg;
 
  471    $this->last_error_code = array($code, $info);
 
  472    if (!$this->suppress_errors) {
 
  473      trigger_error($msg, E_USER_WARNING);