czyli
Cytat
Czyli analizuję ciąg od początku, sprawdzam co mam a potem czego oczekuję następnie. Jeśli tak nie jest to błąd a jeśli jest to następny znak?
Bo jak narazie stworzyłem coś takiego:
<?php
/**
* @author ShInUeXx
* @copyright 2011
*/
class math_exp{
/**
*
* Typy operatorów
*
*/
const T_POW="^";
const T_MUL="*";
const T_DIV="/";
const T_ADD="+";
const T_MIN="-";
CONST T_LPAR="(";
CONST T_RPAR=")";
CONST T_FACT="!";
const I_NUM=0;
const I_OPR=1;
const I_FUN=2;
const I_VAR=3;
self::T_POW,
self::T_MUL,
self::T_DIV,
self::T_ADD,
self::T_MIN,
self::T_FACT,
);
private $_allowed_function=array( "abs",
"acos",
"acosh",
"asin",
"asinh",
"atan2",
"atan",
"atanh",
"ceil",
"cos",
"cosh",
"exp",
"floor",
"fmod",
"log10",
"ln",
"rand",
"round",
"sin",
"sinh",
"sqrt",
"tan",
"tanh",
);
private $_input;
private $_result=array(); private $_output;
public function __construct
($vars=array()){ $this->_vars=$vars;
}
public function addExp($str){
$this->_input=$str;
}
public function addVars($vars){
}
private function _priority($n){
switch($n){
case self::T_MIN:return 0;break;
case self::T_ADD:return 0;break;
case self::T_DIV:return 1;break;
case self::T_MUL:return 1;break;
case self::T_POW:return 2;break;
case self::T_FACT:return 3;break;
case null:return -1;break;
default:
break;
}
}
public function countExp($str=null){
if($str===null)$str=$this->_input;
$this->addExp($str);
if(!$this->_lexer()) return false;
$this->_reverse_polish_notation();
$this->_count();
return $this->_output;
}
public function _lexer(){
if(!preg_match_all("/([[:digit:]]+[e|E]{1}[\+\-]{0,1}[[:digit:]]+|[A-Za-z]{1}[A-Za-z0-9\_]*|[[:digit:]]+[\.]{0,1}[[:digit:]]*|[\.]{1}[[:digit:]]+|[\!\(\)\+\-\^\/\*\[\]]{1})/",$this->_input
,$m)) return false;
$this->_token=$m[0];
return true;
}
public function _identify($token){
return self::I_NUM;
return self::I_OPR;
elseif(in_array($token,$this->_allowed_function
)) return self::I_FUN;
else
return self::I_VAR;
}
public function _reverse_polish_notation(){
$return=&$this->_result;
$token=$this->_token;
foreach($token as $k=>$v){
$pr=$this->_priority($v);
if($v==self::T_LPAR){
$stack[]=$v;
$sel=1;
}
elseif($v==self::T_RPAR){
while($par!=self::T_LPAR){
$return[]=$par;
}
}
elseif($this->_identify($v)==self::I_NUM||$this->_identify($v)==self::I_VAR){
$return[]=$v;
}
elseif($this->_identify($v)==self::I_OPR||$this->_identify($v)==self::I_FUN){
$T=$this->_priority($last);
if($pr>$T){
if($last!==null) {
$stack[]=$last;
};
$stack[]=$v;
}
elseif($last==self::T_LPAR){
if($v=='-'&&($k==0||$token[$k-1]==self::T_LPAR))$return[]="0";
$stack[]=$last;
$stack[]=$v;
}
else{
if($last!==null&&$last!=self::T_LPAR) $return[]=$last;
$stack[]=$v;
}
}
}
}
public function _count(){
$vars=$this->_vars;
$rpn=$this->_result;
foreach($rpn as $v){
switch($this->_identify($v)){
case 0:
$stack[]=$v;
break;
case 1:
switch($v){
case "*":
$stack[]=$a*$b;
break;
case "^":
$stack[]=pow($a,$b);
break;
case "/":
$stack[]=$a/$b;
break;
case "+":
$stack[]=$a+$b;
break;
case "-":
$a=0;
if($this->_identify
(end($stack))==0
) $stack[]=$a-$b;
break;
case "!":
$stack[]=factorial($a);
break;
default:
break;
}
break;
case 2:
$stack[]=call_user_func($v,$a);
break;
case 3:
$stack[]=$vars[$v];
break;
}
}
}
}
?>
i na większości wyrażeń działa (oczywiście jeszcze błędów nie obsługuje)