diff options
author | zhukv <zhuk2205@gmail.com> | 2013-08-03 14:47:47 +0400 |
---|---|---|
committer | zhukv <zhuk2205@gmail.com> | 2013-08-03 14:47:47 +0400 |
commit | eb9c3651614dd5e5aef067880092e9f622c264df (patch) | |
tree | e093d7928420255e986acb44d4ab34634f601c52 /NXP | |
parent | 253fb694a3fcafa3f9ea6da6681f0b176cdec1f4 (diff) |
Fix to PSR standart, fix tokenizer, fix function executor.
Diffstat (limited to 'NXP')
-rw-r--r-- | NXP/Classes/Func.php | 41 | ||||
-rw-r--r-- | NXP/Classes/Operand.php | 85 | ||||
-rw-r--r-- | NXP/Classes/Token.php | 53 | ||||
-rw-r--r-- | NXP/Classes/TokenParser.php | 159 | ||||
-rw-r--r-- | NXP/MathExecutor.php | 264 | ||||
-rw-r--r-- | NXP/Tests/MathTest.php | 64 |
6 files changed, 0 insertions, 666 deletions
diff --git a/NXP/Classes/Func.php b/NXP/Classes/Func.php deleted file mode 100644 index b3e5b93..0000000 --- a/NXP/Classes/Func.php +++ /dev/null @@ -1,41 +0,0 @@ -<?php -/** - * Author: Alexander "NeonXP" Kiryukhin - * Date: 17.03.13 - * Time: 4:30 - */ - -namespace NXP\Classes; - - -class Func { - /** - * @var string - */ - private $name; - - /** - * @var callable - */ - private $callback; - - /** - * @param $name - * @param $callback - */ - function __construct($name, $callback) - { - $this->name = $name; - $this->callback = $callback; - } - - public function getName() - { - return $this->name; - } - - public function getCallback() - { - return $this->callback; - } -}
\ No newline at end of file diff --git a/NXP/Classes/Operand.php b/NXP/Classes/Operand.php deleted file mode 100644 index 3329679..0000000 --- a/NXP/Classes/Operand.php +++ /dev/null @@ -1,85 +0,0 @@ -<?php -/** - * Author: Alexander "NeonXP" Kiryukhin - * Date: 17.03.13 - * Time: 4:27 - */ - -namespace NXP\Classes; - - -class Operand { - const LEFT_ASSOCIATED = 'LEFT_ASSOCIATED'; - const RIGHT_ASSOCIATED = 'RIGHT_ASSOCIATED'; - const ASSOCIATED = 'ASSOCIATED'; - - const UNARY = 'UNARY'; - const BINARY = 'BINARY'; - - /** - * @var string - */ - private $symbol; - - /** - * @var int - */ - private $priority; - - /** - * @var string - */ - private $association; - - /** - * @var string - */ - private $type; - - /** - * @var callable - */ - private $callback; - - /** - * @param $symbol - * @param $priority - * @param $association - * @param $type - * @param $callback - */ - function __construct($symbol, $priority, $association, $type, $callback) - { - $this->association = $association; - $this->symbol = $symbol; - $this->type = $type; - $this->priority = $priority; - $this->callback = $callback; - } - - public function getAssociation() - { - return $this->association; - } - - public function getSymbol() - { - return $this->symbol; - } - - public function getType() - { - return $this->type; - } - - public function getCallback() - { - return $this->callback; - } - - public function getPriority() - { - return $this->priority; - } - -}
\ No newline at end of file diff --git a/NXP/Classes/Token.php b/NXP/Classes/Token.php deleted file mode 100644 index 28bc736..0000000 --- a/NXP/Classes/Token.php +++ /dev/null @@ -1,53 +0,0 @@ -<?php -/** - * Author: Alexander "NeonXP" Kiryukhin - * Date: 17.03.13 - * Time: 3:23 - */ - -namespace NXP\Classes; - - -class Token { - - const NOTHING = 'NOTHING'; - const STRING = 'STRING'; - const NUMBER = 'NUMBER'; - const OPERATOR = 'OPERATOR'; - const LEFT_BRACKET = 'LEFT_BRACKET'; - const RIGHT_BRACKET = 'RIGHT_BRACKET'; - const FUNC = 'FUNC'; - - /** - * @var string - */ - protected $value; - - /** - * @var string - */ - protected $type; - - function __construct($type, $value) - { - $this->type = $type; - $this->value = $value; - } - - /** - * @return string - */ - public function getType() - { - return $this->type; - } - - /** - * @return string - */ - public function getValue() - { - return $this->value; - } - -}
\ No newline at end of file diff --git a/NXP/Classes/TokenParser.php b/NXP/Classes/TokenParser.php deleted file mode 100644 index 7b9255f..0000000 --- a/NXP/Classes/TokenParser.php +++ /dev/null @@ -1,159 +0,0 @@ -<?php -/** - * Author: Alexander "NeonXP" Kiryukhin - * Date: 17.03.13 - * Time: 2:45 - */ - -namespace NXP\Classes; - - -class TokenParser { - const DIGIT = 'DIGIT'; - const CHAR = 'CHAR'; - const SPECIAL_CHAR = 'SPECIAL_CHAR'; - const LEFT_BRACKET = 'LEFT_BRACKET'; - const RIGHT_BRACKET = 'RIGHT_BRACKET'; - const SPACE = 'SPACE'; - - private $terms = [ - self::DIGIT => '[0-9\.]', - self::CHAR => '[a-z]', - self::SPECIAL_CHAR => '[\!\@\#\$\%\^\&\*\/\|\-\+\=\~]', - self::LEFT_BRACKET => '\(', - self::RIGHT_BRACKET => '\)', - self::SPACE => '\s' - ]; - - const ERROR_STATE = 'ERROR_STATE'; - - private $transitions = [ - Token::NOTHING => [ - self::DIGIT => Token::NUMBER, - self::CHAR => Token::STRING, - self::SPECIAL_CHAR => Token::OPERATOR, - self::LEFT_BRACKET => Token::LEFT_BRACKET, - self::RIGHT_BRACKET => Token::RIGHT_BRACKET, - self::SPACE => Token::NOTHING - ], - Token::STRING => [ - self::DIGIT => Token::STRING, - self::CHAR => Token::STRING, - self::SPECIAL_CHAR => Token::OPERATOR, - self::LEFT_BRACKET => Token::LEFT_BRACKET, - self::RIGHT_BRACKET => Token::RIGHT_BRACKET, - self::SPACE => Token::NOTHING - ], - Token::NUMBER => [ - self::DIGIT => Token::NUMBER, - self::CHAR => self::ERROR_STATE, - self::SPECIAL_CHAR => Token::OPERATOR, - self::LEFT_BRACKET => Token::LEFT_BRACKET, - self::RIGHT_BRACKET => Token::RIGHT_BRACKET, - self::SPACE => Token::NOTHING - ], - Token::OPERATOR => [ - self::DIGIT => Token::NUMBER, - self::CHAR => Token::STRING, - self::SPECIAL_CHAR => Token::OPERATOR, - self::LEFT_BRACKET => Token::LEFT_BRACKET, - self::RIGHT_BRACKET => Token::RIGHT_BRACKET, - self::SPACE => Token::NOTHING - ], - self::ERROR_STATE => [ - self::DIGIT => self::ERROR_STATE, - self::CHAR => self::ERROR_STATE, - self::SPECIAL_CHAR => self::ERROR_STATE, - self::LEFT_BRACKET => self::ERROR_STATE, - self::RIGHT_BRACKET => self::ERROR_STATE, - self::SPACE => self::ERROR_STATE - ], - Token::LEFT_BRACKET => [ - self::DIGIT => Token::NUMBER, - self::CHAR => Token::STRING, - self::SPECIAL_CHAR => Token::OPERATOR, - self::LEFT_BRACKET => Token::LEFT_BRACKET, - self::RIGHT_BRACKET => Token::RIGHT_BRACKET, - self::SPACE => Token::NOTHING - ], - Token::RIGHT_BRACKET => [ - self::DIGIT => Token::NUMBER, - self::CHAR => Token::STRING, - self::SPECIAL_CHAR => Token::OPERATOR, - self::LEFT_BRACKET => Token::LEFT_BRACKET, - self::RIGHT_BRACKET => Token::RIGHT_BRACKET, - self::SPACE => Token::NOTHING - ], - ]; - - private $accumulator = ''; - - private $state = Token::NOTHING; - - private $queue = null; - - function __construct() - { - $this->queue = new \SplQueue(); - } - - /** - * Tokenize math expression - * @param $expression - * @return \SplQueue - * @throws \Exception - */ - public function tokenize($expression) - { - $oldState = null; - for ($i=0; $i<strlen($expression); $i++) { - $char = substr($expression, $i, 1); - $class = $this->getSymbolType($char); - $oldState = $this->state; - $this->state = $this->transitions[$this->state][$class]; - if ($this->state == self::ERROR_STATE) { - throw new \Exception("Parse expression error at $i column (symbol '$char')"); - } - $this->addToQueue($oldState); - $this->accumulator .= $char; - } - if (!empty($this->accumulator)) { - $token = new Token($this->state, $this->accumulator); - $this->queue->push($token); - } - - return $this->queue; - } - - /** - * @param $symbol - * @return string - * @throws \Exception - */ - private function getSymbolType($symbol) - { - foreach ($this->terms as $class => $regex) { - if (preg_match("/$regex/i", $symbol)) { - return $class; - } - } - - throw new \Exception("Unknown char '$symbol'"); - } - - /** - * @param $oldState - */ - private function addToQueue($oldState) - { - if ($oldState == Token::NOTHING) { - $this->accumulator = ''; - return; - } - if (($this->state != $oldState) || ($oldState == Token::LEFT_BRACKET) || ($oldState == Token::RIGHT_BRACKET)) { - $token = new Token($oldState, $this->accumulator); - $this->queue->push($token); - $this->accumulator = ''; - } - } -}
\ No newline at end of file diff --git a/NXP/MathExecutor.php b/NXP/MathExecutor.php deleted file mode 100644 index cc1c187..0000000 --- a/NXP/MathExecutor.php +++ /dev/null @@ -1,264 +0,0 @@ -<?php -/** - * Author: Alexander "NeonXP" Kiryukhin - * Date: 14.03.13 - * Time: 1:01 - */ -namespace NXP; - -use NXP\Classes\Func; -use NXP\Classes\Operand; -use NXP\Classes\Token; -use NXP\Classes\TokenParser; - -/** - * Class MathExecutor - * @package NXP - */ -class MathExecutor { - - - private $operators = [ ]; - - private $functions = [ ]; - - private $variables = [ ]; - - /** - * @var \SplStack - */ - private $stack; - - /** - * @var \SplQueue - */ - private $queue; - - /** - * Base math operators - */ - public function __construct() - { - $this->addOperator(new Operand('+', 1, Operand::LEFT_ASSOCIATED, Operand::BINARY, function ($op1, $op2) { return $op1+$op2; })); - $this->addOperator(new Operand('-', 1, Operand::LEFT_ASSOCIATED, Operand::BINARY, function ($op1, $op2) { return $op1-$op2; })); - $this->addOperator(new Operand('*', 2, Operand::LEFT_ASSOCIATED, Operand::BINARY, function ($op1, $op2) { return $op1*$op2; })); - $this->addOperator(new Operand('/', 2, Operand::LEFT_ASSOCIATED, Operand::BINARY, function ($op1, $op2) { return $op1/$op2; })); - $this->addOperator(new Operand('^', 3, Operand::LEFT_ASSOCIATED, Operand::BINARY, function ($op1, $op2) { return pow($op1,$op2); })); - - $this->addFunction(new Func('sin', function ($arg) { return sin($arg); })); - $this->addFunction(new Func('cos', function ($arg) { return cos($arg); })); - $this->addFunction(new Func('tn', function ($arg) { return tan($arg); })); - $this->addFunction(new Func('asin', function ($arg) { return asin($arg); })); - $this->addFunction(new Func('acos', function ($arg) { return acos($arg); })); - $this->addFunction(new Func('atn', function ($arg) { return atan($arg); })); - } - - /** - * Add operator to executor - * @param Operand $operator - */ - public function addOperator(Operand $operator) - { - $this->operators[$operator->getSymbol()] = $operator; - } - - /** - * Add function to executor - * @param Func $function - */ - public function addFunction(Func $function) - { - $this->functions[$function->getName()] = $function->getCallback(); - } - - /** - * Add variable to executor - * @param $variable - * @param $value - * @throws \Exception - */ - public function setVar($variable, $value) - { - if (!is_numeric($value)) { - throw new \Exception("Variable value must be a number"); - } - $this->variables[$variable] = $value; - } - - /** - * Execute expression - * @param $expression - * @return int|float - */ - public function execute($expression) - { - $reversePolishNotation = $this->convertToReversePolishNotation($expression); - $result = $this->calculateReversePolishNotation($reversePolishNotation); - - return $result; - } - - /** - * Convert expression from normal expression form to RPN - * @param $expression - * @return \SplQueue - * @throws \Exception - */ - private function convertToReversePolishNotation($expression) - { - $this->stack = new \SplStack(); - $this->queue = new \SplQueue(); - - $tokenParser = new TokenParser(); - $input = $tokenParser->tokenize($expression); - - foreach ($input as $token) { - $this->categorizeToken($token); - } - - while (!$this->stack->isEmpty()) { - $token = $this->stack->pop(); - if ($token->getType() != Token::OPERATOR) { - throw new \Exception('Opening bracket without closing bracket'); - } - $this->queue->push($token); - } - - return $this->queue; - } - - /** - * @param Token $token - * @throws \Exception - */ - private function categorizeToken(Token $token) - { - switch ($token->getType()) { - case Token::NUMBER : - $this->queue->push($token); - break; - - case Token::STRING: - if (array_key_exists($token->getValue(), $this->variables)) { - $this->queue->push(new Token(Token::NUMBER, $this->variables[$token->getValue()])); - } else { - $this->stack->push($token); - } - break; - - case Token::LEFT_BRACKET: - $this->stack->push($token); - break; - - case Token::RIGHT_BRACKET: - $previousToken = $this->stack->pop(); - while (!$this->stack->isEmpty() && ($previousToken->getType() != Token::LEFT_BRACKET)) { - $this->queue->push($previousToken); - $previousToken = $this->stack->pop(); - } - if ((!$this->stack->isEmpty()) && ($this->stack->top()->getType() == Token::STRING)) { - $string = $this->stack->pop()->getValue(); - if (!array_key_exists($string, $this->functions)) { - throw new \Exception('Unknown function'); - } - $this->queue->push(new Token(Token::FUNC, $string)); - } - break; - - case Token::OPERATOR: - if (!array_key_exists($token->getValue(), $this->operators)) { - throw new \Exception("Unknown operator '{$token->getValue()}'"); - } - - $this->proceedOperator($token); - $this->stack->push($token); - break; - - default: - throw new \Exception('Unknown token'); - } - } - - /** - * @param $token - * @throws \Exception - */ - private function proceedOperator($token) - { - if (!array_key_exists($token->getValue(), $this->operators)) { - throw new \Exception('Unknown operator'); - } - /** @var Operand $operator */ - $operator = $this->operators[$token->getValue()]; - while (!$this->stack->isEmpty()) { - $top = $this->stack->top(); - if ($top->getType() == Token::OPERATOR) { - $priority = $this->operators[$top->getValue()]->getPriority(); - if ( $operator->getAssociation() == Operand::RIGHT_ASSOCIATED) { - if (($priority > $operator->getPriority())) { - $this->queue->push($this->stack->pop()); - } else { - return; - } - } else { - if (($priority >= $operator->getPriority())) { - $this->queue->push($this->stack->pop()); - } else { - return; - } - } - } elseif ($top->getType() == Token::STRING) { - $this->queue->push($this->stack->pop()); - } else { - return; - } - } - } - - /** - * @param \SplQueue $expression - * @return mixed - * @throws \Exception - */ - private function calculateReversePolishNotation(\SplQueue $expression) - { - $this->stack = new \SplStack(); - /** @val Token $token */ - foreach ($expression as $token) { - switch ($token->getType()) { - case Token::NUMBER : - $this->stack->push($token); - break; - case Token::OPERATOR: - /** @var Operand $operator */ - $operator = $this->operators[$token->getValue()]; - if ($operator->getType() == Operand::BINARY) { - $arg2 = $this->stack->pop()->getValue(); - $arg1 = $this->stack->pop()->getValue(); - } else { - $arg2 = null; - $arg1 = $this->stack->pop()->getValue(); - } - $callback = $operator->getCallback(); - - - $this->stack->push(new Token(Token::NUMBER, ($callback($arg1, $arg2)))); - break; - case Token::FUNC: - /** @var Func $function */ - $callback = $this->functions[$token->getValue()]; - $arg = $this->stack->pop()->getValue(); - $this->stack->push(new Token(Token::NUMBER, ($callback($arg)))); - break; - default: - throw new \Exception('Unknown token'); - } - } - $result = $this->stack->pop()->getValue(); - if (!$this->stack->isEmpty()) { - throw new \Exception('Incorrect expression'); - } - - return $result; - } -}
\ No newline at end of file diff --git a/NXP/Tests/MathTest.php b/NXP/Tests/MathTest.php deleted file mode 100644 index 6bfcf55..0000000 --- a/NXP/Tests/MathTest.php +++ /dev/null @@ -1,64 +0,0 @@ -<?php -/** - * Author: Alexander "NeonXP" Kiryukhin - * Date: 14.03.13 - * Time: 3:41 - */ -namespace NXP\Tests; - -use \NXP\MathExecutor; - -class MathTest extends \PHPUnit_Framework_TestCase { - public function setup() - { - require '../MathExecutor.php'; - require '../Classes/Func.php'; - require '../Classes/Operand.php'; - require '../Classes/Token.php'; - require '../Classes/TokenParser.php'; - } - public function testCalculating() - { - $calculator = new MathExecutor(); - for ($i = 1; $i <= 10; $i++) { - $expression = $this->generateExpression(); - print "Test #$i. Expression: '$expression'\t"; - - eval('$result1 = ' . $expression . ';'); - print "PHP result: $result1 \t"; - $result2 = $calculator->execute($expression); - print "NXP Math Executor result: $result2\n"; - $this->assertEquals($result1, $result2); - } - } - - private function generateExpression() - { - $operators = [ '+', '-', '*', '/' ]; - $number = true; - $expression = ''; - $brackets = 0; - for ($i = 1; $i < rand(1,10)*2; $i++) { - if ($number) { - $expression .= rand(1,100)*0.5; - } else { - $expression .= $operators[rand(0,3)]; - } - $number = !$number; - $rand = rand(1,5); - if (($rand == 1) && ($number)) { - $expression .= '('; - $brackets++; - } elseif (($rand == 2) && (!$number) && ($brackets > 0)) { - $expression .= ')'; - $brackets--; - } - } - if ($number) { - $expression .= rand(1,100)*0.5; - } - $expression .= str_repeat(')', $brackets); - - return $expression; - } -}
\ No newline at end of file |