-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
+Add calc command using php-math-phraser by aboyadzhiev. +Add encrypt and decrypt command.
- Loading branch information
Showing
11 changed files
with
561 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
<?php | ||
|
||
namespace Math; | ||
|
||
/** | ||
* Tokenize mathematical expression. | ||
* | ||
* @author Adrean Boyadzhiev (netforce) <[email protected]> | ||
*/ | ||
class Lexer | ||
{ | ||
|
||
/** | ||
* Collection of Token instances | ||
* | ||
* @var array | ||
*/ | ||
protected $tokens; | ||
|
||
/** | ||
* The mathematical expression that should be tokenized | ||
* | ||
* @var string | ||
*/ | ||
protected $code; | ||
|
||
/** | ||
* Mathematical operators map | ||
* | ||
* @var array | ||
*/ | ||
protected static $operatorsMap = array( | ||
'+' => array('priority' => 0, 'associativity' => Operator::O_LEFT_ASSOCIATIVE), | ||
'-' => array('priority' => 0, 'associativity' => Operator::O_LEFT_ASSOCIATIVE), | ||
'*' => array('priority' => 1, 'associativity' => Operator::O_LEFT_ASSOCIATIVE), | ||
'/' => array('priority' => 1, 'associativity' => Operator::O_LEFT_ASSOCIATIVE), | ||
'%' => array('priority' => 1, 'associativity' => Operator::O_LEFT_ASSOCIATIVE), | ||
); | ||
|
||
public function __construct() | ||
{ | ||
$this->tokens = array(); | ||
} | ||
|
||
/** | ||
* Tokenize matematical expression. | ||
* | ||
* @param type $code | ||
* @return array Collection of Token instances | ||
* @throws \InvalidArgumentException | ||
*/ | ||
public function tokenize($code) | ||
{ | ||
$code = trim((string) $code); | ||
if (empty($code)) { | ||
throw new \InvalidArgumentException('Cannot tokenize empty string.'); | ||
} | ||
|
||
$this->code = $code; | ||
$this->tokens = array(); | ||
|
||
$tokenArray = explode(' ', $this->code); | ||
|
||
if (!is_array($tokenArray) || empty($tokenArray)) { | ||
throw new \InvalidArgumentException( | ||
sprintf('Cannot tokenize string: %s, please use " "(empty space for delimeter betwwen tokens)', $this->code) | ||
); | ||
} | ||
|
||
foreach ($tokenArray as $t) { | ||
if (array_key_exists($t, static::$operatorsMap)) { | ||
$token = new Operator( | ||
$t, | ||
static::$operatorsMap[$t]['priority'], | ||
static::$operatorsMap[$t]['associativity'] | ||
); | ||
} elseif (is_numeric($t)) { | ||
$token = new Token((float) $t, Token::T_OPERAND); | ||
}elseif('(' === $t) { | ||
$token = new Token($t, Token::T_LEFT_BRACKET); | ||
}elseif(')' === $t) { | ||
$token = new Token($t, Token::T_RIGHT_BRACKET); | ||
}elseif('' === $t) { | ||
continue; | ||
}else { | ||
throw new \InvalidArgumentException(sprintf('Syntax error: unknown token "%s"', $t)); | ||
} | ||
|
||
$this->tokens[] = $token; | ||
} | ||
|
||
return $this->tokens; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
<?php | ||
|
||
namespace Math; | ||
|
||
/** | ||
* Value object representing one operator of mathematical expression. | ||
* | ||
* @author Adrean Boyadzhiev (netforce) <[email protected]> | ||
*/ | ||
class Operator extends Token | ||
{ | ||
const O_LEFT_ASSOCIATIVE = -1; | ||
const O_NONE_ASSOCIATIVE = 0; | ||
const O_RIGHT_ASSOCIATIVE = 1; | ||
|
||
protected $priority; | ||
protected $associativity; | ||
|
||
/** | ||
* Create new "Value object" which represent one mathematical operator. | ||
* | ||
* @param string $value string representation of this operator | ||
* @param integer $priority priority value of this token | ||
* @param integer $associativity one of Operator associative constants | ||
* @throws \InvalidArgumentException | ||
*/ | ||
public function __construct($value, $priority, $associativity) | ||
{ | ||
if(!in_array($associativity, array(self::O_LEFT_ASSOCIATIVE, self::O_NONE_ASSOCIATIVE, self::O_RIGHT_ASSOCIATIVE))) { | ||
throw new \InvalidArgumentException(sprintf('Invalid associativity: %s', $associativity)); | ||
} | ||
|
||
$this->priority = (int) $priority; | ||
$this->associativity = (int) $associativity; | ||
parent::__construct($value, Token::T_OPERATOR); | ||
} | ||
|
||
/** | ||
* Return associativity of this operator. | ||
* | ||
* @return integer | ||
*/ | ||
public function getAssociativity() | ||
{ | ||
return $this->associativity; | ||
} | ||
|
||
/** | ||
* Return priority of this operator. | ||
* | ||
* @return integer | ||
*/ | ||
public function getPriority() | ||
{ | ||
return $this->priority; | ||
} | ||
|
||
/** | ||
* Return true if this operator has lower priority of operator $o. | ||
* | ||
* @param \Math\Operator $o | ||
* @return boolean | ||
*/ | ||
public function hasLowerPriority(Operator $o) | ||
{ | ||
$hasLowerPriority = ((Operator::O_LEFT_ASSOCIATIVE == $o->getAssociativity() | ||
&& $this->getPriority() == $o->getPriority()) | ||
|| $this->getPriority() < $o->getPriority()); | ||
|
||
|
||
return $hasLowerPriority; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
<?php | ||
|
||
namespace Math; | ||
|
||
/** | ||
* Evaluate mathematical expression. | ||
* | ||
* @author Adrean Boyadzhiev (netforce) <[email protected]> | ||
*/ | ||
class Parser | ||
{ | ||
/** | ||
* Lexer wich should tokenize the mathematical expression. | ||
* | ||
* @var Lexer | ||
*/ | ||
protected $lexer; | ||
|
||
/** | ||
* TranslationStrategy that should translate from infix | ||
* mathematical expression notation to reverse-polish | ||
* mathematical expression notation. | ||
* | ||
* @var TranslationStrategy\TranslationStrategyInterface | ||
*/ | ||
protected $translationStrategy; | ||
|
||
/** | ||
* Array of key => value options. | ||
* | ||
* @var array | ||
*/ | ||
private $options = array( | ||
'translationStrategy' => '\Math\TranslationStrategy\ShuntingYard', | ||
); | ||
|
||
/** | ||
* Create new Lexer wich can evaluate mathematical expression. | ||
* Accept array of configuration options, currently supports only | ||
* one option "translationStrategy" => "Fully\Qualified\Classname". | ||
* Class represent by this options is responsible for translation | ||
* from infix mathematical expression notation to reverse-polish | ||
* mathematical expression notation. | ||
* | ||
* <code> | ||
* $options = array( | ||
* 'translationStrategy' => '\Math\TranslationStrategy\ShuntingYard' | ||
* ); | ||
* </code> | ||
* | ||
* @param array $options | ||
*/ | ||
public function __construct(array $options = array()) | ||
{ | ||
$this->lexer = new Lexer(); | ||
$this->options = array_merge($this->options, $options); | ||
$this->translationStrategy = new $this->options['translationStrategy'](); | ||
} | ||
|
||
/** | ||
* Evaluate string representing mathematical expression. | ||
* | ||
* @param string $expression | ||
* @return float | ||
*/ | ||
public function evaluate($expression) | ||
{ | ||
$lexer = $this->getLexer(); | ||
$tokens = $lexer->tokenize($expression); | ||
|
||
$translationStrategy = new \Math\TranslationStrategy\ShuntingYard(); | ||
|
||
return $this->evaluateRPN($translationStrategy->translate($tokens)); | ||
} | ||
|
||
/** | ||
* Evaluate array sequence of tokens in Reverse Polish notation (RPN) | ||
* representing mathematical expression. | ||
* | ||
* @param array $expressionTokens | ||
* @return float | ||
* @throws \InvalidArgumentException | ||
*/ | ||
private function evaluateRPN(array $expressionTokens) | ||
{ | ||
$stack = new \SplStack(); | ||
|
||
foreach ($expressionTokens as $token) { | ||
$tokenValue = $token->getValue(); | ||
if (is_numeric($tokenValue)) { | ||
$stack->push((float) $tokenValue); | ||
continue; | ||
} | ||
|
||
switch ($tokenValue) { | ||
case '+': | ||
$stack->push($stack->pop() + $stack->pop()); | ||
break; | ||
case '-': | ||
$n = $stack->pop(); | ||
$stack->push($stack->pop() - $n); | ||
break; | ||
case '*': | ||
$stack->push($stack->pop() * $stack->pop()); | ||
break; | ||
case '/': | ||
$n = $stack->pop(); | ||
$stack->push($stack->pop() / $n); | ||
break; | ||
case '%': | ||
$n = $stack->pop(); | ||
$stack->push($stack->pop() % $n); | ||
break; | ||
default: | ||
throw new \InvalidArgumentException(sprintf('Invalid operator detected: %s', $tokenValue)); | ||
break; | ||
} | ||
} | ||
|
||
return $stack->top(); | ||
} | ||
|
||
/** | ||
* Return lexer. | ||
* | ||
* @return Lexer | ||
*/ | ||
public function getLexer() | ||
{ | ||
return $this->lexer; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
<?php | ||
|
||
namespace Math; | ||
|
||
/** | ||
* Value object representing one token of mathematical expression. | ||
* | ||
* @author Adrean Boyadzhiev (netforce) <[email protected]> | ||
*/ | ||
class Token | ||
{ | ||
|
||
const T_OPERATOR = 1; | ||
const T_OPERAND = 2; | ||
const T_LEFT_BRACKET = 3; | ||
const T_RIGHT_BRACKET = 4; | ||
|
||
/** | ||
* String representation of this token | ||
* | ||
* @var string | ||
*/ | ||
protected $value; | ||
|
||
/** | ||
* Token type one of Token::T_* constants | ||
* | ||
* @var integer | ||
*/ | ||
protected $type; | ||
|
||
/** | ||
* Create new "Value object" which represent one token | ||
* | ||
* @param integer|string $value | ||
* @param integer $type | ||
* @throws \InvalidArgumentException | ||
*/ | ||
public function __construct($value, $type) | ||
{ | ||
$tokeTypes = array( | ||
self::T_OPERATOR, | ||
self::T_OPERAND, | ||
self::T_LEFT_BRACKET, | ||
self::T_RIGHT_BRACKET | ||
); | ||
if (!in_array($type, $tokeTypes, true)) { | ||
throw new \InvalidArgumentException(sprintf('Invalid token type: %s', $type)); | ||
} | ||
|
||
$this->value = $value; | ||
$this->type = $type; | ||
} | ||
|
||
/** | ||
* Return token value | ||
* | ||
* @return string|integer | ||
*/ | ||
public function getValue() | ||
{ | ||
return $this->value; | ||
} | ||
|
||
/** | ||
* Return token type | ||
* | ||
* return integer | ||
*/ | ||
public function getType() | ||
{ | ||
return $this->type; | ||
} | ||
|
||
/** | ||
* Return string representation of this token. | ||
* | ||
* @return string | ||
*/ | ||
public function __toString() | ||
{ | ||
return (string) $this->getValue(); | ||
} | ||
|
||
} |
Oops, something went wrong.