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. class Calculator{
  10. private $token_type = 0;
  11. private $token = "";
  12. private $exp_ptr = 0;
  13.  
  14. public $parse_string = "";
  15.  
  16. function __construct($str){
  17. $this->parse_string = preg_replace("/\s+/", "", $str);
  18. $this->exp_ptr = 0;
  19.  
  20. $this->tok_type = ENDPARSE;
  21. $this->token = "";
  22. }
  23.  
  24. private function isoperator($tok){
  25. return preg_match_all("/[\+\-\*\/\^\=\(\)%]/u", $tok, $temp);
  26. }
  27.  
  28. private function isdigit($tok){
  29. return preg_match_all("/[\d\.]/u", $tok, $temp);
  30. }
  31.  
  32. public function get_token(){
  33. $tok = "";
  34. $this->token_type = UNDEFTOK;
  35. $this->token = "";
  36. if($this->parse_string == ""){
  37. $this->token_type = UNDEFTOK;
  38. $this->token = "";
  39. return;
  40. }
  41. if($this->exp_ptr == strlen($this->parse_string)){
  42. $this->token_type = ENDPARSE;
  43. $this->token = "";
  44. return;
  45. }
  46. $tok = substr($this->parse_string, $this->exp_ptr, 1);
  47. if($this->isoperator($tok)){
  48. $this->token_type = OPERATORTOK;
  49. $this->token = $tok;
  50. $this->exp_ptr++;
  51. }elseif($this->isdigit($tok)){
  52. $this->token_type = NUMBERTOK;
  53. while($this->isdigit($tok)){
  54. $this->token = $this->token.$tok;
  55. $this->exp_ptr++;
  56. $tok = substr($this->parse_string, $this->exp_ptr, 1);
  57. }
  58. }else{
  59. return;
  60. }
  61. }
  62.  
  63. public function compute(){
  64. $result = 0.0;
  65. $this->get_token();
  66. if($this->token == ""){
  67. echo "Выражение отсутствует";
  68. return 0.0;
  69. }
  70. $this->addOrSubtractMembers($result);
  71. return $result;
  72. }
  73.  
  74. // Сложить или вычесть два члена
  75. public function addOrSubtractMembers(&$result){
  76. $op = "";
  77. $temp = 0.0;
  78.  
  79. $this->multiplyOrDivide($result);
  80. $op = $this->token;
  81.  
  82. While ($op == "+" || $op == "-") {
  83. $this->get_token();
  84. $this->multiplyOrDivide($temp);
  85. switch ($op) {
  86. case "-":
  87. $result = $result - $temp;
  88. break;
  89. case "+":
  90. $result = $result + $temp;
  91. break;
  92. }
  93. $op = $this->token;
  94. }
  95. }
  96.  
  97. // Перемножить или поделить
  98. public function multiplyOrDivide(&$result){
  99. $op = "";
  100. $temp = 0.0;
  101.  
  102. $this->processingDegree($result);
  103. $op = $this->token;
  104. While ($op == "*" || $op == "/" || $op == "%") {
  105. $this->get_token();
  106. $this->processingDegree($temp);
  107. switch ($op) {
  108. case "*":
  109. $result = $result * $temp;
  110. break;
  111. case "/":
  112. if($temp == 0){
  113. echo "Делим на ноль";
  114. exit(-1);
  115. }
  116. $result = $result / $temp;
  117. break;
  118. case "%":
  119. $result = $result % $temp;
  120. break;
  121. }
  122. $op = $this->token;
  123. }
  124. return;
  125. }
  126.  
  127. // обработка степени
  128. public function processingDegree(&$result){
  129. $op = "";
  130. $temp = 0.0;
  131. $ex = 0.0;
  132.  
  133. $this->unaryOperation($result);
  134. if($this->token == "^"){
  135. $this->get_token();
  136. $this->processingDegree($temp);
  137. $ex = $result;
  138. if($temp == 0){
  139. $result = 0.0;
  140. return;
  141. }
  142. $result = pow($result, $temp);
  143. }
  144. return;
  145. }
  146.  
  147. // Унарный + или -
  148. public function unaryOperation(&$result){
  149. $op = "";
  150. if($this->token_type == OPERATORTOK && $this->token == "+" || $this->token == "-" ){
  151. $op = $this->token;
  152. $this->get_token();
  153. }
  154. $this->processingBrackets($result);
  155. if($op == "-"){
  156. $result = -1 * $result;
  157. }
  158. return;
  159. }
  160.  
  161. // Выражения в скобках
  162. public function processingBrackets(&$result){
  163. if($this->token == "("){
  164. $this->get_token();
  165. $this->addOrSubtractMembers($result);
  166. if($this->token != ")"){
  167. exit("Не хватает скобок");
  168. }
  169. $this->get_token();
  170. } else {
  171. $this->receiveValueNumber($result);
  172. }
  173. }
  174.  
  175. // Получить значение числа
  176. public function receiveValueNumber(&$result){
  177. switch ($this->token_type) {
  178. case NUMBERTOK:
  179. $result = (double)$this->token;
  180. $this->get_token();
  181. return;
  182. default:
  183. exit("Что-то пошло не так receiveValueNumber()\t\$this->token = {$this->token}\t\$this->token_type = {$this->token_type}");
  184. }
  185. }
  186. }
  187.  
  188. function test(&$tst){
  189. $tst++;
  190. }
  191.  
  192. $test = new Calculator("6+5/8+15*9/8*9/8*(55+6*5)");
  193. echo "{$test->parse_string} = ".$test->compute()."\n";
  194.  
  195. $test2 = new Calculator("6 + 5^2*8 + 6 / 89*8 - 9+3");
  196. echo "{$test2->parse_string} = ".$test2->compute()."\n";
  197.  
  198. $test3 = new Calculator("6.6 + 5.2^5.5555+6/8*9.9^55.66");
  199. echo "{$test3->parse_string} = ".$test3->compute()."\n";
  200.  
  201. $test4 = new Calculator("6.6 * (2+(6+(9/8)*6/(5+9)))");
  202. echo "{$test4->parse_string} = ".$test4->compute()."\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