Skip to content

Instantly share code, notes, and snippets.

@vvondra
Created February 17, 2011 14:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vvondra/831791 to your computer and use it in GitHub Desktop.
Save vvondra/831791 to your computer and use it in GitHub Desktop.
brainfuck interpreter
<?php
$b = new Brainfuck(file_get_contents('hello.b'));
$b->execute();
class BrainFuck {
private $code;
private $cells = array();
private $cell = 0;
private $loopCount = 0;
public function __construct($code) {
$code = $this->cleanCode($code);
if (!$this->testLoops($code)) {
echo $code;
throw new Exception('Incorrectly formatted code, loops don\'t fit');
}
$this->code = $code;
}
public function execute() {
for ($i = 0; $i < strlen($this->code); $i++) {
switch ($this->code[$i]) {
case '>':
$this->cell++;
break;
case '<':
$this->cell = max(0, $this->cell - 1);
break;
case '+':
$this->incrementCell($this->cells[$this->cell]);
break;
case '-':
$this->decrementCell($this->cells[$this->cell]);
break;
case '.':
echo chr($this->cells[$this->cell]);
break;
case ',':
$this->cells[$this->cell] = ord(fgetc(STDIN));
break;
case '[':
if (empty($this->cells[$this->cell])) {
$i = $this->getLoopEnd($i);
}
break;
case ']':
if (!empty($this->cells[$this->cell])) {
$i = $this->getLoopStart($i);
}
break;
}
}
echo "\nDone";
}
private function incrementCell(&$cell) {
if (isset($cell)) {
$cell = min($cell + 1, 255);
} else {
$cell = 1;
}
}
private function decrementCell(&$cell) {
if (isset($cell)) {
$cell = max($cell - 1, 0);
} else {
$cell = -1;
}
}
private function getLoopStart($pos) {
$counter = 1;
for ($i = $pos - 1; $i != 0; $i--) {
if ($this->code[$i] == ']') {
$counter++;
}
if ($this->code[$i] == '[') {
$counter--;
}
if ($counter == 0) {
return $i;
}
}
}
private function getLoopEnd($pos) {
$counter = 1;
for ($i = $pos + 1; $i < strlen($this->code); $i++) {
if ($this->code[$i] == ']') {
$counter--;
}
if ($this->code[$i] == '[') {
$counter++;
}
if ($counter == 0) {
return $i;
}
}
}
private function testLoops($code) {
$counter = 0;
for ($i = 0; $i < strlen($code); $i++) {
if ($code[$i] != '[' && $code[$i] != ']') {
continue;
} else if ($code[$i] == '[') {
$counter++;
} else {
$counter--;
}
if ($counter < 0) {
return false;
}
}
return $counter === 0;
}
private function cleanCode($code = '') {
return preg_replace('/[^\[\],\.><+-]/', '', $code);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment