fork download
  1. <?php
  2. // Staring straight up into the sky ... oh my my
  3.  
  4. define( 'UNDEFTOK', '0' );
  5. define( 'NUMBERTOK', '1' );
  6. define( 'OPERATORTOK', '2' );
  7. define( 'ENDPARSE', '3' );
  8.  
  9. $token_type = UNDEFTOK;
  10. $token = "";
  11. $exp_ptr = 0;
  12.  
  13. function returnPpiopitet($op){
  14. switch ($op) {
  15. case "(":
  16. return 0;
  17. case ")":
  18. return 1;
  19. case "+":
  20. case "-":
  21. return 2;
  22. case "*":
  23. case "/":
  24. return 3;
  25. case "^":
  26. return 4;
  27. default:
  28. return -1;
  29. }
  30. }
  31.  
  32. function isoperator($tok){
  33. return preg_match_all("/[\+\-\*\/\^\(\)]/u", $tok, $temp);
  34. }
  35.  
  36. function isdigit($tok){
  37. return preg_match_all("/[\d\.]/u", $tok, $temp);
  38. }
  39.  
  40. function getToken($op){
  41. global $exp_ptr;
  42. global $token, $token_type;
  43.  
  44. $tok = "";
  45. $token_type = UNDEFTOK;
  46. $token = "";
  47. if($op == ""){
  48. $token_type = UNDEFTOK;
  49. $token = "";
  50. return;
  51. }
  52. if($exp_ptr == strlen($op)){
  53. $token_type = ENDPARSE;
  54. $token = "";
  55. return;
  56. }
  57. $tok = substr($op, $exp_ptr, 1);
  58. if(isoperator($tok)){
  59. $token_type = OPERATORTOK;
  60. $token = $tok;
  61. $exp_ptr++;
  62. }elseif(isdigit($tok)){
  63. $token_type = NUMBERTOK;
  64. while(isdigit($tok)){
  65. $token = $token.$tok;
  66. $exp_ptr++;
  67. $tok = substr($op, $exp_ptr, 1);
  68. }
  69. }else{
  70. return;
  71. }
  72. }
  73.  
  74. function convertReversePolishNotation(&$stringExpression){
  75. global $token, $token_type, $exp_ptr;
  76.  
  77. $token_type = UNDEFTOK;
  78. $token = "";
  79. $exp_ptr = 0;
  80.  
  81. $stack = new SplStack();
  82. $conversionResults = array();
  83. $stringExpression = preg_replace("/\s+/", "", $stringExpression);
  84. // Изъёбство для обхода унарного минуса -а заменяется на 0-а
  85. // -(а+в) на (0-1)*(а+в)
  86. $stringExpression = preg_replace("/(^-[\d\.]{1,})/u", "(0$1)", $stringExpression);
  87. $stringExpression = preg_replace("/([\/\*\-\+\^\(])(\-[\d\.]{1,})/u", "$1(0$2)", $stringExpression);
  88. $stringExpression = preg_replace("/([\/\*\-\+\^])(\-)\(/u", "$1(0\${2}1)*(", $stringExpression);
  89.  
  90. if(preg_match_all("/(\()/u", $stringExpression, $match) != preg_match_all("/(\))/u", $stringExpression, $match)){
  91. exit("Несовпадение скобок");
  92. }elseif(preg_match_all("/[\+\-\*\/\^]{2,}/u", $stringExpression, $match) && !preg_match_all("/[\+\*\/\^]-/u", $stringExpression, $match)){
  93. exit("Несколько операторов подряд");
  94. }elseif(preg_match_all("/[^\+\-\*\/\^\(\)\d\.]/u", $stringExpression, $match)){
  95. exit("Неизвестные символы");
  96. }elseif(preg_match_all("/\d\(|\)\d|\)\(/u", $stringExpression, $match)){
  97. exit("Пропущен оператор");
  98. }
  99.  
  100. while($token_type != ENDPARSE){
  101. getToken($stringExpression);
  102. if($token_type == OPERATORTOK && $token == ")"){
  103. while(($op = $stack->pop()) != "("){
  104. array_push($conversionResults, $op);
  105. }
  106. }
  107. if($token_type == NUMBERTOK) {
  108. array_push($conversionResults, $token);
  109. }
  110. if($token_type == OPERATORTOK && $token == "("){
  111. $stack->push($token);
  112. }
  113. if($token_type == OPERATORTOK && ($token == "+" || $token == "-" || $token == "*" || $token == "/" || $token == "^")){
  114. if($stack->count() == 0){
  115. $stack->push($token);
  116. } else {
  117. if(returnPpiopitet($token) > returnPpiopitet($stack->top())){
  118. $stack->push($token);
  119. } else {
  120. while($stack->count() !=0 && returnPpiopitet($stack->top()) >= returnPpiopitet($token)){
  121. array_push($conversionResults, $stack->pop());
  122. }
  123. $stack->push($token);
  124. }
  125. }
  126. }
  127.  
  128. }
  129. while($stack->count() !=0){
  130. array_push($conversionResults, $stack->pop());
  131. }
  132. return $conversionResults;
  133. }
  134.  
  135. function compute(&$stringExpression){
  136. $conversionResults = convertReversePolishNotation($stringExpression);
  137. $stack = new SplStack();
  138.  
  139. while(count($conversionResults) !=0){
  140. $op = array_shift($conversionResults);
  141. if(returnPpiopitet($op)>=0){
  142. switch($op){
  143. case "+":
  144. $op1 = $stack->pop();
  145. $op2 = $stack->pop();
  146. $stack->push((double)$op2 + (double)$op1);
  147. break;
  148. case "-":
  149. $op1 = $stack->pop();
  150. $op2 = $stack->pop();
  151. $stack->push((double)$op2 - (double)$op1);
  152. break;
  153. case "*":
  154. $op1 = $stack->pop();
  155. $op2 = $stack->pop();
  156. $stack->push((double)$op2 * (double)$op1);
  157. break;
  158. case "/":
  159. $op1 = $stack->pop();
  160. $op2 = $stack->pop();
  161. if($op2 == 0){
  162. exit("Делим на ноль");
  163. }
  164. $stack->push((double)$op2 / (double)$op1);
  165. break;
  166. case "^":
  167. $op1 = $stack->pop();
  168. $op2 = $stack->pop();
  169. $stack->push(pow((double)$op2, (double)$op1));
  170. break;
  171. }
  172. }else{
  173. $stack->push($op);
  174. }
  175. }
  176. return $stack->pop();
  177. }
  178.  
  179. $str = "6+5/8+15*9/8*9/8*(55+6*5)";
  180. $rez = compute($str);
  181. echo $str." = ".$rez."\n";
  182.  
  183. $str = "6 + 5^2*8 + 6 / 89*8 - 9+3";
  184. $rez = compute($str);
  185. echo $str." = ".$rez."\n";
  186.  
  187. $str = "6.6 + 5.2^5.5555+6/8*9.9^55.66";
  188. $rez = compute($str);
  189. echo $str." = ".$rez."\n";
  190.  
  191. $str = "6.6 * (2+(6+(9/8)*6/(5+9)))";
  192. $rez = compute($str);
  193. echo $str." = ".$rez."\n";
  194.  
  195. $str = "5 * (-3 + 8)";
  196. $rez = compute($str);
  197. echo $str." = ".$rez."\n";
  198.  
  199. $str = "-5+-6*-(-5+-9)/-8+6*8*(-9--6)/-8^-6";
  200. echo $str;
  201. $rez = compute($str);
  202. echo " = ".$rez."\n";
  203.  
  204. ?>
Success #stdin #stdout 0.02s 52432KB
stdin
Standard input is empty
stdout
6+5/8+15*9/8*9/8*(55+6*5) = 1620.296875
6+5^2*8+6/89*8-9+3 = 200.5393258427
6.6+5.2^5.5555+6/8*9.9^55.66 = 1.9593688289175E+55
6.6*(2+(6+(9/8)*6/(5+9))) = 55.982142857143
5*((0-3)+8) = 25
-5+-6*-(-5+-9)/-8+6*8*(-9--6)/-8^-6 = -37748730.5