<?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;
for ($this->i=0;$this->i<strlen($this->code);$this->i++) {
$c = $this->c = substr($this->code, $this->i, 1);
if (!in_array($c, $this->commands)) {
continue;
}
elseif ($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 == '[') {
$this->loop($this->i);
}
}
}
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 output_val() {
$c = $this->arr[$this->ptr];
echo 'hey'.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 {
echo "{ ";
$c->execute($bf);
echo " }";
}
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;
$i = 0;
foreach ($c->getCallStack() as $call) {
echo '#'.$i.' '.$call['command'].' ('.$call['internal_function'],') on pos '.$call['pos'].PHP_EOL;
}
echo PHP_EOL.'Finished.'.PHP_EOL;
?>
preferences:
42.93 ms | 402 KiB | 5 Q