bephunge.phps 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. <?php
  2. /*
  3. Bephunge
  4. A Befunge-93 interpretter written in PHP
  5. by David Gucwa (6/9/2006)
  6. dgucwa@gmail.com
  7. 6/12/2006 - Commented out a line in the push function
  8. This code is in the public domain.
  9. Usage: php bephunge.php <befunge program>
  10. */
  11. define('UP', 1);
  12. define('DOWN', 2);
  13. define('LEFT', 3);
  14. define('RIGHT', 4);
  15. class Program
  16. {
  17. /* The class that holds the Befunge program */
  18. // The 80x25 array that holds the program instructions
  19. var $instructions;
  20. // The current position of the program and its direction
  21. var $cursor_x;
  22. var $cursor_y;
  23. var $cursor_dir;
  24. // The stack. An array of characters.
  25. var $stack;
  26. // The stack pointer. Gives the index of the most recently pushed value.
  27. var $stackPtr;
  28. // String mode. Turns on the first time a double-quote " is seen, and toggles thereafter.
  29. var $stringMode;
  30. function Program ()
  31. {
  32. // Initially set the entire program to blank spaces
  33. for ($i=0; $i<80; $i++)
  34. for ($j=0; $j<25; $j++)
  35. $this->instructions[$i][$j] = ' ';
  36. // Program starts in the upper left corner and heading right
  37. $this->cursor_x = 0;
  38. $this->cursor_y = 0;
  39. $this->cursor_dir = RIGHT;
  40. $this->stack = array();
  41. // -1 means there are no values in the stack
  42. $this->stackPtr = -1;
  43. $this->stringMode = false;
  44. }
  45. function loadFromFile ($filename)
  46. {
  47. $fileArray = file($filename);
  48. if (!$fileArray)
  49. die("Couldn't open $filename for reading.\n");
  50. $numLines = 0;
  51. foreach ($fileArray as $line)
  52. {
  53. $numLines++;
  54. if ($numLines > 25)
  55. break;
  56. $line = trim($line, "\n");
  57. for ($i=0; $i<strlen($line); $i++)
  58. {
  59. if ($i >= 80)
  60. break;
  61. $this->instructions[$i][$numLines-1] = substr($line, $i, 1);
  62. }
  63. }
  64. }
  65. function push ($value)
  66. {
  67. // The stack can hold signed long integers.
  68. //$value = $value % 256;
  69. $this->stackPtr++;
  70. $this->stack[$this->stackPtr] = $value;
  71. }
  72. function pop ()
  73. {
  74. if ($this->stackPtr == -1)
  75. return 0;
  76. else
  77. return $this->stack[$this->stackPtr--];
  78. }
  79. function step ()
  80. {
  81. // Moves the cursor one step in the direction it is facing
  82. switch ($this->cursor_dir)
  83. {
  84. case UP:
  85. $this->cursor_y--;
  86. if ($this->cursor_y < 0)
  87. $this->cursor_y = 24;
  88. break;
  89. case DOWN:
  90. $this->cursor_y++;
  91. if ($this->cursor_y >= 25)
  92. $this->cursor_y = 0;
  93. break;
  94. case LEFT:
  95. $this->cursor_x--;
  96. if ($this->cursor_x < 0)
  97. $this->cursor_x = 79;
  98. break;
  99. case RIGHT:
  100. $this->cursor_x++;
  101. if ($this->cursor_x >= 80)
  102. $this->cursor_x = 0;
  103. break;
  104. }
  105. }
  106. function execute ()
  107. {
  108. // Executes whichever instruction the cursor is on, and moves to the next instruction accordingly
  109. // Returns true normally
  110. // Returns false if the program is done
  111. $instruction = $this->instructions[$this->cursor_x][$this->cursor_y];
  112. if ($this->stringMode AND $instruction != '"')
  113. {
  114. $this->push(ord($instruction));
  115. $this->step();
  116. return true;
  117. }
  118. switch ($instruction)
  119. {
  120. case '<':
  121. $this->cursor_dir = LEFT;
  122. break;
  123. case '>':
  124. $this->cursor_dir = RIGHT;
  125. break;
  126. case 'v':
  127. $this->cursor_dir = DOWN;
  128. break;
  129. case '^':
  130. $this->cursor_dir = UP;
  131. break;
  132. case '0':
  133. case '1':
  134. case '2':
  135. case '3':
  136. case '4':
  137. case '5':
  138. case '6':
  139. case '7':
  140. case '8':
  141. case '9':
  142. $this->push($instruction - '0');
  143. break;
  144. case '+':
  145. $this->push($this->pop() + $this->pop());
  146. break;
  147. case '-':
  148. $a = $this->pop();
  149. $b = $this->pop();
  150. $this->push($b-$a);
  151. break;
  152. case '*':
  153. $this->push($this->pop() * $this->pop());
  154. break;
  155. case '/':
  156. $a = $this->pop();
  157. $b = $this->pop();
  158. if ($a == 0)
  159. $result = $this->ask('int');
  160. else
  161. $result = (int)($b/$a);
  162. $this->push($result);
  163. break;
  164. case '%':
  165. $a = $this->pop();
  166. $b = $this->pop();
  167. if ($a == 0)
  168. $result = $this->ask('int');
  169. else
  170. $result = $b % $a;
  171. $this->push($result);
  172. break;
  173. case '!':
  174. $a = $this->pop();
  175. $this->push($a == 0 ? 1 : 0);
  176. break;
  177. case '`':
  178. $a = $this->pop();
  179. $b = $this->pop();
  180. $this->push($b > $a ? 1 : 0);
  181. break;
  182. case '?':
  183. $this->cursor_dir = rand(1,4);
  184. break;
  185. case '_':
  186. if ($this->pop() == 0)
  187. $this->cursor_dir = RIGHT;
  188. else
  189. $this->cursor_dir = LEFT;
  190. break;
  191. case '|':
  192. if ($this->pop() == 0)
  193. $this->cursor_dir = DOWN;
  194. else
  195. $this->cursor_dir = UP;
  196. break;
  197. case '"':
  198. $this->stringMode = !$this->stringMode;
  199. break;
  200. case ':':
  201. $a = $this->pop();
  202. $this->push($a);
  203. $this->push($a);
  204. break;
  205. case '\\':
  206. $a = $this->pop();
  207. $b = $this->pop();
  208. $this->push($a);
  209. $this->push($b);
  210. break;
  211. case '$':
  212. $this->pop();
  213. break;
  214. case '.':
  215. print($this->pop());
  216. break;
  217. case ',':
  218. print(chr($this->pop()));
  219. break;
  220. case '#':
  221. $this->step();
  222. break;
  223. case 'p':
  224. $y = $this->pop();
  225. $x = $this->pop();
  226. $v = $this->pop();
  227. $this->instructions[$x][$y] = chr($v);
  228. break;
  229. case 'g':
  230. $y = $this->pop();
  231. $x = $this->pop();
  232. $this->push(ord($this->instructions[$x][$y]));
  233. break;
  234. case '&':
  235. $this->push($this->ask('int'));
  236. break;
  237. case '~':
  238. $this->push($this->ask('char'));
  239. break;
  240. case '@':
  241. return false;
  242. default:
  243. break;
  244. }
  245. $this->step();
  246. return true;
  247. }
  248. function ask ($type)
  249. {
  250. // Asks the user for input from the keyboard. $type can be 'int' or 'char'
  251. if ($type == 'int')
  252. return intval(fgets(STDIN));
  253. else if ($type == 'char')
  254. return ord(fgetc(STDIN));
  255. }
  256. }
  257. $Program = new Program();
  258. $Program->loadFromFile($argv[1]);
  259. while ($Program->execute());
  260. ?>