diff options
Diffstat (limited to 'NXP/Classes')
-rw-r--r-- | NXP/Classes/Func.php | 41 | ||||
-rw-r--r-- | NXP/Classes/Operand.php | 85 | ||||
-rw-r--r-- | NXP/Classes/Token.php | 53 | ||||
-rw-r--r-- | NXP/Classes/TokenParser.php | 159 |
4 files changed, 338 insertions, 0 deletions
diff --git a/NXP/Classes/Func.php b/NXP/Classes/Func.php new file mode 100644 index 0000000..b3e5b93 --- /dev/null +++ b/NXP/Classes/Func.php @@ -0,0 +1,41 @@ +<?php +/** + * Author: Alexander "NeonXP" Kiryukhin + * Date: 17.03.13 + * Time: 4:30 + */ + +namespace NXP\Classes; + + +class Func { + /** + * @var string + */ + private $name; + + /** + * @var callable + */ + private $callback; + + /** + * @param $name + * @param $callback + */ + function __construct($name, $callback) + { + $this->name = $name; + $this->callback = $callback; + } + + public function getName() + { + return $this->name; + } + + public function getCallback() + { + return $this->callback; + } +}
\ No newline at end of file diff --git a/NXP/Classes/Operand.php b/NXP/Classes/Operand.php new file mode 100644 index 0000000..3329679 --- /dev/null +++ b/NXP/Classes/Operand.php @@ -0,0 +1,85 @@ +<?php +/** + * Author: Alexander "NeonXP" Kiryukhin + * Date: 17.03.13 + * Time: 4:27 + */ + +namespace NXP\Classes; + + +class Operand { + const LEFT_ASSOCIATED = 'LEFT_ASSOCIATED'; + const RIGHT_ASSOCIATED = 'RIGHT_ASSOCIATED'; + const ASSOCIATED = 'ASSOCIATED'; + + const UNARY = 'UNARY'; + const BINARY = 'BINARY'; + + /** + * @var string + */ + private $symbol; + + /** + * @var int + */ + private $priority; + + /** + * @var string + */ + private $association; + + /** + * @var string + */ + private $type; + + /** + * @var callable + */ + private $callback; + + /** + * @param $symbol + * @param $priority + * @param $association + * @param $type + * @param $callback + */ + function __construct($symbol, $priority, $association, $type, $callback) + { + $this->association = $association; + $this->symbol = $symbol; + $this->type = $type; + $this->priority = $priority; + $this->callback = $callback; + } + + public function getAssociation() + { + return $this->association; + } + + public function getSymbol() + { + return $this->symbol; + } + + public function getType() + { + return $this->type; + } + + public function getCallback() + { + return $this->callback; + } + + public function getPriority() + { + return $this->priority; + } + +}
\ No newline at end of file diff --git a/NXP/Classes/Token.php b/NXP/Classes/Token.php new file mode 100644 index 0000000..28bc736 --- /dev/null +++ b/NXP/Classes/Token.php @@ -0,0 +1,53 @@ +<?php +/** + * Author: Alexander "NeonXP" Kiryukhin + * Date: 17.03.13 + * Time: 3:23 + */ + +namespace NXP\Classes; + + +class Token { + + const NOTHING = 'NOTHING'; + const STRING = 'STRING'; + const NUMBER = 'NUMBER'; + const OPERATOR = 'OPERATOR'; + const LEFT_BRACKET = 'LEFT_BRACKET'; + const RIGHT_BRACKET = 'RIGHT_BRACKET'; + const FUNC = 'FUNC'; + + /** + * @var string + */ + protected $value; + + /** + * @var string + */ + protected $type; + + function __construct($type, $value) + { + $this->type = $type; + $this->value = $value; + } + + /** + * @return string + */ + public function getType() + { + return $this->type; + } + + /** + * @return string + */ + public function getValue() + { + return $this->value; + } + +}
\ No newline at end of file diff --git a/NXP/Classes/TokenParser.php b/NXP/Classes/TokenParser.php new file mode 100644 index 0000000..7b9255f --- /dev/null +++ b/NXP/Classes/TokenParser.php @@ -0,0 +1,159 @@ +<?php +/** + * Author: Alexander "NeonXP" Kiryukhin + * Date: 17.03.13 + * Time: 2:45 + */ + +namespace NXP\Classes; + + +class TokenParser { + const DIGIT = 'DIGIT'; + const CHAR = 'CHAR'; + const SPECIAL_CHAR = 'SPECIAL_CHAR'; + const LEFT_BRACKET = 'LEFT_BRACKET'; + const RIGHT_BRACKET = 'RIGHT_BRACKET'; + const SPACE = 'SPACE'; + + private $terms = [ + self::DIGIT => '[0-9\.]', + self::CHAR => '[a-z]', + self::SPECIAL_CHAR => '[\!\@\#\$\%\^\&\*\/\|\-\+\=\~]', + self::LEFT_BRACKET => '\(', + self::RIGHT_BRACKET => '\)', + self::SPACE => '\s' + ]; + + const ERROR_STATE = 'ERROR_STATE'; + + private $transitions = [ + Token::NOTHING => [ + self::DIGIT => Token::NUMBER, + self::CHAR => Token::STRING, + self::SPECIAL_CHAR => Token::OPERATOR, + self::LEFT_BRACKET => Token::LEFT_BRACKET, + self::RIGHT_BRACKET => Token::RIGHT_BRACKET, + self::SPACE => Token::NOTHING + ], + Token::STRING => [ + self::DIGIT => Token::STRING, + self::CHAR => Token::STRING, + self::SPECIAL_CHAR => Token::OPERATOR, + self::LEFT_BRACKET => Token::LEFT_BRACKET, + self::RIGHT_BRACKET => Token::RIGHT_BRACKET, + self::SPACE => Token::NOTHING + ], + Token::NUMBER => [ + self::DIGIT => Token::NUMBER, + self::CHAR => self::ERROR_STATE, + self::SPECIAL_CHAR => Token::OPERATOR, + self::LEFT_BRACKET => Token::LEFT_BRACKET, + self::RIGHT_BRACKET => Token::RIGHT_BRACKET, + self::SPACE => Token::NOTHING + ], + Token::OPERATOR => [ + self::DIGIT => Token::NUMBER, + self::CHAR => Token::STRING, + self::SPECIAL_CHAR => Token::OPERATOR, + self::LEFT_BRACKET => Token::LEFT_BRACKET, + self::RIGHT_BRACKET => Token::RIGHT_BRACKET, + self::SPACE => Token::NOTHING + ], + self::ERROR_STATE => [ + self::DIGIT => self::ERROR_STATE, + self::CHAR => self::ERROR_STATE, + self::SPECIAL_CHAR => self::ERROR_STATE, + self::LEFT_BRACKET => self::ERROR_STATE, + self::RIGHT_BRACKET => self::ERROR_STATE, + self::SPACE => self::ERROR_STATE + ], + Token::LEFT_BRACKET => [ + self::DIGIT => Token::NUMBER, + self::CHAR => Token::STRING, + self::SPECIAL_CHAR => Token::OPERATOR, + self::LEFT_BRACKET => Token::LEFT_BRACKET, + self::RIGHT_BRACKET => Token::RIGHT_BRACKET, + self::SPACE => Token::NOTHING + ], + Token::RIGHT_BRACKET => [ + self::DIGIT => Token::NUMBER, + self::CHAR => Token::STRING, + self::SPECIAL_CHAR => Token::OPERATOR, + self::LEFT_BRACKET => Token::LEFT_BRACKET, + self::RIGHT_BRACKET => Token::RIGHT_BRACKET, + self::SPACE => Token::NOTHING + ], + ]; + + private $accumulator = ''; + + private $state = Token::NOTHING; + + private $queue = null; + + function __construct() + { + $this->queue = new \SplQueue(); + } + + /** + * Tokenize math expression + * @param $expression + * @return \SplQueue + * @throws \Exception + */ + public function tokenize($expression) + { + $oldState = null; + for ($i=0; $i<strlen($expression); $i++) { + $char = substr($expression, $i, 1); + $class = $this->getSymbolType($char); + $oldState = $this->state; + $this->state = $this->transitions[$this->state][$class]; + if ($this->state == self::ERROR_STATE) { + throw new \Exception("Parse expression error at $i column (symbol '$char')"); + } + $this->addToQueue($oldState); + $this->accumulator .= $char; + } + if (!empty($this->accumulator)) { + $token = new Token($this->state, $this->accumulator); + $this->queue->push($token); + } + + return $this->queue; + } + + /** + * @param $symbol + * @return string + * @throws \Exception + */ + private function getSymbolType($symbol) + { + foreach ($this->terms as $class => $regex) { + if (preg_match("/$regex/i", $symbol)) { + return $class; + } + } + + throw new \Exception("Unknown char '$symbol'"); + } + + /** + * @param $oldState + */ + private function addToQueue($oldState) + { + if ($oldState == Token::NOTHING) { + $this->accumulator = ''; + return; + } + if (($this->state != $oldState) || ($oldState == Token::LEFT_BRACKET) || ($oldState == Token::RIGHT_BRACKET)) { + $token = new Token($oldState, $this->accumulator); + $this->queue->push($token); + $this->accumulator = ''; + } + } +}
\ No newline at end of file |