aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeonXP <frei@neonxp.info>2013-09-06 08:19:02 +0400
committerNeonXP <frei@neonxp.info>2013-09-06 08:19:02 +0400
commit9cef8dbc799343f6fc0fca926fbef4917b94f335 (patch)
tree915397133271cdc9e2e86a800be02ec695184fdc
parent4b08ec4b4dbf83dd242d7882e852b8d933ef0560 (diff)
+ Added cache, which speeds up the repetitive calculations
+ Returned variables, because they need for cached expressions
-rw-r--r--README.md19
-rw-r--r--src/NXP/Classes/Calculator.php19
-rw-r--r--src/NXP/Classes/Lexer.php4
-rw-r--r--src/NXP/Classes/Token/TokenVariable.php25
-rw-r--r--src/NXP/Classes/TokenFactory.php26
-rw-r--r--src/NXP/Exception/IncorrectBracketsException.php2
-rw-r--r--src/NXP/Exception/UnknownVariableException.php19
-rw-r--r--src/NXP/MathExecutor.php93
8 files changed, 196 insertions, 11 deletions
diff --git a/README.md b/README.md
index 9bc06e3..8000e35 100644
--- a/README.md
+++ b/README.md
@@ -99,4 +99,21 @@ And adding to executor:
```php
$executor->addOperator('MyNamespace\ModulusToken');
-``` \ No newline at end of file
+```
+
+## Variables:
+
+Default variables:
+
+$pi = 3.14159265359
+$e = 2.71828182846
+
+You can add own variable to executor:
+
+```php
+$executor->setVars(array(
+ 'var1' => 0.15,
+ 'var2' => 0.22
+));
+
+$executor->execute("$var1 + $var2"); \ No newline at end of file
diff --git a/src/NXP/Classes/Calculator.php b/src/NXP/Classes/Calculator.php
index e74b7ab..41e0d9f 100644
--- a/src/NXP/Classes/Calculator.php
+++ b/src/NXP/Classes/Calculator.php
@@ -13,7 +13,9 @@ namespace NXP\Classes;
use NXP\Classes\Token\InterfaceOperator;
use NXP\Classes\Token\TokenFunction;
use NXP\Classes\Token\TokenNumber;
+use NXP\Classes\Token\TokenVariable;
use NXP\Exception\IncorrectExpressionException;
+use NXP\Exception\UnknownVariableException;
/**
* @author Alexander Kiryukhin <alexander@symdev.org>
@@ -21,17 +23,28 @@ use NXP\Exception\IncorrectExpressionException;
class Calculator
{
/**
- * @param array $tokens Tokens in reverse polish notation
- * @return number
+ * Calculate array of tokens in reverse polish notation
+ * @param array $tokens Array of tokens
+ * @param array $variables Array of variables
+ * @return number Result
* @throws \NXP\Exception\IncorrectExpressionException
+ * @throws \NXP\Exception\UnknownVariableException
*/
- public function calculate($tokens)
+ public function calculate($tokens, $variables)
{
$stack = array();
foreach ($tokens as $token) {
if ($token instanceof TokenNumber) {
array_push($stack, $token);
}
+ if ($token instanceof TokenVariable) {
+ $variable = $token->getValue();
+ if (!array_key_exists($variable, $variables)) {
+ throw new UnknownVariableException();
+ }
+ $value = $variables[$variable];
+ array_push($stack, new TokenNumber($value));
+ }
if ($token instanceof InterfaceOperator || $token instanceof TokenFunction) {
array_push($stack, $token->execute($stack));
}
diff --git a/src/NXP/Classes/Lexer.php b/src/NXP/Classes/Lexer.php
index 676962d..63a87b2 100644
--- a/src/NXP/Classes/Lexer.php
+++ b/src/NXP/Classes/Lexer.php
@@ -16,6 +16,7 @@ use NXP\Classes\Token\TokenFunction;
use NXP\Classes\Token\TokenLeftBracket;
use NXP\Classes\Token\TokenNumber;
use NXP\Classes\Token\TokenRightBracket;
+use NXP\Classes\Token\TokenVariable;
use NXP\Exception\IncorrectBracketsException;
use NXP\Exception\IncorrectExpressionException;
@@ -67,6 +68,9 @@ class Lexer
if ($token instanceof TokenNumber) {
$output[] = $token;
}
+ if ($token instanceof TokenVariable) {
+ $output[] = $token;
+ }
if ($token instanceof TokenFunction) {
array_push($stack, $token);
}
diff --git a/src/NXP/Classes/Token/TokenVariable.php b/src/NXP/Classes/Token/TokenVariable.php
new file mode 100644
index 0000000..ccd7c83
--- /dev/null
+++ b/src/NXP/Classes/Token/TokenVariable.php
@@ -0,0 +1,25 @@
+<?php
+/**
+ * This file is part of the MathExecutor package
+ *
+ * (c) Alexander Kiryukhin
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code
+ */
+
+namespace NXP\Classes\Token;
+
+/**
+ * @author Alexander Kiryukhin <alexander@symdev.org>
+ */
+class TokenVariable extends AbstractContainerToken
+{
+ /**
+ * @return string
+ */
+ public static function getRegex()
+ {
+ return '\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*';
+ }
+}
diff --git a/src/NXP/Classes/TokenFactory.php b/src/NXP/Classes/TokenFactory.php
index 924203d..19ba1cf 100644
--- a/src/NXP/Classes/TokenFactory.php
+++ b/src/NXP/Classes/TokenFactory.php
@@ -16,6 +16,7 @@ use NXP\Classes\Token\TokenFunction;
use NXP\Classes\Token\TokenLeftBracket;
use NXP\Classes\Token\TokenNumber;
use NXP\Classes\Token\TokenRightBracket;
+use NXP\Classes\Token\TokenVariable;
use NXP\Exception\UnknownFunctionException;
use NXP\Exception\UnknownOperatorException;
use NXP\Exception\UnknownTokenException;
@@ -40,6 +41,7 @@ class TokenFactory
protected $functions = array();
/**
+ * Add function
* @param $name
* @param $function
* @param $places
@@ -49,6 +51,11 @@ class TokenFactory
$this->functions[$name] = array($places, $function);
}
+ /**
+ * Add operator
+ * @param string $operatorClass
+ * @throws \NXP\Exception\UnknownOperatorException
+ */
public function addOperator($operatorClass)
{
$class = new \ReflectionClass($operatorClass);
@@ -62,6 +69,16 @@ class TokenFactory
}
/**
+ * Add variable
+ * @param string $name
+ * @param mixed $value
+ */
+ public function addVariable($name, $value)
+ {
+
+ }
+
+ /**
* @return string
*/
public function getTokenParserRegex()
@@ -72,10 +89,11 @@ class TokenFactory
}
return sprintf(
- '/(%s)|([%s])|(%s)|([%s%s%s])/i',
+ '/(%s)|([%s])|(%s)|(%s)|([%s%s%s])/i',
TokenNumber::getRegex(),
$operatorsRegex,
TokenFunction::getRegex(),
+ TokenVariable::getRegex(),
TokenLeftBracket::getRegex(),
TokenRightBracket::getRegex(),
TokenComma::getRegex()
@@ -112,6 +130,11 @@ class TokenFactory
}
}
+ $regex = sprintf('/%s/i', TokenVariable::getRegex());
+ if (preg_match($regex, $token)) {
+ return new TokenVariable(substr($token,1));
+ }
+
$regex = sprintf('/%s/i', TokenFunction::getRegex());
if (preg_match($regex, $token)) {
if (isset($this->functions[$token])) {
@@ -120,6 +143,7 @@ class TokenFactory
throw new UnknownFunctionException();
}
}
+
throw new UnknownTokenException();
}
}
diff --git a/src/NXP/Exception/IncorrectBracketsException.php b/src/NXP/Exception/IncorrectBracketsException.php
index 68d67c6..e2aaed9 100644
--- a/src/NXP/Exception/IncorrectBracketsException.php
+++ b/src/NXP/Exception/IncorrectBracketsException.php
@@ -12,7 +12,7 @@
namespace NXP\Exception;
/**
- * @author V@author Alexander Kiryukhin <alexander@symdev.org>
+ * @author Alexander Kiryukhin <alexander@symdev.org>
*/
class IncorrectBracketsException extends \Exception
{
diff --git a/src/NXP/Exception/UnknownVariableException.php b/src/NXP/Exception/UnknownVariableException.php
new file mode 100644
index 0000000..8de9493
--- /dev/null
+++ b/src/NXP/Exception/UnknownVariableException.php
@@ -0,0 +1,19 @@
+<?php
+
+/**
+ * This file is part of the MathExecutor package
+ *
+ * (c) Alexander Kiryukhin
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code
+ */
+
+namespace NXP\Exception;
+
+/**
+ * @author Alexander Kiryukhin <alexander@symdev.org>
+ */
+class UnknownVariableException extends \Exception
+{
+}
diff --git a/src/NXP/MathExecutor.php b/src/NXP/MathExecutor.php
index a9bf8a9..7eaa914 100644
--- a/src/NXP/MathExecutor.php
+++ b/src/NXP/MathExecutor.php
@@ -23,11 +23,23 @@ use NXP\Classes\TokenFactory;
class MathExecutor
{
/**
+ * Available variables
+ *
+ * @var array
+ */
+ private $variables = array();
+
+ /**
* @var TokenFactory
*/
private $tokenFactory;
/**
+ * @var array
+ */
+ private $cache = array();
+
+ /**
* Base math operators
*/
public function __construct()
@@ -63,6 +75,72 @@ class MathExecutor
$this->tokenFactory->addFunction('max', 'max', 2);
$this->tokenFactory->addFunction('avg', function($arg1, $arg2) { return ($arg1 + $arg2) / 2; }, 2);
+ $this->setVars(array(
+ 'pi' => 3.14159265359,
+ 'e' => 2.71828182846
+ ));
+ }
+
+ /**
+ * Add variable to executor
+ *
+ * @param string $variable
+ * @param integer|float $value
+ * @throws \Exception
+ * @return MathExecutor
+ */
+ public function setVar($variable, $value)
+ {
+ if (!is_numeric($value)) {
+ throw new \Exception("Variable value must be a number");
+ }
+
+ $this->variables[$variable] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Add variables to executor
+ *
+ * @param array $variables
+ * @param bool $clear Clear previous variables
+ * @return MathExecutor
+ */
+ public function setVars(array $variables, $clear = true)
+ {
+ if ($clear) {
+ $this->removeVars();
+ }
+
+ foreach ($variables as $name => $value) {
+ $this->setVar($name, $value);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Remove variable from executor
+ *
+ * @param string $variable
+ * @return MathExecutor
+ */
+ public function removeVar($variable)
+ {
+ unset ($this->variables[$variable]);
+
+ return $this;
+ }
+
+ /**
+ * Remove all variables
+ */
+ public function removeVars()
+ {
+ $this->variables = array();
+
+ return $this;
}
/**
@@ -97,15 +175,20 @@ class MathExecutor
* Execute expression
*
* @param $expression
- * @return int|float
+ * @return number
*/
public function execute($expression)
{
- $lexer = new Lexer($this->tokenFactory);
- $tokensStream = $lexer->stringToTokensStream($expression);
- $tokens = $lexer->buildReversePolishNotation($tokensStream);
+ if (!array_key_exists($expression, $this->cache)) {
+ $lexer = new Lexer($this->tokenFactory);
+ $tokensStream = $lexer->stringToTokensStream($expression);
+ $tokens = $lexer->buildReversePolishNotation($tokensStream);
+ $this->cache[$expression] = $tokens;
+ } else {
+ $tokens = $this->cache[$expression];
+ }
$calculator = new Calculator();
- $result = $calculator->calculate($tokens);
+ $result = $calculator->calculate($tokens, $this->variables);
return $result;
}