<?php
abstract class AbstractOperator{
const ASSOCIATIVE_LEFT = 0;
const ASSOCIATIVE_RIGHT = 1;
private $associative_map = array( self::ASSOCIATIVE_LEFT,
self::ASSOCIATIVE_RIGHT
);
protected $priority = null;
protected $token = null;
protected $operands_count = null;
protected $associative = null;
final public function __construct()
{
}
abstract protected function doExecute
(array $operands);
public function execute
(array $operands) {
if (count($operands) != $this->getOperandsCount()){ throw new Exception('Operands count must be equal ' . $this->getOperandsCount());
}
return $this->doExecute($operands);
}
public function getAssociative()
{
throw new Exception('Associative is empty');
}
if (!in_array($this->associative, $this->associative_map)){ throw new Exception('Invalid associative value');
}
return $this->associative;
}
public function getOperandsCount()
{
if (is_null($this->operands_count)){ throw new Exception('Operands count is empty');
}
return $this->operands_count;
}
public function comparePriority(AbstractOperator $operator){
throw new Exception('Priority is empty');
}
$num = $this->priority - $operator->priority;
return ($num > 0) ? 1 : (($num < 0) ? -1 : 0);
}
public function __toString()
{
throw new Exception('Token is empty');
}
return $this->token;
}
}
class PowOperator extends AbstractOperator{
protected $priority = 2;
protected $token = '^';
protected $operands_count = 2;
protected $associative = parent::ASSOCIATIVE_RIGHT;
protected function doExecute
(array $operands){ return pow($operands[0], $operands[1]); }
}
class AddOperator extends AbstractOperator{
protected $priority = 0;
protected $token = '+';
protected $operands_count = 2;
protected $associative = parent::ASSOCIATIVE_LEFT;
protected function doExecute
(array $operands){ return $operands[0] + $operands[1];
}
}
class SubOperator extends AbstractOperator{
protected $priority = 0;
protected $token = '-';
protected $operands_count = 2;
protected $associative = parent::ASSOCIATIVE_LEFT;
protected function doExecute
(array $operands){ return $operands[0] - $operands[1];
}
}
class MulOperator extends AbstractOperator{
protected $priority = 1;
protected $token = '*';
protected $operands_count = 2;
protected $associative = parent::ASSOCIATIVE_LEFT;
protected function doExecute
(array $operands){ return $operands[0] * $operands[1];
}
}
class DivOperator extends AbstractOperator{
protected $priority = 1;
protected $token = '/';
protected $operands_count = 2;
protected $associative = parent::ASSOCIATIVE_LEFT;
protected function doExecute
(array $operands){ if ($operands[1] == 0){
throw new Exception('Division by zero');
}
return $operands[0] / $operands[1];
}
}
abstract class OperatorFactory{
private static
$operators = array( '+' => 'add',
'-' => 'sub',
'*' => 'mul',
'/' => 'div',
'^' => 'pow'
);
public static function getTokens()
{
}
public static function getOperator($token)
{
return $token;
}
$class = ucfirst(self::$operators[$token]) . 'Operator'; throw new Exception('Operator class "' . $class . '" not found.');
}
$operator = new $class();
if (!($operator instanceof AbstractOperator)){
throw new Exception
('Operator class "' . $class . '" must be instance of AbstractOperator and instance of ' . get_class($operator) . ' given.'); }
return $operator;
}
}
class Infix2Postfix{
private $postfix = array(); private $stack = array();
public function process($infix){
$infix = (string) $infix;
$operators = OperatorFactory::getTokens();
$operators = array_map('preg_quote', $operators); $operators ='(' . implode(')|(', $operators) . ')'; $pattern = '#(\\d+(\.?\\d+|\\d*))|(\()|(\))|' . $operators . '#';
$tokens = array_map( array('OperatorFactory', 'getOperator'), $tokens[0]);
foreach ($tokens as $token){
$this->postfix[] = $token;
}
elseif ($token == '('){
}
elseif ($token == ')'){
$tmp = '';
while ($tmp <> '('){
if (count($this->stack) == 0){ throw new Exception('Parse error.');
}
if ($tmp != '('){
$this->postfix[] = $tmp;
}
}
}
elseif ($token instanceof AbstractOperator){
while ($this->stack[0] instanceof AbstractOperator){
if ($token->comparePriority($this->stack[0]) == 1 && $this->stack[0]->getAssociative() == AbstractOperator::ASSOCIATIVE_LEFT){
break;
}
if ($token->comparePriority($this->stack[0]) >= 0 && $this->stack[0]->getAssociative() == AbstractOperator::ASSOCIATIVE_RIGHT){
break;
}
}
}
}
foreach ($this->stack as $token){
if (!($token instanceof AbstractOperator)){
throw new Exception('Parse error.');
}
$this->postfix[] = $token;
}
return $this->postfix;
}
}
class ComputeInfix{
public function compute($str)
{
$parser = new Infix2Postfix();
$postfix = $parser->process($str);
foreach ($postfix as $token){
}
elseif ($token instanceof AbstractOperator){
for ($i = 1; $i <= $token->getOperandsCount(); $i++){
$params[] = 0;
}
else{
}
}
}
}
return $result;
}
}
$t = new ComputeInfix();
print_r($t->compute('5 * (-3 + 8)')); ?>