aboutsummaryrefslogtreecommitdiff
path: root/src/NXP/Classes
diff options
context:
space:
mode:
authorAlexander Kiryukhin <a.kiryukhin@mail.ru>2020-05-15 21:51:23 +0300
committerAlexander Kiryukhin <a.kiryukhin@mail.ru>2020-05-15 21:51:23 +0300
commitcab8e2d38ae1c8c7fb75022f7d9b0539a0a86d4e (patch)
treed3107b0f586885d56b13dc65411b455a7aee37cb /src/NXP/Classes
parent01415abc9d7f7401d9f4c09fbbec24930c65a097 (diff)
Massive refactoring
More clean structure Parsing without regular expressions
Diffstat (limited to 'src/NXP/Classes')
-rw-r--r--src/NXP/Classes/Calculator.php61
-rw-r--r--src/NXP/Classes/CustomFunction.php63
-rw-r--r--src/NXP/Classes/Lexer.php161
-rw-r--r--src/NXP/Classes/Operator.php69
-rw-r--r--src/NXP/Classes/Token.php35
-rw-r--r--src/NXP/Classes/Token/AbstractContainerToken.php46
-rw-r--r--src/NXP/Classes/Token/AbstractOperator.php51
-rw-r--r--src/NXP/Classes/Token/InterfaceFunction.php23
-rw-r--r--src/NXP/Classes/Token/InterfaceOperator.php33
-rw-r--r--src/NXP/Classes/Token/InterfaceToken.php22
-rw-r--r--src/NXP/Classes/Token/TokenAnd.php53
-rw-r--r--src/NXP/Classes/Token/TokenComma.php53
-rw-r--r--src/NXP/Classes/Token/TokenDegree.php64
-rw-r--r--src/NXP/Classes/Token/TokenDivision.php70
-rw-r--r--src/NXP/Classes/Token/TokenEqual.php53
-rw-r--r--src/NXP/Classes/Token/TokenFunction.php42
-rw-r--r--src/NXP/Classes/Token/TokenGreaterThan.php53
-rw-r--r--src/NXP/Classes/Token/TokenGreaterThanOrEqual.php53
-rw-r--r--src/NXP/Classes/Token/TokenLeftBracket.php25
-rw-r--r--src/NXP/Classes/Token/TokenLessThan.php53
-rw-r--r--src/NXP/Classes/Token/TokenLessThanOrEqual.php53
-rw-r--r--src/NXP/Classes/Token/TokenMinus.php68
-rw-r--r--src/NXP/Classes/Token/TokenMultiply.php64
-rw-r--r--src/NXP/Classes/Token/TokenNotEqual.php53
-rw-r--r--src/NXP/Classes/Token/TokenNumber.php25
-rw-r--r--src/NXP/Classes/Token/TokenOr.php53
-rw-r--r--src/NXP/Classes/Token/TokenPlus.php64
-rw-r--r--src/NXP/Classes/Token/TokenRightBracket.php25
-rw-r--r--src/NXP/Classes/Token/TokenStringDoubleQuoted.php25
-rw-r--r--src/NXP/Classes/Token/TokenStringSingleQuoted.php26
-rw-r--r--src/NXP/Classes/Token/TokenVariable.php25
-rw-r--r--src/NXP/Classes/TokenFactory.php217
-rw-r--r--src/NXP/Classes/Tokenizer.php313
33 files changed, 526 insertions, 1568 deletions
diff --git a/src/NXP/Classes/Calculator.php b/src/NXP/Classes/Calculator.php
index 7d82ecd..21f3178 100644
--- a/src/NXP/Classes/Calculator.php
+++ b/src/NXP/Classes/Calculator.php
@@ -13,10 +13,12 @@ namespace NXP\Classes;
use NXP\Classes\Token\InterfaceOperator;
use NXP\Classes\Token\TokenFunction;
use NXP\Classes\Token\TokenNumber;
-use NXP\Classes\Token\TokenStringSingleQuoted;
use NXP\Classes\Token\TokenStringDoubleQuoted;
+use NXP\Classes\Token\TokenStringSingleQuoted;
use NXP\Classes\Token\TokenVariable;
use NXP\Exception\IncorrectExpressionException;
+use NXP\Exception\UnknownFunctionException;
+use NXP\Exception\UnknownOperatorException;
use NXP\Exception\UnknownVariableException;
/**
@@ -25,35 +27,64 @@ use NXP\Exception\UnknownVariableException;
class Calculator
{
/**
+ * @var CustomFunction[]
+ */
+ private $functions;
+
+ /**
+ * @var Operator[]
+ */
+ private $operators;
+
+ /**
+ * Calculator constructor.
+ * @param CustomFunction[] $functions
+ * @param Operator[] $operators
+ */
+ public function __construct(array $functions, array $operators)
+ {
+ $this->functions = $functions;
+ $this->operators = $operators;
+ }
+
+ /**
* Calculate array of tokens in reverse polish notation
- * @param array $tokens
- * @param array $variables
- * @return number Result
- * @throws \NXP\Exception\IncorrectExpressionException
- * @throws \NXP\Exception\UnknownVariableException
+ * @param Token[] $tokens
+ * @param array $variables
+ * @return mixed
+ * @throws IncorrectExpressionException
+ * @throws UnknownVariableException
*/
public function calculate($tokens, $variables)
{
+ /** @var Token[] $stack */
$stack = [];
foreach ($tokens as $token) {
- if ($token instanceof TokenNumber || $token instanceof TokenStringDoubleQuoted || $token instanceof TokenStringSingleQuoted) {
+ if ($token->type === Token::Literal || $token->type === Token::String) {
$stack[] = $token;
- } else if ($token instanceof TokenVariable) {
- $variable = $token->getValue();
+ } else if ($token->type === Token::Variable) {
+ $variable = $token->value;
if (!array_key_exists($variable, $variables)) {
throw new UnknownVariableException($variable);
}
$value = $variables[$variable];
- $stack[] = new TokenNumber($value);
- } else if ($token instanceof InterfaceOperator || $token instanceof TokenFunction) {
- $stack[] = $token->execute($stack);
+ $stack[] = new Token(Token::Literal, $value);
+ } else if ($token->type === Token::Function) {
+ if (!array_key_exists($token->value, $this->functions)) {
+ throw new UnknownFunctionException($token->value);
+ }
+ $stack[] = $this->functions[$token->value]->execute($stack);
+ } elseif ($token->type === Token::Operator) {
+ if (!array_key_exists($token->value, $this->operators)) {
+ throw new UnknownOperatorException($token->value);
+ }
+ $stack[] = $this->operators[$token->value]->execute($stack);
}
}
$result = array_pop($stack);
- if ($result === null || ! empty($stack)) {
+ if ($result === null || !empty($stack)) {
throw new IncorrectExpressionException();
}
-
- return $result->getValue();
+ return $result->value;
}
}
diff --git a/src/NXP/Classes/CustomFunction.php b/src/NXP/Classes/CustomFunction.php
new file mode 100644
index 0000000..944f7d9
--- /dev/null
+++ b/src/NXP/Classes/CustomFunction.php
@@ -0,0 +1,63 @@
+<?php
+
+
+namespace NXP\Classes;
+
+
+use NXP\Exception\IncorrectExpressionException;
+use ReflectionException;
+use ReflectionFunction;
+
+class CustomFunction
+{
+ /**
+ * @var string
+ */
+ public $name;
+
+ /**
+ * @var callable $function
+ */
+ public $function;
+
+ /**
+ * @var int
+ */
+ public $places;
+
+ /**
+ * CustomFunction constructor.
+ * @param string $name
+ * @param callable $function
+ * @param int $places
+ * @throws ReflectionException
+ */
+ public function __construct(string $name, callable $function, $places = null)
+ {
+ $this->name = $name;
+ $this->function = $function;
+ if ($places === null) {
+ $reflection = new ReflectionFunction($function);
+ $this->places = $reflection->getNumberOfParameters();
+ } else {
+ $this->places = $places;
+ }
+ }
+
+ public function execute(&$stack)
+ {
+ if (count($stack) < $this->places) {
+ throw new IncorrectExpressionException();
+ }
+ $args = [];
+ for ($i = 0; $i < $this->places; $i++) {
+ array_unshift($args, array_pop($stack)->value);
+ }
+
+ $result = call_user_func_array($this->function, $args);
+
+ return new Token(Token::Literal, $result);
+ }
+
+
+} \ No newline at end of file
diff --git a/src/NXP/Classes/Lexer.php b/src/NXP/Classes/Lexer.php
deleted file mode 100644
index 9964de9..0000000
--- a/src/NXP/Classes/Lexer.php
+++ /dev/null
@@ -1,161 +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;
-
-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\TokenMinus;
-use NXP\Classes\Token\TokenNumber;
-use NXP\Classes\Token\TokenRightBracket;
-use NXP\Classes\Token\TokenStringDoubleQuoted;
-use NXP\Classes\Token\TokenStringSingleQuoted;
-use NXP\Classes\Token\TokenVariable;
-use NXP\Exception\IncorrectBracketsException;
-use NXP\Exception\IncorrectExpressionException;
-
-/**
- * @author Alexander Kiryukhin <a.kiryukhin@mail.ru>
- */
-class Lexer
-{
- /**
- * @var TokenFactory
- */
- private $tokenFactory;
-
- public function __construct($tokenFactory)
- {
- $this->tokenFactory = $tokenFactory;
- }
-
- /**
- * @param string $input Source string of equation
- * @return array Tokens stream
- */
- public function stringToTokensStream($input)
- {
- $matches = [];
- preg_match_all($this->tokenFactory->getTokenParserRegex(), $input, $matches);
- $tokenFactory = $this->tokenFactory;
- $tokensStream = array_map(
- function ($token) use ($tokenFactory) {
- return $tokenFactory->createToken($token);
- },
- $matches[0]
- );
-
- return $tokensStream;
- }
-
- /**
- * @param array $tokensStream Tokens stream
- * @return array Array of tokens in revers polish notation
- * @throws IncorrectBracketsException
- */
- public function buildReversePolishNotation($tokensStream)
- {
- $output = [];
- $stack = [];
- $lastToken = null;
-
- foreach ($tokensStream as $token) {
- if ($token instanceof TokenStringDoubleQuoted) {
- $output[] = $token;
- } elseif ($token instanceof TokenStringSingleQuoted) {
- $output[] = $token;
- } elseif ($token instanceof TokenNumber) {
- // if the number starts with a minus sign, it could be a negative number, or it could be an operator grabbed by the greedy regex
- // if previous token is an operator or open bracket, then it negative, otherwise remove the minus sign and put a negative operator on the stack
- if ($lastToken !== null) {
- $value = $token->getValue();
- if (($value < 0 || $this->isNegativeZero($value)) && ! ($lastToken instanceof AbstractOperator || $lastToken instanceof TokenLeftBracket)) {
- $token = new TokenNumber(abs($value));
- $output[] = $token;
- $output[] = new TokenMinus('-');
- } else {
- $output[] = $token;
- }
- } else {
- $output[] = $token;
- }
- } elseif ($token instanceof TokenVariable) {
- $output[] = $token;
- } elseif ($token instanceof TokenFunction) {
- $stack[] = $token;
- } elseif ($token instanceof AbstractOperator) {
- // While we have something on the stack
- while (($count = count($stack)) > 0
- && (
- // If it is a function
- ($stack[$count - 1] instanceof TokenFunction)
-
- ||
- // Or the operator at the top of the operator stack
- // has (left associative and equal precedence)
- // or has greater precedence
- (($stack[$count - 1] instanceof InterfaceOperator) &&
- (
- ($stack[$count - 1]->getAssociation() == AbstractOperator::LEFT_ASSOC &&
- $token->getPriority() == $stack[$count - 1]->getPriority())
- ||
- ($stack[$count - 1]->getPriority() > $token->getPriority())
- )
- )
- )
-
- // And not a left bracket
- && (!($stack[$count - 1] instanceof TokenLeftBracket))) {
- $output[] = array_pop($stack);
- }
-
- // Comma operators do nothing really, don't put them on the stack
- if (! ($token instanceof TokenComma)) {
- $stack[] = $token;
- }
- } elseif ($token instanceof TokenLeftBracket) {
- $stack[] = $token;
- } elseif ($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);
- }
- }
- $lastToken = $token;
- }
- while (!empty($stack)) {
- $token = array_pop($stack);
- if ($token instanceof TokenLeftBracket || $token instanceof TokenRightBracket) {
- throw new IncorrectBracketsException();
- }
- $output[] = $token;
- }
-
- return $output;
- }
-
- /**
- * Check if the value is a negative zero
- *
- * @param int|float $x The value to check
- * @return boolean True if negative zero, false otherwise
- */
- private function isNegativeZero($x)
- {
- $floatVal = floatval($x);
-
- return $floatVal === 0.0 && $floatVal ** -1 === -INF;
- }
-}
diff --git a/src/NXP/Classes/Operator.php b/src/NXP/Classes/Operator.php
new file mode 100644
index 0000000..53550a9
--- /dev/null
+++ b/src/NXP/Classes/Operator.php
@@ -0,0 +1,69 @@
+<?php
+
+
+namespace NXP\Classes;
+
+
+use NXP\Exception\IncorrectExpressionException;
+use ReflectionFunction;
+
+class Operator
+{
+ /**
+ * @var string
+ */
+ public $operator;
+
+ /**
+ * @var bool
+ */
+ public $isRightAssoc;
+
+ /**
+ * @var int
+ */
+ public $priority;
+
+ /**
+ * @var callable<\SplStack>
+ */
+ public $function;
+
+ /**
+ * @var int
+ */
+ public $places;
+
+ /**
+ * Operator constructor.
+ * @param string $operator
+ * @param bool $isRightAssoc
+ * @param int $priority
+ * @param callable $function
+ */
+ public function __construct(string $operator, bool $isRightAssoc, int $priority, callable $function)
+ {
+ $this->operator = $operator;
+ $this->isRightAssoc = $isRightAssoc;
+ $this->priority = $priority;
+ $this->function = $function;
+ $this->function = $function;
+ $reflection = new ReflectionFunction($function);
+ $this->places = $reflection->getNumberOfParameters();
+ }
+
+ public function execute(&$stack)
+ {
+ if (count($stack) < $this->places) {
+ throw new IncorrectExpressionException();
+ }
+ $args = [];
+ for ($i = 0; $i < $this->places; $i++) {
+ array_unshift($args, array_pop($stack)->value);
+ }
+
+ $result = call_user_func_array($this->function, $args);
+
+ return new Token(Token::Literal, $result);
+ }
+} \ No newline at end of file
diff --git a/src/NXP/Classes/Token.php b/src/NXP/Classes/Token.php
new file mode 100644
index 0000000..49bf741
--- /dev/null
+++ b/src/NXP/Classes/Token.php
@@ -0,0 +1,35 @@
+<?php
+
+
+namespace NXP\Classes;
+
+class Token
+{
+ const Literal = "literal";
+ const Variable = "variable";
+ const Operator = "operator";
+ const LeftParenthesis = "LP";
+ const RightParenthesis = "RP";
+ const Function = "function";
+ const ParamSeparator = "separator";
+ const String = "string";
+ const Space = "space";
+
+ public $type = self::Literal;
+
+ /**
+ * @var float|string
+ */
+ public $value;
+
+ /**
+ * Token constructor.
+ * @param string $type
+ * @param float|string $value
+ */
+ public function __construct(string $type, $value)
+ {
+ $this->type = $type;
+ $this->value = $value;
+ }
+}
diff --git a/src/NXP/Classes/Token/AbstractContainerToken.php b/src/NXP/Classes/Token/AbstractContainerToken.php
deleted file mode 100644
index be2da5f..0000000
--- a/src/NXP/Classes/Token/AbstractContainerToken.php
+++ /dev/null
@@ -1,46 +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\Token;
-
-/**
- * @author Alexander Kiryukhin <a.kiryukhin@mail.ru>
- */
-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
deleted file mode 100644
index 67e8031..0000000
--- a/src/NXP/Classes/Token/AbstractOperator.php
+++ /dev/null
@@ -1,51 +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\Token;
-
-/**
- * @author Alexander Kiryukhin <a.kiryukhin@mail.ru>
- */
-abstract class AbstractOperator implements InterfaceToken, InterfaceOperator
-{
- const RIGHT_ASSOC = 'RIGHT';
- const LEFT_ASSOC = 'LEFT';
-
- /**
- * Divide by zero reporting
- *
- * @var bool
- */
- private $divideByZeroReporting = false;
-
- /**
- * Set division by zero exception reporting
- *
- * @param bool $exception default true
- *
- * @return $this
- */
- public function setDivisionByZeroException($exception = true)
- {
- $this->divideByZeroReporting = $exception;
-
- return $this;
- }
-
- /**
- * Get division by zero exception status
- *
- * @return bool
- */
- public function getDivisionByZeroException()
- {
- return $this->divideByZeroReporting;
- }
-}
diff --git a/src/NXP/Classes/Token/InterfaceFunction.php b/src/NXP/Classes/Token/InterfaceFunction.php
deleted file mode 100644
index a457d0e..0000000
--- a/src/NXP/Classes/Token/InterfaceFunction.php
+++ /dev/null
@@ -1,23 +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\Token;
-
-/**
- * @author Alexander Kiryukhin <a.kiryukhin@mail.ru>
- */
-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
deleted file mode 100644
index 9e3bae1..0000000
--- a/src/NXP/Classes/Token/InterfaceOperator.php
+++ /dev/null
@@ -1,33 +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\Token;
-
-/**
- * @author Alexander Kiryukhin <a.kiryukhin@mail.ru>
- */
-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
deleted file mode 100644
index db07aeb..0000000
--- a/src/NXP/Classes/Token/InterfaceToken.php
+++ /dev/null
@@ -1,22 +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\Token;
-
-/**
- * @author Alexander Kiryukhin <a.kiryukhin@mail.ru>
- */
-interface InterfaceToken
-{
- /**
- * @return string
- */
- public static function getRegex();
-}
diff --git a/src/NXP/Classes/Token/TokenAnd.php b/src/NXP/Classes/Token/TokenAnd.php
deleted file mode 100644
index dab4497..0000000
--- a/src/NXP/Classes/Token/TokenAnd.php
+++ /dev/null
@@ -1,53 +0,0 @@
-<?php
-
-namespace NXP\Classes\Token;
-
-use NXP\Exception\IncorrectExpressionException;
-
-class TokenAnd extends AbstractOperator
-{
- /**
- * @return string
- */
- public static function getRegex()
- {
- return '&&';
- }
-
- /**
- * @return int
- */
- public function getPriority()
- {
- return 100;
- }
-
- /**
- * @return string
- */
- public function getAssociation()
- {
- return self::LEFT_ASSOC;
- }
-
- /**
- * @param InterfaceToken[] $stack
- *
- * @return $this
- *
- * @throws \NXP\Exception\IncorrectExpressionException
- */
- public function execute(&$stack)
- {
- $op2 = array_pop($stack);
- $op1 = array_pop($stack);
-
- if ($op1 === null || $op2 === null) {
- throw new IncorrectExpressionException("&& requires two operators");
- }
-
- $result = $op1->getValue() && $op2->getValue();
-
- return new TokenNumber($result);
- }
-}
diff --git a/src/NXP/Classes/Token/TokenComma.php b/src/NXP/Classes/Token/TokenComma.php
deleted file mode 100644
index f6fc068..0000000
--- a/src/NXP/Classes/Token/TokenComma.php
+++ /dev/null
@@ -1,53 +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\Token;
-
-/**
- * @author Alexander Kiryukhin <a.kiryukhin@mail.ru>
- */
-class TokenComma extends AbstractOperator
-{
- /**
- * @return string
- */
- public static function getRegex()
- {
- return '\,';
- }
-
- /**
- * Comma operator is lowest priority
- *
- * @return int
- */
- public function getPriority()
- {
- return 0;
- }
-
- /**
- * @return string
- */
- public function getAssociation()
- {
- return self::LEFT_ASSOC;
- }
-
- /**
- * @param array $stack
- * @return TokenNumber
- */
- public function execute(&$stack)
- {
- // Comma operators don't do anything, stack has already executed
- }
-
-}
diff --git a/src/NXP/Classes/Token/TokenDegree.php b/src/NXP/Classes/Token/TokenDegree.php
deleted file mode 100644
index 0d22f91..0000000
--- a/src/NXP/Classes/Token/TokenDegree.php
+++ /dev/null
@@ -1,64 +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\Token;
-
-use NXP\Exception\IncorrectExpressionException;
-
-/**
-* @author Alexander Kiryukhin <a.kiryukhin@mail.ru>
-*/
-class TokenDegree extends AbstractOperator
-{
- /**
- * @return string
- */
- public static function getRegex()
- {
- return '\^';
- }
-
- /**
- * @return int
- */
- public function getPriority()
- {
- return 220;
- }
-
- /**
- * @return string
- */
- public function getAssociation()
- {
- return self::RIGHT_ASSOC;
- }
-
- /**
- * @param InterfaceToken[] $stack
- *
- * @return TokenNumber
- *
- * @throws \NXP\Exception\IncorrectExpressionException
- */
- public function execute(&$stack)
- {
- $op2 = array_pop($stack);
- $op1 = array_pop($stack);
-
- if ($op1 === null || $op2 === null) {
- throw new IncorrectExpressionException("Power operator requires two operators");
- }
-
- $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
deleted file mode 100644
index 328833b..0000000
--- a/src/NXP/Classes/Token/TokenDivision.php
+++ /dev/null
@@ -1,70 +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\Token;
-
-use NXP\Exception\IncorrectExpressionException;
-use NXP\Exception\DivisionByZeroException;
-
-/**
-* @author Alexander Kiryukhin <a.kiryukhin@mail.ru>
-*/
-class TokenDivision extends AbstractOperator
-{
- /**
- * @return string
- */
- public static function getRegex()
- {
- return '\/';
- }
-
- /**
- * @return int
- */
- public function getPriority()
- {
- return 180;
- }
-
- /**
- * @return string
- */
- public function getAssociation()
- {
- return self::LEFT_ASSOC;
- }
-
- /**
- * @param InterfaceToken[] $stack
- *
- * @return $this
- *
- * @throws \NXP\Exception\IncorrectExpressionException
- * @throws \NXP\Exception\DivisionByZeroException
- */
- public function execute(&$stack)
- {
- $op2 = array_pop($stack);
- $op1 = array_pop($stack);
-
- if ($op1 === null || $op2 === null) {
- throw new IncorrectExpressionException("Division requires two operators");
- }
-
- if ($this->getDivisionByZeroException() && $op2->getValue() == 0) {
- throw new DivisionByZeroException();
- }
-
- $result = $op2->getValue() != 0 ? $op1->getValue() / $op2->getValue() : 0;
-
- return new TokenNumber($result);
- }
-}
diff --git a/src/NXP/Classes/Token/TokenEqual.php b/src/NXP/Classes/Token/TokenEqual.php
deleted file mode 100644
index b0ac31e..0000000
--- a/src/NXP/Classes/Token/TokenEqual.php
+++ /dev/null
@@ -1,53 +0,0 @@
-<?php
-
-namespace NXP\Classes\Token;
-
-use NXP\Exception\IncorrectExpressionException;
-
-class TokenEqual extends AbstractOperator
-{
- /**
- * @return string
- */
- public static function getRegex()
- {
- return '\=\=';
- }
-
- /**
- * @return int
- */
- public function getPriority()
- {
- return 140;
- }
-
- /**
- * @return string
- */
- public function getAssociation()
- {
- return self::LEFT_ASSOC;
- }
-
- /**
- * @param InterfaceToken[] $stack
- *
- * @return $this
- *
- * @throws \NXP\Exception\IncorrectExpressionException
- */
- public function execute(&$stack)
- {
- $op2 = array_pop($stack);
- $op1 = array_pop($stack);
-
- if ($op1 === null || $op2 === null) {
- throw new IncorrectExpressionException("== requires two operators");
- }
-
- $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
deleted file mode 100644
index 432f107..0000000
--- a/src/NXP/Classes/Token/TokenFunction.php
+++ /dev/null
@@ -1,42 +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\Token;
-
-/**
- * @author Alexander Kiryukhin <a.kiryukhin@mail.ru>
- */
-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 = [];
- list($places, $function) = $this->value;
- for ($i = 0; $i < $places; $i++) {
- array_unshift($args, array_pop($stack)->getValue());
- }
-
- $result = call_user_func_array($function, $args);
-
- return new TokenNumber($result);
- }
-}
diff --git a/src/NXP/Classes/Token/TokenGreaterThan.php b/src/NXP/Classes/Token/TokenGreaterThan.php
deleted file mode 100644
index 51a5aca..0000000
--- a/src/NXP/Classes/Token/TokenGreaterThan.php
+++ /dev/null
@@ -1,53 +0,0 @@
-<?php
-
-namespace NXP\Classes\Token;
-
-use NXP\Exception\IncorrectExpressionException;
-
-class TokenGreaterThan extends AbstractOperator
-{
- /**
- * @return string
- */
- public static function getRegex()
- {
- return '>';
- }
-
- /**
- * @return int
- */
- public function getPriority()
- {
- return 150;
- }
-
- /**
- * @return string
- */
- public function getAssociation()
- {
- return self::LEFT_ASSOC;
- }
-
- /**
- * @param InterfaceToken[] $stack
- *
- * @return $this
- *
- * @throws \NXP\Exception\IncorrectExpressionException
- */
- public function execute(&$stack)
- {
- $op2 = array_pop($stack);
- $op1 = array_pop($stack);
-
- if ($op1 === null || $op2 === null) {
- throw new IncorrectExpressionException("> requires two operators");
- }
-
- $result = $op1->getValue() > $op2->getValue();
-
- return new TokenNumber($result);
- }
-}
diff --git a/src/NXP/Classes/Token/TokenGreaterThanOrEqual.php b/src/NXP/Classes/Token/TokenGreaterThanOrEqual.php
deleted file mode 100644
index aa4425f..0000000
--- a/src/NXP/Classes/Token/TokenGreaterThanOrEqual.php
+++ /dev/null
@@ -1,53 +0,0 @@
-<?php
-
-namespace NXP\Classes\Token;
-
-use NXP\Exception\IncorrectExpressionException;
-
-class TokenGreaterThanOrEqual extends AbstractOperator
-{
- /**
- * @return string
- */
- public static function getRegex()
- {
- return '>\=';
- }
-
- /**
- * @return int
- */
- public function getPriority()
- {
- return 150;
- }
-
- /**
- * @return string
- */
- public function getAssociation()
- {
- return self::LEFT_ASSOC;
- }
-
- /**
- * @param InterfaceToken[] $stack
- *
- * @return $this
- *
- * @throws \NXP\Exception\IncorrectExpressionException
- */
- public function execute(&$stack)
- {
- $op2 = array_pop($stack);
- $op1 = array_pop($stack);
-
- if ($op1 === null || $op2 === null) {
- throw new IncorrectExpressionException(">= requires two operators");
- }
-
- $result = $op1->getValue() >= $op2->getValue();
-
- return new TokenNumber($result);
- }
-}
diff --git a/src/NXP/Classes/Token/TokenLeftBracket.php b/src/NXP/Classes/Token/TokenLeftBracket.php
deleted file mode 100644
index 08165d8..0000000
--- a/src/NXP/Classes/Token/TokenLeftBracket.php
+++ /dev/null
@@ -1,25 +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\Token;
-
-/**
- * @author Alexander Kiryukhin <a.kiryukhin@mail.ru>
- */
-class TokenLeftBracket implements InterfaceToken
-{
- /**
- * @return string
- */
- public static function getRegex()
- {
- return '\(';
- }
-}
diff --git a/src/NXP/Classes/Token/TokenLessThan.php b/src/NXP/Classes/Token/TokenLessThan.php
deleted file mode 100644
index d289028..0000000
--- a/src/NXP/Classes/Token/TokenLessThan.php
+++ /dev/null
@@ -1,53 +0,0 @@
-<?php
-
-namespace NXP\Classes\Token;
-
-use NXP\Exception\IncorrectExpressionException;
-
-class TokenLessThan extends AbstractOperator
-{
- /**
- * @return string
- */
- public static function getRegex()
- {
- return '<';
- }
-
- /**
- * @return int
- */
- public function getPriority()
- {
- return 150;
- }
-
- /**
- * @return string
- */
- public function getAssociation()
- {
- return self::LEFT_ASSOC;
- }
-
- /**
- * @param InterfaceToken[] $stack
- *
- * @return $this
- *
- * @throws \NXP\Exception\IncorrectExpressionException
- */
- public function execute(&$stack)
- {
- $op2 = array_pop($stack);
- $op1 = array_pop($stack);
-
- if ($op1 === null || $op2 === null) {
- throw new IncorrectExpressionException("< requires two operators");
- }
-
- $result = $op1->getValue() < $op2->getValue();
-
- return new TokenNumber($result);
- }
-}
diff --git a/src/NXP/Classes/Token/TokenLessThanOrEqual.php b/src/NXP/Classes/Token/TokenLessThanOrEqual.php
deleted file mode 100644
index 5a2fba3..0000000
--- a/src/NXP/Classes/Token/TokenLessThanOrEqual.php
+++ /dev/null
@@ -1,53 +0,0 @@
-<?php
-
-namespace NXP\Classes\Token;
-
-use NXP\Exception\IncorrectExpressionException;
-
-class TokenLessThanOrEqual extends AbstractOperator
-{
- /**
- * @return string
- */
- public static function getRegex()
- {
- return '<\=';
- }
-
- /**
- * @return int
- */
- public function getPriority()
- {
- return 150;
- }
-
- /**
- * @return string
- */
- public function getAssociation()
- {
- return self::LEFT_ASSOC;
- }
-
- /**
- * @param InterfaceToken[] $stack
- *
- * @return $this
- *
- * @throws \NXP\Exception\IncorrectExpressionException
- */
- public function execute(&$stack)
- {
- $op2 = array_pop($stack);
- $op1 = array_pop($stack);
-
- if ($op1 === null || $op2 === null) {
- throw new IncorrectExpressionException("<= requires two operators");
- }
-
- $result = $op1->getValue() <= $op2->getValue();
-
- return new TokenNumber($result);
- }
-}
diff --git a/src/NXP/Classes/Token/TokenMinus.php b/src/NXP/Classes/Token/TokenMinus.php
deleted file mode 100644
index b4b04e3..0000000
--- a/src/NXP/Classes/Token/TokenMinus.php
+++ /dev/null
@@ -1,68 +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\Token;
-
-use NXP\Exception\IncorrectExpressionException;
-
-/**
-* @author Alexander Kiryukhin <a.kiryukhin@mail.ru>
-*/
-class TokenMinus extends AbstractOperator
-{
- /**
- * @return string
- */
- public static function getRegex()
- {
- return '\-';
- }
-
- /**
- * @return int
- */
- public function getPriority()
- {
- return 170;
- }
-
- /**
- * @return string
- */
- public function getAssociation()
- {
- return self::LEFT_ASSOC;
- }
-
- /**
- * @param InterfaceToken[] $stack
- *
- * @return $this
- *
- * @throws \NXP\Exception\IncorrectExpressionException
- */
- public function execute(&$stack)
- {
- $op2 = array_pop($stack);
- $op1 = array_pop($stack);
-
- if ($op2 === null) {
- throw new IncorrectExpressionException("Subtraction requires right operator");
- }
-
- if (!$op1) {
- $op1 = new TokenNumber(0);
- }
-
- $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
deleted file mode 100644
index 762fb48..0000000
--- a/src/NXP/Classes/Token/TokenMultiply.php
+++ /dev/null
@@ -1,64 +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\Token;
-
-use NXP\Exception\IncorrectExpressionException;
-
-/**
-* @author Alexander Kiryukhin <a.kiryukhin@mail.ru>
-*/
-class TokenMultiply extends AbstractOperator
-{
- /**
- * @return string
- */
- public static function getRegex()
- {
- return '\*';
- }
-
- /**
- * @return int
- */
- public function getPriority()
- {
- return 180;
- }
-
- /**
- * @return string
- */
- public function getAssociation()
- {
- return self::LEFT_ASSOC;
- }
-
- /**
- * @param InterfaceToken[] $stack
- *
- * @return $this
- *
- * @throws \NXP\Exception\IncorrectExpressionException
- */
- public function execute(&$stack)
- {
- $op2 = array_pop($stack);
- $op1 = array_pop($stack);
-
- if ($op1 === null || $op2 === null) {
- throw new IncorrectExpressionException("Multiplication requires two operators");
- }
-
- $result = $op1->getValue() * $op2->getValue();
-
- return new TokenNumber($result);
- }
-}
diff --git a/src/NXP/Classes/Token/TokenNotEqual.php b/src/NXP/Classes/Token/TokenNotEqual.php
deleted file mode 100644
index 21c9454..0000000
--- a/src/NXP/Classes/Token/TokenNotEqual.php
+++ /dev/null
@@ -1,53 +0,0 @@
-<?php
-
-namespace NXP\Classes\Token;
-
-use NXP\Exception\IncorrectExpressionException;
-
-class TokenNotEqual extends AbstractOperator
-{
- /**
- * @return string
- */
- public static function getRegex()
- {
- return '\!\=';
- }
-
- /**
- * @return int
- */
- public function getPriority()
- {
- return 140;
- }
-
- /**
- * @return string
- */
- public function getAssociation()
- {
- return self::LEFT_ASSOC;
- }
-
- /**
- * @param InterfaceToken[] $stack
- *
- * @return $this
- *
- * @throws \NXP\Exception\IncorrectExpressionException
- */
- public function execute(&$stack)
- {
- $op2 = array_pop($stack);
- $op1 = array_pop($stack);
-
- if ($op1 === null || $op2 === null) {
- throw new IncorrectExpressionException("!= requires two operators");
- }
-
- $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
deleted file mode 100644
index 982e316..0000000
--- a/src/NXP/Classes/Token/TokenNumber.php
+++ /dev/null
@@ -1,25 +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\Token;
-
-/**
- * @author Alexander Kiryukhin <a.kiryukhin@mail.ru>
- */
-class TokenNumber extends AbstractContainerToken
-{
- /**
- * @return string
- */
- public static function getRegex()
- {
- return '\-?\d+\.?\d*(E-?\d+)?';
- }
-}
diff --git a/src/NXP/Classes/Token/TokenOr.php b/src/NXP/Classes/Token/TokenOr.php
deleted file mode 100644
index 86a4e53..0000000
--- a/src/NXP/Classes/Token/TokenOr.php
+++ /dev/null
@@ -1,53 +0,0 @@
-<?php
-
-namespace NXP\Classes\Token;
-
-use NXP\Exception\IncorrectExpressionException;
-
-class TokenOr extends AbstractOperator
-{
- /**
- * @return string
- */
- public static function getRegex()
- {
- return '\|\|';
- }
-
- /**
- * @return int
- */
- public function getPriority()
- {
- return 90;
- }
-
- /**
- * @return string
- */
- public function getAssociation()
- {
- return self::LEFT_ASSOC;
- }
-
- /**
- * @param InterfaceToken[] $stack
- *
- * @return $this
- *
- * @throws \NXP\Exception\IncorrectExpressionException
- */
- public function execute(&$stack)
- {
- $op2 = array_pop($stack);
- $op1 = array_pop($stack);
-
- if ($op1 === null || $op2 === null) {
- throw new IncorrectExpressionException("|| requires two operators");
- }
-
- $result = $op1->getValue() || $op2->getValue();
-
- return new TokenNumber($result);
- }
-}
diff --git a/src/NXP/Classes/Token/TokenPlus.php b/src/NXP/Classes/Token/TokenPlus.php
deleted file mode 100644
index 494f786..0000000
--- a/src/NXP/Classes/Token/TokenPlus.php
+++ /dev/null
@@ -1,64 +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\Token;
-
-use NXP\Exception\IncorrectExpressionException;
-
-/**
-* @author Alexander Kiryukhin <a.kiryukhin@mail.ru>
-*/
-class TokenPlus extends AbstractOperator
-{
- /**
- * @return string
- */
- public static function getRegex()
- {
- return '\+';
- }
-
- /**
- * @return int
- */
- public function getPriority()
- {
- return 170;
- }
-
- /**
- * @return string
- */
- public function getAssociation()
- {
- return self::LEFT_ASSOC;
- }
-
- /**
- * @param InterfaceToken[] $stack
- *
- * @return $this
- *
- * @throws \NXP\Exception\IncorrectExpressionException
- */
- public function execute(&$stack)
- {
- $op2 = array_pop($stack);
- $op1 = array_pop($stack);
-
- if ($op1 === null || $op2 === null) {
- throw new IncorrectExpressionException("Addition requires two operators");
- }
-
- $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
deleted file mode 100644
index 306ae0b..0000000
--- a/src/NXP/Classes/Token/TokenRightBracket.php
+++ /dev/null
@@ -1,25 +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\Token;
-
-/**
- * @author Alexander Kiryukhin <a.kiryukhin@mail.ru>
- */
-class TokenRightBracket implements InterfaceToken
-{
- /**
- * @return string
- */
- public static function getRegex()
- {
- return '\)';
- }
-}
diff --git a/src/NXP/Classes/Token/TokenStringDoubleQuoted.php b/src/NXP/Classes/Token/TokenStringDoubleQuoted.php
deleted file mode 100644
index 6cff262..0000000
--- a/src/NXP/Classes/Token/TokenStringDoubleQuoted.php
+++ /dev/null
@@ -1,25 +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\Token;
-
-/**
- * @author Bruce Wells <brucekwells@gmail.com>
- */
-class TokenStringDoubleQuoted extends AbstractContainerToken
-{
- /**
- * @return string
- */
- public static function getRegex()
- {
- return '"([^"]|"")*"';
- }
-}
diff --git a/src/NXP/Classes/Token/TokenStringSingleQuoted.php b/src/NXP/Classes/Token/TokenStringSingleQuoted.php
deleted file mode 100644
index 7a7ab92..0000000
--- a/src/NXP/Classes/Token/TokenStringSingleQuoted.php
+++ /dev/null
@@ -1,26 +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\Token;
-
-/**
- * @author Bruce Wells <brucekwells@gmail.com>
- * @author Alexander Kiryukhin <a.kiryukhin@mail.ru>
- */
-class TokenStringSingleQuoted extends AbstractContainerToken
-{
- /**
- * @return string
- */
- public static function getRegex()
- {
- return "'([^']|'')*'";
- }
-}
diff --git a/src/NXP/Classes/Token/TokenVariable.php b/src/NXP/Classes/Token/TokenVariable.php
deleted file mode 100644
index a4a820a..0000000
--- a/src/NXP/Classes/Token/TokenVariable.php
+++ /dev/null
@@ -1,25 +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\Token;
-
-/**
- * @author Alexander Kiryukhin <a.kiryukhin@mail.ru>
- */
-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
deleted file mode 100644
index 70d1ba9..0000000
--- a/src/NXP/Classes/TokenFactory.php
+++ /dev/null
@@ -1,217 +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;
-
-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\Classes\Token\TokenStringSingleQuoted;
-use NXP\Classes\Token\TokenVariable;
-use NXP\Classes\Token\TokenStringDoubleQuoted;
-use NXP\Exception\UnknownFunctionException;
-use NXP\Exception\UnknownOperatorException;
-use NXP\Exception\UnknownTokenException;
-
-/**
- * @author Alexander Kiryukhin <a.kiryukhin@mail.ru>
- */
-class TokenFactory
-{
- /**
- * Available operators
- *
- * @var array
- */
- protected $operators = [];
-
- /**
- * Divide by zero reporting
- *
- * @var bool
- */
- protected $divideByZeroReporting = false;
-
- /**
- * Available functions
- *
- * @var array
- */
- protected $functions = [];
-
- /**
- * Add function
- * @param string $name
- * @param callable $function
- * @param int $places
- * @return TokenFactory
- * @throws \ReflectionException
- */
- public function addFunction($name, callable $function, $places = null)
- {
- if ($places === null) {
- $reflector = new \ReflectionFunction($function);
- $places = $reflector->getNumberOfParameters();
- }
- $this->functions[$name] = [$places, $function];
-
- return $this;
- }
-
- /**
- * get functions
- *
- * @return array containing callback and places indexed by
- * function name
- */
- public function getFunctions()
- {
- return $this->functions;
- }
-
- /**
- * Add operator
- * @param string $operatorClass
- * @return TokenFactory
- * @throws UnknownOperatorException
- * @throws \ReflectionException
- */
- public function addOperator($operatorClass)
- {
- $class = new \ReflectionClass($operatorClass);
-
- if (!in_array('NXP\Classes\Token\InterfaceToken', $class->getInterfaceNames())) {
- throw new UnknownOperatorException($operatorClass);
- }
-
- $this->operators[$operatorClass::getRegex()] = $operatorClass;
-
- return $this;
- }
-
- /**
- * Get registered operators
- *
- * @return array of operator class names
- */
- public function getOperators()
- {
- return $this->operators;
- }
-
- /**
- * Set division by zero exception reporting
- *
- * @param bool $exception default true
- *
- * @return TokenFactory
- */
- public function setDivisionByZeroException($exception = true)
- {
- $this->divideByZeroReporting = $exception;
-
- return $this;
- }
-
- /**
- * Get division by zero exception status
- *
- * @return bool
- */
- public function getDivisionByZeroException()
- {
- return $this->divideByZeroReporting;
- }
-
- /**
- * @return string
- */
- public function getTokenParserRegex()
- {
- $operatorsRegex = '';
- foreach ($this->operators as $operator) {
- $operatorsRegex .= '|(' . $operator::getRegex() . ')';
- }
- $s = sprintf(
- '/(%s)|(%s)|(%s)|(%s)|(%s)|([%s%s%s])',
- TokenNumber::getRegex(),
- TokenStringDoubleQuoted::getRegex(),
- TokenStringSingleQuoted::getRegex(),
- TokenFunction::getRegex(),
- TokenVariable::getRegex(),
- TokenLeftBracket::getRegex(),
- TokenRightBracket::getRegex(),
- TokenComma::getRegex()
- );
- $s .= $operatorsRegex . '/i';
-
- return $s;
- }
-
- /**
- * @param string $token
- * @return InterfaceToken
- * @throws UnknownTokenException
- * @throws UnknownFunctionException
- */
- public function createToken($token)
- {
- if (is_numeric($token)) {
- return new TokenNumber($token);
- }
-
- if ($token == '(') {
- return new TokenLeftBracket();
- }
-
- if ($token == ')') {
- return new TokenRightBracket();
- }
-
- if ($token[0] == '"') {
- return new TokenStringDoubleQuoted(str_replace('"', '', $token));
- }
-
- if ($token[0] == "'") {
- return new TokenStringSingleQuoted(str_replace("'", '', $token));
- }
-
- if ($token == ',') {
- return new TokenComma();
- }
-
- foreach ($this->operators as $operator) {
- $regex = sprintf('/%s/i', $operator::getRegex());
- if (preg_match($regex, $token)) {
- $op = new $operator;
- return $op->setDivisionByZeroException($this->getDivisionByZeroException());
- }
- }
-
- $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])) {
- return new TokenFunction($this->functions[$token]);
- } else {
- throw new UnknownFunctionException($token);
- }
- }
-
- throw new UnknownTokenException($token);
- }
-}
diff --git a/src/NXP/Classes/Tokenizer.php b/src/NXP/Classes/Tokenizer.php
new file mode 100644
index 0000000..869c720
--- /dev/null
+++ b/src/NXP/Classes/Tokenizer.php
@@ -0,0 +1,313 @@
+<?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\InterfaceToken;
+use NXP\Classes\Token\TokenComma;
+use NXP\Classes\Token\TokenFunction;
+use NXP\Classes\Token\TokenLeftBracket;
+use NXP\Classes\Token\TokenMinus;
+use NXP\Classes\Token\TokenNumber;
+use NXP\Classes\Token\TokenRightBracket;
+use NXP\Classes\Token\TokenStringDoubleQuoted;
+use NXP\Classes\Token\TokenStringSingleQuoted;
+use NXP\Classes\Token\TokenVariable;
+use NXP\Exception\IncorrectBracketsException;
+use NXP\Exception\UnknownOperatorException;
+use RuntimeException;
+use SplStack;
+
+/**
+ * @author Alexander Kiryukhin <a.kiryukhin@mail.ru>
+ */
+class Tokenizer
+{
+ /**
+ * @var Token[]
+ */
+ public $tokens = [];
+ /**
+ * @var string
+ */
+ private $input = "";
+ /**
+ * @var string
+ */
+ private $numberBuffer = "";
+ /**
+ * @var string
+ */
+ private $stringBuffer = "";
+ /**
+ * @var bool
+ */
+ private $allowNegative = true;
+ /**
+ * @var Operator[]
+ */
+ private $operators = [];
+
+ /**
+ * @var bool
+ */
+ private $inSingleQuotedString = false;
+
+ /**
+ * @var bool
+ */
+ private $inDoubleQuotedString = false;
+
+ /**
+ * Tokenizer constructor.
+ * @param string $input
+ * @param Operator[] $operators
+ */
+ public function __construct(string $input, array $operators)
+ {
+ $this->input = $input;
+ $this->operators = $operators;
+ }
+
+ public function tokenize()
+ {
+ foreach (mb_str_split($this->input, 1) as $ch) {
+ switch (true) {
+ case $this->inSingleQuotedString:
+ if ($ch === "'") {
+ $this->tokens[] = new Token(Token::String, $this->stringBuffer);
+ $this->inSingleQuotedString = false;
+ $this->stringBuffer = "";
+ continue 2;
+ }
+ $this->stringBuffer .= $ch;
+ continue 2;
+ case $this->inDoubleQuotedString:
+ if ($ch === "\"") {
+ $this->tokens[] = new Token(Token::String, $this->stringBuffer);
+ $this->inDoubleQuotedString = false;
+ $this->stringBuffer = "";
+ continue 2;
+ }
+ $this->stringBuffer .= $ch;
+ continue 2;
+ case $ch == " " || $ch == "\n" || $ch == "\r" || $ch == "\t":
+ $this->tokens[] = new Token(Token::Space, "");
+ continue 2;
+ case $this->isNumber($ch):
+ if ($this->stringBuffer != "") {
+ $this->stringBuffer .= $ch;
+ continue 2;
+ }
+ $this->numberBuffer .= $ch;
+ $this->allowNegative = false;
+ break;
+ case strtolower($ch) === "e":
+ if ($this->numberBuffer != "" && strpos($this->numberBuffer, ".") !== false) {
+ $this->numberBuffer .= "e";
+ $this->allowNegative = true;
+ break;
+ }
+ case $this->isAlpha($ch):
+ if ($this->numberBuffer != "") {
+ $this->emptyNumberBufferAsLiteral();
+ $this->tokens[] = new Token(Token::Operator, "*");
+ }
+ $this->allowNegative = false;
+ $this->stringBuffer .= $ch;
+ break;
+ case $ch == "\"":
+ $this->inDoubleQuotedString = true;
+ continue 2;
+ case $ch == "'":
+ $this->inSingleQuotedString = true;
+ continue 2;
+
+ case $this->isDot($ch):
+ $this->numberBuffer .= $ch;
+ $this->allowNegative = false;
+ break;
+ case $this->isLP($ch):
+ if ($this->stringBuffer != "") {
+ $this->tokens[] = new Token(Token::Function, $this->stringBuffer);
+ $this->stringBuffer = "";
+ } elseif ($this->numberBuffer != "") {
+ $this->emptyNumberBufferAsLiteral();
+ $this->tokens[] = new Token(Token::Operator, "*");
+ }
+ $this->allowNegative = true;
+ $this->tokens[] = new Token(Token::LeftParenthesis, "");
+ break;
+ case $this->isRP($ch):
+ $this->emptyNumberBufferAsLiteral();
+ $this->emptyStrBufferAsVariable();
+ $this->allowNegative = false;
+ $this->tokens[] = new Token(Token::RightParenthesis, "");
+ break;
+ case $this->isComma($ch):
+ $this->emptyNumberBufferAsLiteral();
+ $this->emptyStrBufferAsVariable();
+ $this->allowNegative = true;
+ $this->tokens[] = new Token(Token::ParamSeparator, "");
+ break;
+ default:
+ if ($this->allowNegative && $ch == "-") {
+ $this->allowNegative = false;
+ $this->numberBuffer .= "-";
+ continue 2;
+ }
+ $this->emptyNumberBufferAsLiteral();
+ $this->emptyStrBufferAsVariable();
+ if (count($this->tokens) > 0) {
+ if ($this->tokens[count($this->tokens) - 1]->type === Token::Operator) {
+ $this->tokens[count($this->tokens) - 1]->value .= $ch;
+ } else {
+ $this->tokens[] = new Token(Token::Operator, $ch);
+ }
+ } else {
+ $this->tokens[] = new Token(Token::Operator, $ch);
+ }
+ $this->allowNegative = true;
+ }
+ }
+ $this->emptyNumberBufferAsLiteral();
+ $this->emptyStrBufferAsVariable();
+ return $this;
+ }
+
+ private function isNumber($ch)
+ {
+ return $ch >= '0' && $ch <= '9';
+ }
+
+ private function isAlpha($ch)
+ {
+ return $ch >= 'a' && $ch <= 'z' || $ch >= 'A' && $ch <= 'Z' || $ch == '_';
+ }
+
+ private function emptyNumberBufferAsLiteral()
+ {
+ if ($this->numberBuffer != "") {
+ $this->tokens[] = new Token(Token::Literal, $this->numberBuffer);
+ $this->numberBuffer = "";
+ }
+ }
+
+ private function isDot($ch)
+ {
+ return $ch == '.';
+ }
+
+ private function isLP($ch)
+ {
+ return $ch == '(';
+ }
+
+ private function isRP($ch)
+ {
+ return $ch == ')';
+ }
+
+ private function emptyStrBufferAsVariable()
+ {
+ if ($this->stringBuffer != "") {
+ $this->tokens[] = new Token(Token::Variable, $this->stringBuffer);
+ $this->stringBuffer = "";
+ }
+ }
+
+ private function isComma($ch)
+ {
+ return $ch == ',';
+ }
+
+ /**
+ * @return Token[] Array of tokens in revers polish notation
+ * @throws IncorrectBracketsException
+ * @throws UnknownOperatorException
+ */
+ public function buildReversePolishNotation()
+ {
+ $tokens = [];
+ /** @var SplStack<Token> $stack */
+ $stack = new SplStack();
+ foreach ($this->tokens as $token) {
+ switch ($token->type) {
+ case Token::Literal:
+ case Token::Variable:
+ case Token::String:
+ $tokens[] = $token;
+ break;
+ case Token::Function:
+ case Token::LeftParenthesis:
+ $stack->push($token);
+ break;
+ case Token::ParamSeparator:
+ while ($stack->top()->type !== Token::LeftParenthesis) {
+ if ($stack->count() === 0) {
+ throw new IncorrectBracketsException();
+ }
+ $tokens[] = $stack->pop();
+ }
+ break;
+ case Token::Operator:
+ if (!array_key_exists($token->value, $this->operators)) {
+ throw new UnknownOperatorException();
+ }
+ $op1 = $this->operators[$token->value];
+ while ($stack->count() > 0 && $stack->top()->type === Token::Operator) {
+ if (!array_key_exists($stack->top()->value, $this->operators)) {
+ throw new UnknownOperatorException();
+ }
+ $op2 = $this->operators[$stack->top()->value];
+ if ($op2->priority >= $op1->priority) {
+ $tokens[] = $stack->pop();
+ continue;
+ }
+ break;
+ }
+ $stack->push($token);
+ break;
+ case Token::RightParenthesis:
+ while (true) {
+ try {
+ $ctoken = $stack->pop();
+ if ($ctoken->type === Token::LeftParenthesis) {
+ break;
+ }
+ $tokens[] = $ctoken;
+ } catch (RuntimeException $e) {
+ throw new IncorrectBracketsException();
+ }
+ }
+ if ($stack->count() > 0 && $stack->top()->type == Token::Function) {
+ $tokens[] = $stack->pop();
+ }
+ break;
+ case Token::Space:
+ //do nothing
+ }
+ }
+ while ($stack->count() !== 0) {
+ if ($stack->top()->type === Token::LeftParenthesis || $stack->top()->type === Token::RightParenthesis) {
+ throw new IncorrectBracketsException();
+ }
+ if ($stack->top()->type === Token::Space) {
+ $stack->pop();
+ continue;
+ }
+ $tokens[] = $stack->pop();
+ }
+ return $tokens;
+ }
+}
+