Brainfuck.php 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. <?php
  2. namespace dotzero;
  3. /**
  4. * Class Brainfuck
  5. *
  6. * A PHP implementation of interpreter for Brainfuck.
  7. *
  8. * @package dotzero
  9. * @version 1.1
  10. * @author dotzero <mail@dotzero.ru>
  11. * @link http://www.dotzero.ru/
  12. * @link https://github.com/dotzero/brainfuck-php
  13. *
  14. * For the full copyright and license information, please view the LICENSE
  15. * file that was distributed with this source code.
  16. */
  17. class Brainfuck {
  18. /**
  19. * @var null|string Source code
  20. */
  21. private $code = null;
  22. /**
  23. * @var int Source code pointer
  24. */
  25. private $code_pointer = 0;
  26. /**
  27. * @var array Data cells
  28. */
  29. private $cells = array();
  30. /**
  31. * @var int Data cell pointer
  32. */
  33. private $pointer = 0;
  34. /**
  35. * @var null|string User input
  36. */
  37. private $input = null;
  38. /**
  39. * @var int User input pointer
  40. */
  41. private $input_pointer = 0;
  42. /**
  43. * @var array Buffer
  44. */
  45. private $buffer = array();
  46. /**
  47. * @var string Output
  48. */
  49. private $output = '';
  50. /**
  51. * @var boolean Wrap over/underflows?
  52. */
  53. private $wrap = true;
  54. /**
  55. * Brainfuck constructor.
  56. *
  57. * @param string $code Source code
  58. * @param null|string $input User input
  59. */
  60. public function __construct($code = '', $input = null, $wrap = null) {
  61. $this->setCode($code);
  62. $this->setInput($input);
  63. $this->setWrap($wrap);
  64. }
  65. /**
  66. * Sets code to execute
  67. *
  68. * @param string $code
  69. *
  70. * @return void
  71. */
  72. public function setCode($code = '') {
  73. $this->code = $code;
  74. //clearing object instance data during new code setting
  75. $this->code_pointer=0;
  76. $this->cells=array();
  77. $this->output='';
  78. }
  79. /**
  80. * Sets users input
  81. *
  82. * @param string $input
  83. *
  84. * @return void
  85. */
  86. public function setInput($input = null) {
  87. $this->input = ($input) ? $input : null;
  88. //clearing input data
  89. $this->input_pointer=0;
  90. }
  91. /**
  92. * Executes PHP code returned from run method
  93. *
  94. * @return void
  95. */
  96. public function execute() {
  97. if (!empty($this->code)) {
  98. $result = $this->run(true);
  99. if (!empty($result)) {
  100. eval($result);
  101. }
  102. }
  103. }
  104. /**
  105. * Sets instaince wrap property
  106. *
  107. * @param bool $wrap
  108. *
  109. * @return void
  110. */
  111. public function setWrap($wrap = null) {
  112. $this->wrap = (boolean) $wrap;
  113. }
  114. /**
  115. * Execute Brainfuck interpreter
  116. *
  117. * @param bool $return
  118. * @return string
  119. */
  120. public function run($return = false) {
  121. while ($this->code_pointer < strlen($this->code)) {
  122. $this->interpret($this->code[$this->code_pointer]);
  123. $this->code_pointer++;
  124. }
  125. if ($return) {
  126. return $this->output;
  127. } else {
  128. echo $this->output;
  129. }
  130. }
  131. /**
  132. * Command interpreter
  133. *
  134. * @param $command
  135. */
  136. private function interpret($command) {
  137. if (!isset($this->cells[$this->pointer])) {
  138. $this->cells[$this->pointer] = 0;
  139. }
  140. switch ($command) {
  141. case '>' :
  142. $this->pointer++;
  143. break;
  144. case '<' :
  145. $this->pointer--;
  146. break;
  147. case '+' :
  148. $this->cells[$this->pointer] ++;
  149. if ($this->wrap && $this->cells[$this->pointer] > 255) {
  150. $this->cells[$this->pointer] = 0;
  151. }
  152. break;
  153. case '-' :
  154. $this->cells[$this->pointer] --;
  155. if ($this->wrap && $this->cells[$this->pointer] < 0) {
  156. $this->cells[$this->pointer] = 255;
  157. }
  158. break;
  159. case '.' :
  160. $this->output .= chr($this->cells[$this->pointer]);
  161. break;
  162. case ',' :
  163. $this->cells[$this->pointer] = isset($this->input[$this->input_pointer]) ? ord($this->input[$this->input_pointer]) : 0;
  164. $this->input_pointer++;
  165. break;
  166. case '[' :
  167. if ($this->cells[$this->pointer] == 0) {
  168. $delta = 1;
  169. while ($delta AND $this->code_pointer++ < strlen($this->code)) {
  170. switch ($this->code[$this->code_pointer]) {
  171. case '[' :
  172. $delta++;
  173. break;
  174. case ']' :
  175. $delta--;
  176. break;
  177. }
  178. }
  179. } else {
  180. $this->buffer[] = $this->code_pointer;
  181. }
  182. break;
  183. case ']' :
  184. $this->code_pointer = array_pop($this->buffer) - 1;
  185. }
  186. }
  187. }