<?php
/**
* This file contains a class to parse and calculate a mathematical expression.
* Allowed functions are: sin, cos, tan, sqrt, abs and ln (natural logarithm)
* Allowed constans are: PI and E
*/
dirname(__FILE__) . "/classes/parser/parser.php";
require_once "classes/parser/parser.php";
class MathParser extends Parser {
private $constants;
private $operators;
private $functions;
private $stack;
public function __construct($string, $flags = 0) {
parent::__construct($string, $flags);
$this->constants = array(
"pi" => M_PI,
"e" => M_E
);
$this->operators = array(
"+" => array("priority" => 0, "func" => create_function('$x,$y', 'return $x + $y;')),
"-" => array("priority" => 0, "func" => create_function('$x,$y', 'return $x - $y;')),
"*" => array("priority" => 1, "func" => create_function('$x,$y', 'return $x * $y;')),
"/" => array("priority" => 1, "func" => create_function('$x,$y', 'return $x / $y;')),
"^" => array("priority" => 2, "func" => create_function('$x,$y', 'return pow($x, $y);'))
);
$this->functions = array(
'sin' => create_function('$x', 'return sin($x);'),
'cos' => create_function('$x', 'return cos($x);'),
'tan' => create_function('$x', 'return tan($x);'),
'sqrt' => create_function('$x', 'return sqrt($x);'),
'abs' => create_function('$x', 'return abs($x);'),
"ln" => create_function('$x', 'return log($x);')
);
$this->stack = array();
}
private function compute($number, $operator = "+") {
$level = count($this->stack) - 1;
array_unshift($this->stack[$level], array("number" => $number, "operator" => $operator));
while (count($this->stack[$level]) > 1) {
$op0 = $this->stack[$level][0]["operator"];
$op1 = $this->stack[$level][1]["operator"];
$priority0 = $this->operators[$op0]["priority"];
$priority1 = $this->operators[$op1]["priority"];
if ($priority0 <= $priority1) {
$func = $this->operators[$op1]["func"];
$n0 = $this->stack[$level][0]["number"];
$n1 = $this->stack[$level][1]["number"];
$this->stack[$level][1]["number"] = $func($n1, $n0);
$this->stack[$level][1]["operator"] = $op0;
array_shift($this->stack[$level]);
} else {
break;
}
}
return $this->stack[$level][0]["number"];
}
protected function constant() {
return $this->in(array_keys($this->constants));
}
protected function operator() {
return $this->in(array_keys($this->operators));
}
protected function func() {
$functions = array_keys($this->functions);
if (list($func) = $this->in(array_keys($this->functions))) {
$f = $this->functions[$func];
if (!list($number) = $this->is("term")) {
throw new ParserException($this, "Unrecognized term");
}
return array($f($number));
}
return FALSE;
}
protected function term() {
$ret = FALSE;
if ($this->eq("(")) {
if (list($number) = $this->is("expression")) {
$ret = array($number);
}
if (!$this->eq(")")) {
throw new ParserException($this, "Missing ')'");
}
} else
if ($this->eq("-")) {
if (!list($number) = $this->is("term")) {
throw new ParserException($this, "Unrecognized term");
}
$ret = array(-$number);
} else
if (list($const) = $this->is("constant")) {
$ret = array($this->constants[$const]);
} else
if ( (list($number) = $this->number()) || (list($number) = $this->is("func")) ) {
$ret = array($number);
}
return $ret;
}
protected function expression() {
array_push($this->stack, array());
$result = 0;
$op = "+";
do {
$this->compute($result, $op);
if (!list($result) = $this->is("term")) {
throw new ParserException($this, "Unrecognized term");
}
} while (list($op) = $this->is("operator"));
$result = $this->compute($result);
array_pop($this->stack);
return array($result);
}
protected function _parse() {
return $this->is("expression");
}
}
$error = "";
$result = 0;
$expression = isset($_REQUEST["expression"])? $_REQUEST["expression"] : "-25 + 48 * (32^2 - ln E) + sin(PI/2) - 5^2";
// calculates the expression
$p = new MathParser($expression);
try {
list($result) = $p->parse();
} catch (ParserException $e) {
$error = $e->getPrintableMessage();
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Math Parser</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<form action="<?php echo $_SERVER["PHP_SELF"] ?>" method="post">
<div>
<label for="expression">Enter a mathematical expression:</label><br />
<input type="text" name="expression" id="expression" value="<?php echo htmlentities($expression) ?>" size="80" />
<input type="submit" value="Calculate!" />
</div>
<?php if ($error): ?>
<pre style="color: brown; "><strong><?php echo $error ?></strong></pre>
<?php else: ?>
<p><strong>Result is</strong>: <?php echo htmlentities($result) ?></p>
<?php endif ?>
<p style="color: gray; ">
Allowed functions: sin, cos, tan, sqrt, abs, ln<br />
Allowed constants: PI, E
</p>
</form>
</body>
</html>
|