diff options
Diffstat (limited to 'src/NXP/Classes')
22 files changed, 847 insertions, 355 deletions
diff --git a/src/NXP/Classes/Calculator.php b/src/NXP/Classes/Calculator.php new file mode 100644 index 0000000..e74b7ab --- /dev/null +++ b/src/NXP/Classes/Calculator.php @@ -0,0 +1,46 @@ +<?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; + +use NXP\Classes\Token\InterfaceOperator; +use NXP\Classes\Token\TokenFunction; +use NXP\Classes\Token\TokenNumber; +use NXP\Exception\IncorrectExpressionException; + +/** + * @author Alexander Kiryukhin <alexander@symdev.org> + */ +class Calculator +{ + /** + * @param array $tokens Tokens in reverse polish notation + * @return number + * @throws \NXP\Exception\IncorrectExpressionException + */ + public function calculate($tokens) + { + $stack = array(); + foreach ($tokens as $token) { + if ($token instanceof TokenNumber) { + array_push($stack, $token); + } + if ($token instanceof InterfaceOperator || $token instanceof TokenFunction) { + array_push($stack, $token->execute($stack)); + } + } + $result = array_pop($stack); + if (!empty($stack)) { + throw new IncorrectExpressionException(); + } + + return $result->getValue(); + } +} diff --git a/src/NXP/Classes/Func.php b/src/NXP/Classes/Func.php deleted file mode 100644 index e8c0fa2..0000000 --- a/src/NXP/Classes/Func.php +++ /dev/null @@ -1,45 +0,0 @@ -<?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; - -class Func -{ - /** - * @var string - */ - private $name; - - /** - * @var callable - */ - private $callback; - - /** - * @param $name - * @param $callback - */ - public function __construct($name, $callback) - { - $this->name = $name; - $this->callback = $callback; - } - - public function getName() - { - return $this->name; - } - - public function getCallback() - { - return $this->callback; - } -} diff --git a/src/NXP/Classes/Lexer.php b/src/NXP/Classes/Lexer.php new file mode 100644 index 0000000..676962d --- /dev/null +++ b/src/NXP/Classes/Lexer.php @@ -0,0 +1,121 @@ +<?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; +use NXP\Classes\Token\AbstractOperator; +use NXP\Classes\Token\InterfaceOperator; +use NXP\Classes\Token\TokenComma; +use NXP\Classes\Token\TokenFunction; +use NXP\Classes\Token\TokenLeftBracket; +use NXP\Classes\Token\TokenNumber; +use NXP\Classes\Token\TokenRightBracket; +use NXP\Exception\IncorrectBracketsException; +use NXP\Exception\IncorrectExpressionException; + +/** + * @author Alexander Kiryukhin <alexander@symdev.org> + */ +class Lexer +{ + /** + * @var TokenFactory + */ + private $tokenFactory; + + public function __construct($tokenFactory) + { + $this->tokenFactory = $tokenFactory; + } + + /** + * @param string $input Source string of equation + * @return array Tokens stream + * @throws \NXP\Exception\IncorrectExpressionException + */ + public function stringToTokensStream($input) + { + $matches = array(); + preg_match_all($this->tokenFactory->getTokenParserRegex(), $input, $matches); + $tokensStream = array_map( + function ($token) { + return $this->tokenFactory->createToken($token); + }, + $matches[0] + ); + + return $tokensStream; + } + + /** + * @param array $tokensStream Tokens stream + * @return array Array of tokens in revers polish notation + * @throws \NXP\Exception\IncorrectExpressionException + */ + public function buildReversePolishNotation($tokensStream) + { + $output = array(); + $stack = array(); + + foreach ($tokensStream as $token) { + if ($token instanceof TokenNumber) { + $output[] = $token; + } + if ($token instanceof TokenFunction) { + array_push($stack, $token); + } + if ($token instanceof TokenLeftBracket) { + array_push($stack, $token); + } + if ($token instanceof TokenComma) { + while (($current = array_pop($stack)) && (!$current instanceof TokenLeftBracket)) { + $output[] = $current; + if (empty($stack)) { + throw new IncorrectExpressionException(); + } + } + } + if ($token instanceof TokenRightBracket) { + while (($current = array_pop($stack)) && (!$current instanceof TokenLeftBracket)) { + $output[] = $current; + } + if (!empty($stack) && ($stack[count($stack)-1] instanceof TokenFunction)) { + $output[] = array_pop($stack); + } + } + + if ($token instanceof AbstractOperator) { + while ( + count($stack) > 0 && + ($stack[count($stack)-1] instanceof InterfaceOperator) && + ( + $token->getAssociation() == AbstractOperator::LEFT_ASSOC && + $token->getPriority() <= $stack[count($stack)-1]->getPriority() + ) || ( + $token->getAssociation() == AbstractOperator::RIGHT_ASSOC && + $token->getPriority() < $stack[count($stack)-1]->getPriority() + ) + ) { + $output[] = array_pop($stack); + } + + array_push($stack, $token); + } + } + while (!empty($stack)) { + $token = array_pop($stack); + if ($token instanceof TokenLeftBracket || $token instanceof TokenRightBracket) { + throw new IncorrectBracketsException(); + } + $output[] = $token; + } + + return $output; + } +} diff --git a/src/NXP/Classes/Operand.php b/src/NXP/Classes/Operand.php deleted file mode 100644 index fae0c69..0000000 --- a/src/NXP/Classes/Operand.php +++ /dev/null @@ -1,89 +0,0 @@ -<?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; - -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 - */ - public 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; - } - -} diff --git a/src/NXP/Classes/Token.php b/src/NXP/Classes/Token.php deleted file mode 100644 index bbcd5bc..0000000 --- a/src/NXP/Classes/Token.php +++ /dev/null @@ -1,56 +0,0 @@ -<?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; - -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; - - public 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; - } - -} diff --git a/src/NXP/Classes/Token/AbstractContainerToken.php b/src/NXP/Classes/Token/AbstractContainerToken.php new file mode 100644 index 0000000..12d49d2 --- /dev/null +++ b/src/NXP/Classes/Token/AbstractContainerToken.php @@ -0,0 +1,46 @@ +<?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> + */ +abstract class AbstractContainerToken implements InterfaceToken +{ + /** + * @var string + */ + protected $value; + + /** + * @param string $value + */ + public function __construct($value) + { + $this->value = $value; + } + + /** + * @param string $value + */ + public function setValue($value) + { + $this->value = $value; + } + + /** + * @return string + */ + public function getValue() + { + return $this->value; + } +} diff --git a/src/NXP/Classes/Token/AbstractOperator.php b/src/NXP/Classes/Token/AbstractOperator.php new file mode 100644 index 0000000..6cdfe99 --- /dev/null +++ b/src/NXP/Classes/Token/AbstractOperator.php @@ -0,0 +1,20 @@ +<?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> + */ +abstract class AbstractOperator implements InterfaceToken, InterfaceOperator +{ + const RIGHT_ASSOC = 'RIGHT'; + const LEFT_ASSOC = 'LEFT'; +} diff --git a/src/NXP/Classes/Token/InterfaceFunction.php b/src/NXP/Classes/Token/InterfaceFunction.php new file mode 100644 index 0000000..be867b0 --- /dev/null +++ b/src/NXP/Classes/Token/InterfaceFunction.php @@ -0,0 +1,23 @@ +<?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> + */ +interface InterfaceFunction +{ + /** + * @param array $stack + * @return $this + */ + public function execute(&$stack); +} diff --git a/src/NXP/Classes/Token/InterfaceOperator.php b/src/NXP/Classes/Token/InterfaceOperator.php new file mode 100644 index 0000000..da6cdf0 --- /dev/null +++ b/src/NXP/Classes/Token/InterfaceOperator.php @@ -0,0 +1,33 @@ +<?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> + */ +interface InterfaceOperator +{ + /** + * @return int + */ + public function getPriority(); + + /** + * @return string + */ + public function getAssociation(); + + /** + * @param array $stack + * @return TokenNumber + */ + public function execute(&$stack); +} diff --git a/src/NXP/Classes/Token/InterfaceToken.php b/src/NXP/Classes/Token/InterfaceToken.php new file mode 100644 index 0000000..86fec91 --- /dev/null +++ b/src/NXP/Classes/Token/InterfaceToken.php @@ -0,0 +1,22 @@ +<?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> + */ +interface InterfaceToken +{ + /** + * @return string + */ + public static function getRegex(); +} diff --git a/src/NXP/Classes/Token/TokenComma.php b/src/NXP/Classes/Token/TokenComma.php new file mode 100644 index 0000000..f590e32 --- /dev/null +++ b/src/NXP/Classes/Token/TokenComma.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 TokenComma implements InterfaceToken +{ + /** + * @return string + */ + public static function getRegex() + { + return '\,'; + } +} diff --git a/src/NXP/Classes/Token/TokenDegree.php b/src/NXP/Classes/Token/TokenDegree.php new file mode 100644 index 0000000..8488dcd --- /dev/null +++ b/src/NXP/Classes/Token/TokenDegree.php @@ -0,0 +1,54 @@ +<?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 TokenDegree extends AbstractOperator +{ + /** + * @return string + */ + public static function getRegex() + { + return '\^'; + } + + /** + * @return int + */ + public function getPriority() + { + return 3; + } + + /** + * @return string + */ + public function getAssociation() + { + return self::RIGHT_ASSOC; + } + + /** + * @param InterfaceToken[] $stack + * @return $this + */ + public function execute(&$stack) + { + $op2 = array_pop($stack); + $op1 = array_pop($stack); + $result = $op1->getValue() ^ $op2->getValue(); + + return new TokenNumber($result); + } +} diff --git a/src/NXP/Classes/Token/TokenDivision.php b/src/NXP/Classes/Token/TokenDivision.php new file mode 100644 index 0000000..479a4ec --- /dev/null +++ b/src/NXP/Classes/Token/TokenDivision.php @@ -0,0 +1,54 @@ +<?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 TokenDivision extends AbstractOperator +{ + /** + * @return string + */ + public static function getRegex() + { + return '\/'; + } + + /** + * @return int + */ + public function getPriority() + { + return 2; + } + + /** + * @return string + */ + public function getAssociation() + { + return self::LEFT_ASSOC; + } + + /** + * @param InterfaceToken[] $stack + * @return $this + */ + public function execute(&$stack) + { + $op2 = array_pop($stack); + $op1 = array_pop($stack); + $result = $op1->getValue() / $op2->getValue(); + + return new TokenNumber($result); + } +} diff --git a/src/NXP/Classes/Token/TokenFunction.php b/src/NXP/Classes/Token/TokenFunction.php new file mode 100644 index 0000000..23f64bd --- /dev/null +++ b/src/NXP/Classes/Token/TokenFunction.php @@ -0,0 +1,41 @@ +<?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 TokenFunction extends AbstractContainerToken implements InterfaceFunction +{ + /** + * @return string + */ + public static function getRegex() + { + return '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*'; + } + + /** + * @param array $stack + * @return $this + */ + public function execute(&$stack) + { + $args = array(); + list($places, $function) = $this->value; + for ($i = 0; $i < $places; $i++) { + array_push($args, array_pop($stack)->getValue()); + } + $result = call_user_func_array($function, $args); + + return new TokenNumber($result); + } +} diff --git a/src/NXP/Classes/Token/TokenLeftBracket.php b/src/NXP/Classes/Token/TokenLeftBracket.php new file mode 100644 index 0000000..0cfdc1a --- /dev/null +++ b/src/NXP/Classes/Token/TokenLeftBracket.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 TokenLeftBracket implements InterfaceToken +{ + /** + * @return string + */ + public static function getRegex() + { + return '\('; + } +} diff --git a/src/NXP/Classes/Token/TokenMinus.php b/src/NXP/Classes/Token/TokenMinus.php new file mode 100644 index 0000000..0463d4c --- /dev/null +++ b/src/NXP/Classes/Token/TokenMinus.php @@ -0,0 +1,54 @@ +<?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 TokenMinus extends AbstractOperator +{ + /** + * @return string + */ + public static function getRegex() + { + return '\-'; + } + + /** + * @return int + */ + public function getPriority() + { + return 1; + } + + /** + * @return string + */ + public function getAssociation() + { + return self::LEFT_ASSOC; + } + + /** + * @param InterfaceToken[] $stack + * @return $this + */ + public function execute(&$stack) + { + $op2 = array_pop($stack); + $op1 = array_pop($stack); + $result = $op1->getValue() - $op2->getValue(); + + return new TokenNumber($result); + } +} diff --git a/src/NXP/Classes/Token/TokenMultiply.php b/src/NXP/Classes/Token/TokenMultiply.php new file mode 100644 index 0000000..e6fd960 --- /dev/null +++ b/src/NXP/Classes/Token/TokenMultiply.php @@ -0,0 +1,54 @@ +<?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 TokenMultiply extends AbstractOperator +{ + /** + * @return string + */ + public static function getRegex() + { + return '\*'; + } + + /** + * @return int + */ + public function getPriority() + { + return 2; + } + + /** + * @return string + */ + public function getAssociation() + { + return self::LEFT_ASSOC; + } + + /** + * @param InterfaceToken[] $stack + * @return $this + */ + public function execute(&$stack) + { + $op2 = array_pop($stack); + $op1 = array_pop($stack); + $result = $op1->getValue() * $op2->getValue(); + + return new TokenNumber($result); + } +} diff --git a/src/NXP/Classes/Token/TokenNumber.php b/src/NXP/Classes/Token/TokenNumber.php new file mode 100644 index 0000000..763ca04 --- /dev/null +++ b/src/NXP/Classes/Token/TokenNumber.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 TokenNumber extends AbstractContainerToken +{ + /** + * @return string + */ + public static function getRegex() + { + return '\-?\d+\.?\d*'; + } +} diff --git a/src/NXP/Classes/Token/TokenPlus.php b/src/NXP/Classes/Token/TokenPlus.php new file mode 100644 index 0000000..f9562e7 --- /dev/null +++ b/src/NXP/Classes/Token/TokenPlus.php @@ -0,0 +1,54 @@ +<?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 TokenPlus extends AbstractOperator +{ + /** + * @return string + */ + public static function getRegex() + { + return '\+'; + } + + /** + * @return int + */ + public function getPriority() + { + return 1; + } + + /** + * @return string + */ + public function getAssociation() + { + return self::LEFT_ASSOC; + } + + /** + * @param InterfaceToken[] $stack + * @return $this + */ + public function execute(&$stack) + { + $op2 = array_pop($stack); + $op1 = array_pop($stack); + $result = $op1->getValue() + $op2->getValue(); + + return new TokenNumber($result); + } +} diff --git a/src/NXP/Classes/Token/TokenRightBracket.php b/src/NXP/Classes/Token/TokenRightBracket.php new file mode 100644 index 0000000..c68473a --- /dev/null +++ b/src/NXP/Classes/Token/TokenRightBracket.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 TokenRightBracket implements InterfaceToken +{ + /** + * @return string + */ + public static function getRegex() + { + return '\)'; + } +} diff --git a/src/NXP/Classes/TokenFactory.php b/src/NXP/Classes/TokenFactory.php new file mode 100644 index 0000000..924203d --- /dev/null +++ b/src/NXP/Classes/TokenFactory.php @@ -0,0 +1,125 @@ +<?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; + +use NXP\Classes\Token\InterfaceToken; +use NXP\Classes\Token\TokenComma; +use NXP\Classes\Token\TokenFunction; +use NXP\Classes\Token\TokenLeftBracket; +use NXP\Classes\Token\TokenNumber; +use NXP\Classes\Token\TokenRightBracket; +use NXP\Exception\UnknownFunctionException; +use NXP\Exception\UnknownOperatorException; +use NXP\Exception\UnknownTokenException; + +/** + * @author Alexander Kiryukhin <alexander@symdev.org> + */ +class TokenFactory +{ + /** + * Available operators + * + * @var array + */ + protected $operators = array(); + + /** + * Available functions + * + * @var array + */ + protected $functions = array(); + + /** + * @param $name + * @param $function + * @param $places + */ + public function addFunction($name, $function, $places = 1) + { + $this->functions[$name] = array($places, $function); + } + + public function addOperator($operatorClass) + { + $class = new \ReflectionClass($operatorClass); + + if (!in_array('NXP\Classes\Token\InterfaceToken', $class->getInterfaceNames())) { + throw new UnknownOperatorException; + } + + $this->operators[] = $operatorClass; + $this->operators = array_unique($this->operators); + } + + /** + * @return string + */ + public function getTokenParserRegex() + { + $operatorsRegex = ''; + foreach ($this->operators as $operator) { + $operatorsRegex .= $operator::getRegex(); + } + + return sprintf( + '/(%s)|([%s])|(%s)|([%s%s%s])/i', + TokenNumber::getRegex(), + $operatorsRegex, + TokenFunction::getRegex(), + TokenLeftBracket::getRegex(), + TokenRightBracket::getRegex(), + TokenComma::getRegex() + ); + } + + /** + * @param string $token + * @return InterfaceToken + * @throws UnknownTokenException + */ + public function createToken($token) + { + if (is_numeric($token)) { + return new TokenNumber($token); + } + + if ($token == '(') { + return new TokenLeftBracket(); + } + + if ($token == ')') { + return new TokenRightBracket(); + } + + if ($token == ',') { + return new TokenComma(); + } + + foreach ($this->operators as $operator) { + $regex = sprintf('/%s/i', $operator::getRegex()); + if (preg_match($regex, $token)) { + return new $operator; + } + } + + $regex = sprintf('/%s/i', TokenFunction::getRegex()); + if (preg_match($regex, $token)) { + if (isset($this->functions[$token])) { + return new TokenFunction($this->functions[$token]); + } else { + throw new UnknownFunctionException(); + } + } + throw new UnknownTokenException(); + } +} diff --git a/src/NXP/Classes/TokenParser.php b/src/NXP/Classes/TokenParser.php deleted file mode 100644 index f498184..0000000 --- a/src/NXP/Classes/TokenParser.php +++ /dev/null @@ -1,165 +0,0 @@ -<?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; - -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 = array( - 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 = array( - Token::NOTHING => array( - 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 => array( - 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 => array( - 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 => array( - 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 => array( - 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 => array( - 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 => array( - 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; - - public 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 = ''; - } - } -} |