<?php
/*******************************************************************************
* PHPVM - Version 0.01
*
* Author:   John Hobbs

* Created:  9/21/06
* Modified: 9/21/06
*
* More information is available at:
* http://static.velvetcache.org/projects/phpvm/
*
* This work is licensed under Creative Commons Attribution-ShareAlike 2.5
* http://creativecommons.org/licenses/by-sa/2.5/

*
* This is a basic virtual machine written in PHP that accepts a set of
* instructions modeled loosely in the style of assembly, then executes them.
*
* The VM currently has a 512 space integer "RAM" and accepts the following
* instructions:
*
* ADD(targetAddress,sourceAddress);
*   - Add target's value and source's value, place result in target.
*
* NOP();
*   - No Operation, skip a loop.
*
* SET(targetAddress,value);
*   - Set target to implicit value
*
* STP();
*   - End program.
*
* PRT(targetAddress);
*   - Print the integer found in the target.
*
* ASC(targetAddress);
*   - Print the ASCII character represented by the int at target.
*
* BNZ(targetAddress,sourceAddress);
*   - This will move the pointer to the souceAddress's value's instruction
*     if the value at targetAddress is not zero.
*
* Example Program, instructions are numbered for clarity
*
* 0 - SET(0,10)
* 1 - SET(1,-1)
* 2 - SET(2,4)
* 3 - SET(3,10)
* 4 - PRT(0,0)
* 5 - ASC(3,0)
* 6 - ADD(0,1)
* 7 - BNZ(0,2)
* 8 - STP(0,0)
*
* This should print 10 to 1 to the output, then quit.
* Note the use of 10 to print a newline character (\n) at
* RAM[3].
*******************************************************************************/

// Set our maximum execution time, good for breaking infinite loops.
set_time_limit (10);

// Load up our "Console"
echo "<pre class=\"phpvm\">";
echo 
"PHP VM - Version 0.01\n";
echo 
"Loading Instructions\n";

// Currently this is the only way to load instructions.
// This is the example program from the introduction.
$INS = array(
            array(
"SET",0,10),
            array(
"SET",1,-1),
            array(
"SET",2,4),
            array(
"SET",3,10),
            array(
"PRT",0,0),
            array(
"ASC",3,0),
            array(
"ADD",0,1),
            array(
"BNZ",0,2),
            array(
"STP",0,0)
            );

echo 
"Padding RAM\n";            
$RAM = array();
$RAM array_pad($RAM5120);

echo 
"Setting Environment\n";      
$exitCode = -1;
$eip 0;

echo 
"Executing\n\n";
// Start the timer.
$timeparts explode(' ',microtime());
$starttime $timeparts[1].substr($timeparts[0],1);

while(
$exitCode == -1)
{
  
$target $INS["$eip"][1];
  
$source $INS["$eip"][2];
  
  switch (
$INS["$eip"][0])
  {
    case 
"SET":
    {
      
$RAM["$target"] = $source;
      break;
    }
    
    case 
"ADD":
    {
      
$RAM["$target"] = $RAM["$target"] + $RAM["$source"];
      break;
    }
    
    case 
"PRT":
    {
      echo 
$RAM["$target"];
      break;
    } 
    
    case 
"ASC":
    {
      echo 
chr($RAM["$target"]);
      break;
    }  
    
    case 
"BNZ":
    {
      if(
$RAM["$target"] != 0)
      {
        
$eip = ($RAM["$source"] - 1); 
      }
      break;
    }
    
    case 
"STP":
    {
      
$exitCode 0;
      break;
    }
    
    case 
"NOP":
    {
      break;
    }
    
  }
  
$eip++;
}
// End timer, display.
$timeparts explode(' ',microtime());
$endtime $timeparts[1].substr($timeparts[0],1);
echo 
"\nFinished - Running Time: ".round($endtime $starttime8)." Seconds</pre>";
?>