aboutsummaryrefslogtreecommitdiff
path: root/src/NXP/Classes
diff options
context:
space:
mode:
Diffstat (limited to 'src/NXP/Classes')
-rw-r--r--src/NXP/Classes/Calculator.php46
-rw-r--r--src/NXP/Classes/Func.php45
-rw-r--r--src/NXP/Classes/Lexer.php121
-rw-r--r--src/NXP/Classes/Operand.php89
-rw-r--r--src/NXP/Classes/Token.php56
-rw-r--r--src/NXP/Classes/Token/AbstractContainerToken.php46
-rw-r--r--src/NXP/Classes/Token/AbstractOperator.php20
-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/TokenComma.php25
-rw-r--r--src/NXP/Classes/Token/TokenDegree.php54
-rw-r--r--src/NXP/Classes/Token/TokenDivision.php54
-rw-r--r--src/NXP/Classes/Token/TokenFunction.php41
-rw-r--r--src/NXP/Classes/Token/TokenLeftBracket.php25
-rw-r--r--src/NXP/Classes/Token/TokenMinus.php54
-rw-r--r--src/NXP/Classes/Token/TokenMultiply.php54
-rw-r--r--src/NXP/Classes/Token/TokenNumber.php25
-rw-r--r--src/NXP/Classes/Token/TokenPlus.php54
-rw-r--r--src/NXP/Classes/Token/TokenRightBracket.php25
-rw-r--r--src/NXP/Classes/TokenFactory.php125
-rw-r--r--src/NXP/Classes/TokenParser.php165
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 = '';
- }
- }
-}