Location: PHPKode > scripts > PHP befunge class > php-befunge-class/befunge.class.php
<?php
/*************************************************\
*   PHP Befunge interpeter class.                 *
*               Befunge-93 completed 1/27/07      *
*                                                 *
*      Original work By Jeremy Sturdivant         *
*                                                 *
**Interpeter for the befunge programming language *
**Handles reading files, arrays                   *
**Will read unefunge programs correctly           *
**Befunge-98 support planned                      *
**Easy to use, just include the class, spawn,     *
* call init, call table_load, and loop cycle().   *
*                                                 \********\
*  This work released under the Creative Commons           *
*  Attribution-Share Alike 2.5 License                     *
*  http://creativecommons.org/licenses/by-sa/2.5/          *
*  You are free to modify this work as long as credit      *
*  is given and the derivative is licenced under the same  *
*  licence as this one.                                    *
*                                                          *
\**********************************************************/

// $stacks[0] is stack pointers, $stacks[0][0] is the stack stack pointer, for the stack stack
// befunge($char) should be called with one char (e.g. '<') to interpet
class php_befunge{
// Stacks go here...
	public $stacks;
// Vector is coordinates and a direction. basically the instruction pointer in 2d :D
// like so: array(x,y,v) with v (vector)
// b00 (0) = up, b11 (3) = down, b01 (1) = right, b10 (2) = left
// that way (3 ^ vector) turns around and goes the other way :D
// also (1 ^ vector) is like a / type mirror :D
// plus (2 ^ vector) is like a \ type mirror :D
	public $vector;
// The table is the playing field. its where the current code is :D
	public $table;
// Debug mode is currently on if > 0 :D
	public $debug;
// called at the beginning. sets everything to the norm :D
	function init(){
			$this->stacks[0][0] = 1;
			$this->stacks[0][1] = 0;
			$this->stacks[1][0] = 0;
			$this->vector = array(0,0,1);
			$this->debug = 0;
		}
// loads a file, or an array, into the table variable...
	function table_load($input,$type=1){ 
	// $type 0 loads a file by name, type 1 takes a 2-d array of 1 char strings, type 2 takes an array of single characters
		if($type==1){
			$this->table = $input;
		}elseif($type==2){
			$i = 0;
			foreach($input as $item){
				$this->table[$i++] = $item; 
			}
		}else{
			$this->table = file($input);
		}
	}
// Shift the stack stack by x, -1 to go down, 1 to go up.
	function shift_stack($howmuch){
			$this->stacks[0][0] = (($howmuch + $this->stacks[0][0]) >= 0)?$this->stacks[0][0]+$howmuch:0;
		}
// pop the current stack, and return it.
	function stack_pop(){
		   $stack_index = $this->stacks[0][0];
		   $stack_pointer = ($this->stacks[0][$stack_index] == 0) ? 0 : $this->stacks[0][$stack_index]--;
		   return (($stack_pointer > 0) ? $this->stacks[$stack_index][$stack_pointer-1] : 0);
		}
// push $val onto the current stack
	function stack_push($val){
			$stack_index = $this->stacks[0][0];
			$stack_pointer = $this->stacks[0][$stack_index]++;
			$this->stacks[$stack_index][$stack_pointer] = $val+0;
		}
// incriment the vector
	function move($invector){
			switch($invector % 2){
			case true:
				if($invector == 3){
					$this->vector[1]++;
				}elseif($invector == 1){
					$this->vector[0]++;
				}
				break;
			case false:
				if($invector == 2){
					$this->vector[0]--;
				}elseif($invector == 0){
					$this->vector[1]--;
				}
				break;
			}
		}
// handle stuff that always happens every automatic cycle.
// simply using while(1){$funge->cycle();} after table_load and init
// will suffice for running a table.
	function cycle(){
		$x = $this->vector[0];
		$y = $this->vector[1];
		$table = $this->table;
		$this->befunge($table[$y]{$x});
		$this->move($this->vector[2]);
		
	}
// The interpeter itself. requires stack_push/pop, $strmode, $vector, $table, 
// $debug and a few PHP functions/defines like STDIN and floor...
	function befunge($char){
			$char = $char{0};
			if($this->strmode == true && $char !== '"'){
				$this->stack_push(ord($char));
			}elseif($this->strmode != true || $char === '"'){
			switch($char){
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
	echo $this->debug > 0 ? 'Pushing '.$char : '';
	$this->stack_push($char-0);
	break;
case '@':
	die("\n".'Program end.'."\n");
	break;
case '<':
	$this->vector[2] = 2;
	break;
case '>':
	$this->vector[2] = 1;
	break;
case '^':
	$this->vector[2] = 0;
	break;
case 'v':
	$this->vector[2] = 3;
	break;
case '#':
	$this->move($this->vector[2]);
	break;
case '"':
	$this->strmode ? $this->strmode = false : $this->strmode = true;
	break;
case '.':
	echo $this->stack_pop()-0;
	break;
case ',':
	echo chr($this->stack_pop()-0);
	break;
case '$':
	$this->stack_pop();
	break;
case 'x':
	var_dump($this->stacks);
	break;
case '\\':
	$tmp1 = $this->stack_pop();
	$tmp2 = $this->stack_pop();
	$this->stack_push($tmp1);
	$this->stack_push($tmp2);
	break;
case ':':
	$tmp = $this->stack_pop();
	$this->stack_push($tmp);
	$this->stack_push($tmp);
	break;	
case '+':
	$this->stack_push($this->stack_pop()+$this->stack_pop());
	break;
case '-':
	$a = $this->stack_pop();
	$b = $this->stack_pop();
	$this->stack_push($b-$a);
	break;
case '/':
	$a = $this->stack_pop();
	$b = $this->stack_pop();
	if($a==0){
		echo 'Debug catch hit, attept to divide by zero. '."\n".'enter a number for the result:';
		$this->stack_push(fread(STDIN, 1024)+0);
	}else{
		echo $this->debug > 0 ? 'Dividing b/a a='.$a.' b='.$b."\n" : '';
		$this->stack_push(floor($b/$a));
	}
	break;
case '*':
	$this->stack_push($this->stack_pop()*$this->stack_pop());
	break;
case 'p':
	$y = $this->stack_pop();
	$x = $this->stack_pop();
	$v = $this->stack_pop();
	$this->table[$y]{$x} = chr($v);
	break;
case 'g':
	$y = $this->stack_pop();
	$x = $this->stack_pop();
	$this->stack_push(ord($this->table[$y]{$x}));
	break;
case '&':
	echo 'Please enter an integer (max 1024 chars):';
	$this->stack_push(fread(STDIN, 1024)+0);
	break;
case '~':
	echo 'Type a character and press return:';
	$this->stack_push(ord(fread(STDIN, 1024)));
	break;
case '?':
	$this->vector[2] = rand(0,3);
	break;
case '!':
	$this->stack_push(!$this->stack_pop());
	break;
case '_':
	if($this->stack_pop() == 0){
		$this->vector[2] = 1; //right (1)
	}else{
		$this->vector[2] = 2; //left  (2)
	}
	break;
case '|':
	if($this->stack_pop() == 0){
		$this->vector[2] = 3; //down (3)
	}else{
		$this->vector[2] = 0; //up   (0)
	}
	break;
case '`':
	$this->stack_push(($this->stack_pop()<$this->stack_pop())-0);
	break;
case '%':
	$a = $this->stack_pop();
	$b = $this->stack_pop();
	if($a==0){
		echo 'Debug catch hit, attept to modulus divide by zero. '."\n".'enter a number for the result:';
		$this->stack_push(fread(STDIN, 1024)+0);
	}else{
		echo $this->debug > 0 ? 'Modulus dividing b/a a='.$a.' b='.$b."\n" : '';
		$this->stack_push(floor($b%$a));
	}
	break;
			}
		}
		}
}
?>
Return current item: PHP befunge class