/brainfuck.php

https://github.com/nbartels/php-brainfuck · PHP · 136 lines · 69 code · 17 blank · 50 comment · 16 complexity · 2feb458e9d917dae1140e023d37269bb MD5 · raw file

  1. <?php
  2. /*
  3. Brainfuck interpreter Class
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  15. */
  16. class Brainfuck {
  17. protected $data = array();
  18. protected $data_index = 0;
  19. protected $source_index = 0;
  20. protected $input_index = 0;
  21. protected $output = '';
  22. protected $input = null;
  23. protected $source = null;
  24. function __construct() {
  25. $this->data[0] = chr(0);
  26. }
  27. public function setSource($source) {
  28. $this->source = $source;
  29. }
  30. public function setInput($input) {
  31. $this->input = $input;
  32. }
  33. public function getOutput() {
  34. return $this->output;
  35. }
  36. public function execute() {
  37. $this->brainfuck_interpret($this->source, $this->source_index, $this->data, $this->data_index, $this->input, $this->input_index, $this->output);
  38. return $this;
  39. }
  40. /* Debug function displays valuable debug information.
  41. Rewrite this if desired.
  42. $s, $_s Source string and pointer (current position)
  43. $d, $_d Data array and pointer
  44. $i, $_i Input string and pointer
  45. $o Output string
  46. */
  47. protected function brainfuck_debug(&$s, &$_s, &$d, &$_d, &$i, &$_i, &$o) {
  48. foreach ($d as $element => $value) {
  49. echo $element . "\t" . ord($value) . "\t" . (ord($value) >= 32 ? htmlentities($value) : "&nbsp;") . "\n";
  50. }
  51. }
  52. /*
  53. Brainfuck interpreter in PHP
  54. Copyright (C) 2002 Daniel Lorch
  55. */
  56. protected function brainfuck_interpret(&$s, &$_s, &$d, &$_d, &$i, &$_i, &$o) {
  57. do {
  58. switch ($s[$_s]) {
  59. /* Execute brainfuck commands. Values are not stored as numbers, but as their
  60. representing characters in the ASCII table. This is perfect, as chr(256) is
  61. automagically converted to chr(0). */
  62. case '+': $d[$_d] = chr(ord($d[$_d]) + 1);
  63. break;
  64. case '-': $d[$_d] = chr(ord($d[$_d]) - 1);
  65. break;
  66. case '>': $_d++;
  67. if (!isset($d[$_d]))
  68. $d[$_d] = chr(0); break;
  69. case '<': $_d--;
  70. break;
  71. /* Output is stored in a variable. Change this to
  72. echo $d[$_d]; flush();
  73. if you would like to have a "live" output (when running long calculations, for example.
  74. Or if you are just terribly impatient). */
  75. case '.': $o .= $d[$_d];
  76. break;
  77. /* Due to PHP's non-interactive nature I have the whole input passed over in a string.
  78. I successively read characters from this string and pass it over to BF every time a
  79. ',' command is executed. */
  80. case ',': $d[$_d] = $_i == strlen($i) ? chr(0) : $i[$_i++];
  81. break;
  82. /* Catch loops */
  83. case '[':
  84. /* Skip loop (also nested ones) */
  85. if ((int) ord($d[$_d]) == 0) {
  86. $brackets = 1;
  87. while ($brackets && $_s++ < strlen($s)) {
  88. if ($s[$_s] == '[')
  89. $brackets++;
  90. else if ($s[$_s] == ']')
  91. $brackets--;
  92. }
  93. }
  94. /* Execute loop */
  95. else {
  96. $pos = $_s++ - 1;
  97. /* The closing ] returns true when the loop has to be executed again. If so, then return
  98. to the $pos(ition) where the opening [ is. */
  99. if ($this->brainfuck_interpret($s, $_s, $d, $_d, $i, $_i, $o))
  100. $_s = $pos;
  101. }
  102. break;
  103. /* Return true when loop has to be executed again. It is redundant to the [ checking, but
  104. it will save some parsing time (otherwise the interpreter would have to return to [ only
  105. to skip all characters again) */
  106. case ']': return ((int) ord($d[$_d]) != 0);
  107. /* Call debug function */
  108. case '#': $this->brainfuck_debug($s, $_s, $d, $_d, $i, $_i, $o);
  109. }
  110. } while (++$_s < strlen($s));
  111. }
  112. }
  113. ?>