diff options
author | NeonXP <frei@neonxp.info> | 2013-09-06 08:19:02 +0400 |
---|---|---|
committer | NeonXP <frei@neonxp.info> | 2013-09-06 08:19:02 +0400 |
commit | 9cef8dbc799343f6fc0fca926fbef4917b94f335 (patch) | |
tree | 915397133271cdc9e2e86a800be02ec695184fdc | |
parent | 4b08ec4b4dbf83dd242d7882e852b8d933ef0560 (diff) |
+ Added cache, which speeds up the repetitive calculations
+ Returned variables, because they need for cached expressions
-rw-r--r-- | README.md | 19 | ||||
-rw-r--r-- | src/NXP/Classes/Calculator.php | 19 | ||||
-rw-r--r-- | src/NXP/Classes/Lexer.php | 4 | ||||
-rw-r--r-- | src/NXP/Classes/Token/TokenVariable.php | 25 | ||||
-rw-r--r-- | src/NXP/Classes/TokenFactory.php | 26 | ||||
-rw-r--r-- | src/NXP/Exception/IncorrectBracketsException.php | 2 | ||||
-rw-r--r-- | src/NXP/Exception/UnknownVariableException.php | 19 | ||||
-rw-r--r-- | src/NXP/MathExecutor.php | 93 |
8 files changed, 196 insertions, 11 deletions
@@ -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; } |