diff options
author | Alexander Kiryukhin <frei@neonxp.info> | 2013-08-03 15:15:02 +0400 |
---|---|---|
committer | Alexander Kiryukhin <frei@neonxp.info> | 2013-08-03 15:15:02 +0400 |
commit | f172123a0dccdca7651c7ad552175924a16b9458 (patch) | |
tree | e093d7928420255e986acb44d4ab34634f601c52 /src/NXP/Classes/TokenParser.php | |
parent | 253fb694a3fcafa3f9ea6da6681f0b176cdec1f4 (diff) | |
parent | eb9c3651614dd5e5aef067880092e9f622c264df (diff) |
Merge pull request #3 from ZhukV/master
Fix to PSR standart, fix tokenizer, fix function executor.
Diffstat (limited to 'src/NXP/Classes/TokenParser.php')
-rw-r--r-- | src/NXP/Classes/TokenParser.php | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/src/NXP/Classes/TokenParser.php b/src/NXP/Classes/TokenParser.php new file mode 100644 index 0000000..f498184 --- /dev/null +++ b/src/NXP/Classes/TokenParser.php @@ -0,0 +1,165 @@ +<?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 = ''; + } + } +} |