<?PHP
if (!class_exists('RuntimeException')) {
class RuntimeException extends Exception { }
}
class InvalidStateException extends RuntimeException { }
class Compiler {
private $ptr;
private $arr;
private $code;
private $commands = array('>', '<', '+', '-', '.', ',', '[', ']');
private $call_stack = array();
private $cellsize = 8;
public function parseString($code, $throwException = true) {
$this->code = $code;
for ($i=0;$i<strlen($this->code);$i++) {
$c = substr($this->code, $i, 1);
if (!in_array($c, $this->commands)) {
continue;
}
}
}
public function execute($code) {
$this->arr = array(0 => 0);
$this->ptr = 0;
$this->code = $code;
$jump = -1;
$loop = array();
$depth = 0;
for ($this->i=0;$this->i<strlen($this->code);$this->i++) {
$c = $this->c = substr($this->code, $this->i, 1);
$cell = $this->arr[$this->ptr];
if (!in_array($c, $this->commands)) {
continue;
}
else if ($jump >= 0) {
if ($c == '[') {
$depth++;
}
if ($c == ']') {
if ($depth === $jump) {
$jump = -1;
$this->stack();
}
$depth--;
}
}
else {
if ($c == '>') {
$this->increment_pointer();
}
elseif ($c == '<') {
$this->decrement_pointer();
}
elseif ($c == '+') {
$this->increment_val();
}
elseif ($c == '-') {
$this->decrement_val();
}
elseif ($c == '.') {
$this->output_val();
}
elseif ($c == ',') {
$this->store_val($this->input_val());
}
elseif ($c == '[') {
$depth++;
if ($cell == 0) {
$this->stack('jump');
$jump = $depth;
}
else {
array_push($loop, $this->i);
}
}
elseif ($c == ']') {
if ($cell > 0) {
$this->i = $loop[count($loop)-1];
continue;
}
else {
array_pop($loop);
$depth--;
continue;
}
}
}
}
}
private function stack($func=null) {
if (is_null($func)) {
if (count($this->call_stack) == 0) {
throw new InvalidStateException("Trying to pop empty call stack");
return false;
}
array_pop($this->call_stack);
return true;
}
else {
$info = array('command' => $this->c, 'pos' => $this->i, 'internal_function' => $func);
array_push($this->call_stack, $info);
return true;
}
}
public function minimum_cellsize() {
return (-1*(pow(2, $this->cellsize-1)));
}
public function maximum_cellsize() {
return pow(2, $this->cellsize-1)-1;
}
private function increment_pointer() {
$this->stack(__FUNCTION__);
$this->ptr++;
if (!isset($this->arr[$this->ptr])) $this->arr[$this->ptr] = 0;
$this->stack();
return true;
}
private function decrement_pointer() {
$this->stack(__FUNCTION__);
$this->ptr--;
if ($this->ptr < 0) {
throw new InvalidStateException("The data pointer is less than 0");
return false;
}
$this->stack();
return true;
}
private function increment_val() {
$x = $this->arr[$this->ptr]++;
if ($x < $this->minimum_cellsize()) {
$this->arr[$this->ptr] = $this->maximum_cellsize();
}
elseif ($x > $this->maximum_cellsize()) {
$this->arr[$this->ptr] = $this->minimum_cellsize();
}
return true;
}
private function decrement_val() {
$x = $this->arr[$this->ptr]--;
if ($x < $this->minimum_cellsize()) {
$this->arr[$this->ptr] = $this->maximum_cellsize();
}
elseif ($x > $this->maximum_cellsize()) {
$this->arr[$this->ptr] = $this->minimum_cellsize();
}
return true;
}
private function output_val() {
$c = $this->arr[$this->ptr];
echo ''.chr($c);
}
private function store_val($chr) {
$x = ord($chr);
$this->arr[$this->ptr] = $x;
}
private function input_val() {
return fgets(STDIN);
}
public function getCallStack() {
return $this->call_stack;
}
public function getCells() {
return $this->arr;
}
public function getPointer() {
return $this->ptr;
}
}
$c = new Compiler();
$bf = '
+++++++++++
>+>>>>++++++++++++++++++++++++++++++++++++++++++++
>++++++++++++++++++++++++++++++++<<<<<<[>[>>>>>>+>
+<<<<<<<-]>>>>>>>[<<<<<<<+>>>>>>>-]<[>++++++++++[-
<-[>>+>+<<<-]>>>[<<<+>>>-]+<[>[-]<[-]]>[<<[>>>+<<<
-]>>[-]]<<]>>>[>>+>+<<<-]>>>[<<<+>>>-]+<[>[-]<[-]]
>[<<+>>[-]]<<<<<<<]>>>>>[+++++++++++++++++++++++++
+++++++++++++++++++++++.[-]]++++++++++<[->-<]>++++
++++++++++++++++++++++++++++++++++++++++++++.[-]<<
<<<<<<<<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<-[>>.>.<<<
[-]]<<[>>+>+<<<-]>>>[<<<+>>>-]<<[<+>-]>[<+>-]<<<-]
';
try {
$c->execute($bf);
}
catch (Exception $e) {
echo PHP_EOL."An exception was thrown whilst processing your BF program.".PHP_EOL;
echo $e->getMessage().":".PHP_EOL;
}
echo "The pointer was set to ".$c->getPointer()." and the cell array resembled:".PHP_EOL;
echo "[".implode(", ", $c->getCells())."]".PHP_EOL;
echo "The current stack trace was:".PHP_EOL;
foreach ($c->getCallStack() as $k => $call) {
echo '#'.$k.' '.$call['command'].' ('.$call['internal_function'],') on pos '.$call['pos'].PHP_EOL;
}
echo PHP_EOL.'Finished.'.PHP_EOL;
?>
preferences:
45.68 ms | 402 KiB | 5 Q