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);
108 $this->
v[
'e'] = exp(1);
119 $expr = preg_replace(
"/(\\d{0,1})e(-{0,1}\\d+)/eis",
"'\\1'.((strlen('\\1')) ? '*' : '').'10^(\\2)'", $expr);
121 $this->last_error = null;
123 if (substr($expr, -1, 1) ==
';') $expr = substr($expr, 0, strlen($expr)-1);
126 if (preg_match(
'/^\s*([a-z]\w*)\s*=\s*(.+)$/', $expr, $matches)) {
127 if (in_array($matches[1], $this->vb)) {
128 return $this->
trigger(
"cannot assign to constant '$matches[1]'");
130 if (($tmp = $this->
pfx($this->
nfx($matches[2]))) ===
false)
return false;
131 $this->
v[$matches[1]] = $tmp;
132 return $this->
v[$matches[1]];
135 } elseif (preg_match(
'/^\s*([a-z]\w*)\s*\(\s*([a-z]\w*(?:\s*,\s*[a-z]\w*)*)\s*\)\s*=\s*(.+)$/', $expr, $matches)) {
137 if (in_array($matches[1], $this->fb)) {
138 return $this->
trigger(
"cannot redefine built-in function '$matches[1]()'");
140 $args = explode(
",", preg_replace(
"/\s+/",
"", $matches[2]));
141 if (($stack = $this->
nfx($matches[3])) ===
false)
return false;
142 for ($i = 0; $i<count($stack); $i++) {
144 if (preg_match(
'/^[a-z]\w*$/', $token) and !in_array($token, $args)) {
145 if (array_key_exists($token, $this->
v)) {
146 $stack[$i] = $this->
v[$token];
148 return $this->
trigger(
"undefined variable '$token' in function definition");
152 $this->f[$fnn] = array(
'args'=>$args,
'func'=>$stack);
156 return $this->
pfx($this->
nfx($expr));
162 unset($output[
'pi']);
169 foreach ($this->f as $fnn=>$dat)
170 $output[] = $fnn .
'(' . implode(
',', $dat[
'args']) .
')';
182 $expr = trim(strtolower($expr));
184 $ops = array(
'+',
'-',
'*',
'/',
'^',
'_');
185 $ops_r = array(
'+'=>0,
'-'=>0,
'*'=>0,
'/'=>0,
'^'=>1);
186 $ops_p = array(
'+'=>0,
'-'=>0,
'*'=>1,
'/'=>1,
'_'=>1,
'^'=>2);
188 $expecting_op =
false;
191 if (preg_match(
"/[^\w\s+*^\/()\.,-]/", $expr, $matches)) {
192 return $this->
trigger(
"illegal character '{$matches[0]}'");
196 $op = substr($expr, $index, 1);
198 $ex = preg_match(
'/^([01]+[bB]|[\da-fA-F]+[hH]|[a-z]\w*\(?|\d+(?:\.\d*)?|\.\d+|\()/', substr($expr, $index), $match);
200 if ($op ==
'-' and !$expecting_op) {
203 } elseif ($op ==
'_') {
204 return $this->
trigger(
"illegal character '_'");
206 } elseif ((in_array($op, $ops) or $ex) and $expecting_op) {
211 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])) {
212 $output[] = $stack->pop();
217 $expecting_op =
false;
219 } elseif ($op ==
')' and $expecting_op) {
220 while (($o2 = $stack->pop()) !=
'(') {
221 if (is_null($o2))
return $this->
trigger(
"unexpected ')'");
222 else $output[] = $o2;
224 if (preg_match(
"/^([a-z]\w*)\($/", $stack->last(2), $matches)) {
226 $arg_count = $stack->pop();
227 $output[] = $stack->pop();
228 if (in_array($fnn, $this->fb)) {
230 return $this->
trigger(
"too many arguments ($arg_count given, 1 expected)");
231 } elseif (array_key_exists($fnn, $this->f)) {
232 if ($arg_count != count($this->f[$fnn][
'args']))
233 return $this->
trigger(
"wrong number of arguments ($arg_count given, " . count($this->f[$fnn][
'args']) .
" expected)");
235 return $this->
trigger(
"internal error");
240 } elseif ($op ==
',' and $expecting_op) {
241 while (($o2 = $stack->pop()) !=
'(') {
242 if (is_null($o2))
return $this->
trigger(
"unexpected ','");
243 else $output[] = $o2;
246 if (!preg_match(
"/^([a-z]\w*)\($/", $stack->last(2), $matches))
247 return $this->
trigger(
"unexpected ','");
248 $stack->push($stack->pop()+1);
251 $expecting_op =
false;
253 } elseif ($op ==
'(' and !$expecting_op) {
258 } elseif ($ex and !$expecting_op) {
259 $expecting_op =
true;
261 if (preg_match(
"/^([a-z]\w*)\($/", $val, $matches)) {
262 if (in_array($matches[1], $this->fb) or array_key_exists($matches[1], $this->f)) {
266 $expecting_op =
false;
274 $index += strlen($val);
276 } elseif ($op ==
')') {
277 return $this->
trigger(
"unexpected ')'");
278 } elseif (in_array($op, $ops) and !$expecting_op) {
279 return $this->
trigger(
"unexpected operator '$op'");
281 return $this->
trigger(
"an unexpected error occured");
283 if ($index == strlen($expr)) {
284 if (in_array($op, $ops)) {
285 return $this->
trigger(
"operator '$op' lacks operand");
290 while (substr($expr, $index, 1) ==
' ') {
295 while (!is_null($op = $stack->pop())) {
296 if ($op ==
'(')
return $this->
trigger(
"expecting ')'");
303 function pfx($tokens, $vars = array()) {
305 if ($tokens ==
false)
return false;
309 foreach ($tokens as $token) {
311 if (in_array($token, array(
'+',
'-',
'*',
'/',
'^'))) {
312 if (is_null($op2 = $stack->pop()))
return $this->
trigger(
"internal error");
313 if (is_null($op1 = $stack->pop()))
return $this->
trigger(
"internal error");
314 include_once
"class.ilMath.php";
323 if ($op2 == 0)
return $this->
trigger(
"division by zero");
329 } elseif ($token ==
"_") {
330 $stack->push(-1*$stack->pop());
332 } elseif (preg_match(
"/^([a-z]\w*)\($/", $token, $matches)) {
334 if (in_array($fnn, $this->fb)) {
335 if (is_null($op1 = $stack->pop()))
return $this->
trigger(
"internal error");
336 $fnn = preg_replace(
"/^arc/",
"a", $fnn);
337 if ($fnn ==
'ln') $fnn =
'log';
338 eval(
'$stack->push(' . $fnn .
'($op1));');
339 } elseif (array_key_exists($fnn, $this->f)) {
342 for ($i = count($this->f[$fnn][
'args'])-1; $i >= 0; $i--) {
343 if (is_null($args[$this->f[$fnn][
'args'][$i]] = $stack->pop()))
return $this->
trigger(
"internal error");
345 $stack->push($this->
pfx($this->f[$fnn][
'func'], $args));
349 if (is_numeric($token)) {
350 $stack->push($token);
351 } elseif (($hex=$this->
from_hexbin($token))!==FALSE) {
353 } elseif (array_key_exists($token, $this->
v)) {
354 $stack->push($this->
v[$token]);
355 } elseif (array_key_exists($token, $vars)) {
356 $stack->push($vars[$token]);
358 return $this->
trigger(
"undefined variable '$token'");
363 if ($stack->count != 1)
return $this->
trigger(
"internal error");
364 return $stack->pop();
369 $this->last_error = $msg;
370 if (!$this->suppress_errors) trigger_error($msg, E_USER_WARNING);
377 if (strtoupper(substr($token, -1, 1))==
'H')
return hexdec($token);
378 if (strtoupper(substr($token, -1, 1))==
'B')
return bindec($token);
395 if ($this->count > 0) {
403 return $this->stack[$this->count-
$n];