94 var
$v = array(
'e'=>2.71,
'pi'=>3.14);
96 var
$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');
105 $this->v[
'pi'] = pi();
106 $this->v[
'exp'] = exp(1);
115 $expr = preg_replace(
"/(\\d{0,1})e(-{0,1}\\d+)/eis",
"'\\1'.((strlen('\\1')) ? '*' : '').'10^(\\2)'", $expr);
117 $this->last_error = null;
119 if (substr($expr, -1, 1) ==
';') $expr = substr($expr, 0, strlen($expr)-1);
122 if (preg_match(
'/^\s*([a-z]\w*)\s*=\s*(.+)$/', $expr, $matches)) {
123 if (in_array($matches[1], $this->vb)) {
124 return $this->
trigger(
"cannot assign to constant '$matches[1]'");
126 if (($tmp = $this->
pfx($this->
nfx($matches[2]))) ===
false)
return false;
127 $this->v[$matches[1]] = $tmp;
128 return $this->v[$matches[1]];
131 } elseif (preg_match(
'/^\s*([a-z]\w*)\s*\(\s*([a-z]\w*(?:\s*,\s*[a-z]\w*)*)\s*\)\s*=\s*(.+)$/', $expr, $matches)) {
133 if (in_array($matches[1], $this->fb)) {
134 return $this->
trigger(
"cannot redefine built-in function '$matches[1]()'");
136 $args = explode(
",", preg_replace(
"/\s+/",
"", $matches[2]));
137 if (($stack = $this->
nfx($matches[3])) ===
false)
return false;
138 for ($i = 0; $i<count($stack); $i++) {
140 if (preg_match(
'/^[a-z]\w*$/', $token) and !in_array($token, $args)) {
141 if (array_key_exists($token, $this->v)) {
142 $stack[$i] = $this->v[$token];
144 return $this->
trigger(
"undefined variable '$token' in function definition");
148 $this->f[$fnn] = array(
'args'=>$args,
'func'=>$stack);
152 return $this->
pfx($this->
nfx($expr));
158 unset($output[
'pi']);
165 foreach ($this->f as $fnn=>$dat)
166 $output[] = $fnn .
'(' . implode(
',', $dat[
'args']) .
')';
178 $expr = trim(strtolower($expr));
180 $ops = array(
'+',
'-',
'*',
'/',
'^',
'_');
181 $ops_r = array(
'+'=>0,
'-'=>0,
'*'=>0,
'/'=>0,
'^'=>1);
182 $ops_p = array(
'+'=>0,
'-'=>0,
'*'=>1,
'/'=>1,
'_'=>1,
'^'=>2);
184 $expecting_op =
false;
187 if (preg_match(
"/[^\w\s+*^\/()\.,-]/", $expr, $matches)) {
188 return $this->
trigger(
"illegal character '{$matches[0]}'");
192 $op = substr($expr, $index, 1);
194 $ex = preg_match(
'/^([01]+[bB]|[\da-fA-F]+[hH]|[a-z]\w*\(?|\d+(?:\.\d*)?|\.\d+|\()/', substr($expr, $index), $match);
196 if ($op ==
'-' and !$expecting_op) {
199 } elseif ($op ==
'_') {
200 return $this->
trigger(
"illegal character '_'");
202 } elseif ((in_array($op, $ops) or $ex) and $expecting_op) {
207 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])) {
208 $output[] = $stack->pop();
213 $expecting_op =
false;
215 } elseif ($op ==
')' and $expecting_op) {
216 while (($o2 = $stack->pop()) !=
'(') {
217 if (is_null($o2))
return $this->
trigger(
"unexpected ')'");
218 else $output[] = $o2;
220 if (preg_match(
"/^([a-z]\w*)\($/", $stack->last(2), $matches)) {
222 $arg_count = $stack->pop();
223 $output[] = $stack->pop();
224 if (in_array($fnn, $this->fb)) {
226 return $this->
trigger(
"too many arguments ($arg_count given, 1 expected)");
227 } elseif (array_key_exists($fnn, $this->f)) {
228 if ($arg_count != count($this->f[$fnn][
'args']))
229 return $this->
trigger(
"wrong number of arguments ($arg_count given, " . count($this->f[$fnn][
'args']) .
" expected)");
231 return $this->
trigger(
"internal error");
236 } elseif ($op ==
',' and $expecting_op) {
237 while (($o2 = $stack->pop()) !=
'(') {
238 if (is_null($o2))
return $this->
trigger(
"unexpected ','");
239 else $output[] = $o2;
242 if (!preg_match(
"/^([a-z]\w*)\($/", $stack->last(2), $matches))
243 return $this->
trigger(
"unexpected ','");
244 $stack->push($stack->pop()+1);
247 $expecting_op =
false;
249 } elseif ($op ==
'(' and !$expecting_op) {
254 } elseif ($ex and !$expecting_op) {
255 $expecting_op =
true;
257 if (preg_match(
"/^([a-z]\w*)\($/", $val, $matches)) {
258 if (in_array($matches[1], $this->fb) or array_key_exists($matches[1], $this->f)) {
262 $expecting_op =
false;
270 $index += strlen($val);
272 } elseif ($op ==
')') {
273 return $this->
trigger(
"unexpected ')'");
274 } elseif (in_array($op, $ops) and !$expecting_op) {
275 return $this->
trigger(
"unexpected operator '$op'");
277 return $this->
trigger(
"an unexpected error occured");
279 if ($index == strlen($expr)) {
280 if (in_array($op, $ops)) {
281 return $this->
trigger(
"operator '$op' lacks operand");
286 while (substr($expr, $index, 1) ==
' ') {
291 while (!is_null($op = $stack->pop())) {
292 if ($op ==
'(')
return $this->
trigger(
"expecting ')'");
299 function pfx($tokens, $vars = array()) {
301 if ($tokens ==
false)
return false;
305 foreach ($tokens as $token) {
307 if (in_array($token, array(
'+',
'-',
'*',
'/',
'^'))) {
308 if (is_null($op2 = $stack->pop()))
return $this->
trigger(
"internal error");
309 if (is_null($op1 = $stack->pop()))
return $this->
trigger(
"internal error");
310 include_once
"class.ilMath.php";
319 if ($op2 == 0)
return $this->
trigger(
"division by zero");
325 } elseif ($token ==
"_") {
326 $stack->push(-1*$stack->pop());
328 } elseif (preg_match(
"/^([a-z]\w*)\($/", $token, $matches)) {
330 if (in_array($fnn, $this->fb)) {
331 if (is_null($op1 = $stack->pop()))
return $this->
trigger(
"internal error");
332 $fnn = preg_replace(
"/^arc/",
"a", $fnn);
333 if ($fnn ==
'ln') $fnn =
'log';
334 eval(
'$stack->push(' . $fnn .
'($op1));');
335 } elseif (array_key_exists($fnn, $this->f)) {
338 for ($i = count($this->f[$fnn][
'args'])-1; $i >= 0; $i--) {
339 if (is_null($args[$this->f[$fnn][
'args'][$i]] = $stack->pop()))
return $this->
trigger(
"internal error");
341 $stack->push($this->
pfx($this->f[$fnn][
'func'], $args));
345 if (is_numeric($token)) {
346 $stack->push($token);
347 } elseif (($hex=$this->
from_hexbin($token))!==FALSE) {
349 } elseif (array_key_exists($token, $this->v)) {
350 $stack->push($this->v[$token]);
351 } elseif (array_key_exists($token, $vars)) {
352 $stack->push($vars[$token]);
354 return $this->
trigger(
"undefined variable '$token'");
359 if ($stack->count != 1)
return $this->
trigger(
"internal error");
360 return $stack->pop();
365 $this->last_error = $msg;
366 if (!$this->suppress_errors) trigger_error($msg, E_USER_WARNING);
373 if (strtoupper(substr($token, -1, 1))==
'H')
return hexdec($token);
374 if (strtoupper(substr($token, -1, 1))==
'B')
return bindec($token);
391 if ($this->count > 0) {
399 return $this->stack[$this->count-
$n];