Guest User

SuperHack Virtual Machine PHP Source

a guest
Apr 11th, 2013
186
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 7.64 KB | None | 0 0
  1. <?php
  2. class SHVM {
  3.   public $MAX_CYCLES = 10000;
  4.   private $movin = array(array(1, 0), array(0, -1), array(-1, 0), array(0, 1));
  5.   //  public $MEM_HEIGHT = 8;
  6.   public $MEM_HEIGHT = 128;
  7.   public $MEM_WIDTH = 1024;
  8.   public $MAX_THREADS = 32;
  9.   private $timeToQuit = false;
  10.  
  11.   public $Memory = array();
  12.   public $Threads = array();
  13.   public $Code = array();
  14.   public $user_input = array();
  15.   public $trace = false;
  16.   private $t = NULL;
  17.   public $cycle_count = 0;
  18.              
  19.   private function InitStuff() {
  20.     $this->timeToQuit = false;
  21.     $this->Code = array();
  22.     $this->Memory = array();
  23.     for ($i = 0; $i < $this->MEM_HEIGHT; $i++) {
  24.       $this->Memory[$i] = array_fill(0, $this->MEM_WIDTH, 0);
  25.      }
  26.     $this->Threads = array();
  27.     $this->t = array();
  28.     $this->t['pcX'] = 0; $this->t['pcY'] = 0;
  29.     $this->t['mX'] = -1; $this->t['mY'] = 0;
  30.     $this->t['dir'] = 0;
  31.     $this->t['cs'] = array();
  32.     $this->Threads[0] = $this->t;
  33.   }
  34.  
  35.   private function Push($v) {
  36.     if ($v > 2147483647 || $v < -2147483648) throw new Exception("integer overflow: '$v'");
  37.     $this->t['mX'] += 1;
  38.     $this->Memory[$this->t['mY']][$this->t['mX']] = $v;
  39.   }
  40.  
  41.     private function Pop() {
  42.       if ($this->t['mX'] < 0) throw new Exception("stack underflow");
  43.       $v = $this->Memory[$this->t['mY']][$this->t['mX']];
  44.       $this->t['mX'] -= 1;
  45.       return $v;
  46.     }
  47.  
  48.    private function MoveOneStep() {
  49.      $this->t['pcX'] += $this->movin[$this->t['dir']][0];
  50.      $this->t['pcY'] += $this->movin[$this->t['dir']][1];
  51.    }
  52.  
  53.   function Run($code, $mem_init, $traceIt = false) {
  54.     $this->InitStuff();
  55.  
  56.     $output = "";
  57.     $message = "";
  58.     $result = 0;
  59.    
  60.     $lines = preg_split('/[\n\r]+/', $code);
  61.      //  print_r($lines);
  62.     for ($y = 0; $y < count($lines); $y++) {
  63.         $this->Code[$y] = array();
  64.       for ($x = 0; $x < strlen($lines[$y]); $x++) {
  65.           $c = $lines[$y][$x];
  66.           $this->Code[$y][$x] = $c;
  67.           if ($c == '%') {
  68.              $this->Threads[0]['pcX'] = $x;
  69.              $this->Threads[0]['pcY'] = $y;
  70.           }
  71.       }
  72.     }
  73.  
  74.     // initialize the memory
  75.     $mem_init_cells = explode(",", $mem_init);
  76.     for ($i=0; $i<count($mem_init_cells); $i++) {
  77.       $this->user_input[$i] = (int)trim($mem_init_cells[$i]);
  78.     }
  79.      $this->user_input = array_reverse($this->user_input);
  80.    
  81.     // run loop
  82.     try {
  83.       while (!$this->timeToQuit) {
  84.         // check that we don't exceed the max
  85.         if ($this->cycle_count++ > $this->MAX_CYCLES) throw new Exception('too many cycles: ' . $this->cycle_count);
  86.           for ($tindex = 0; $tindex < count($this->Threads); $tindex++) {
  87.              $this->t =& $this->Threads[$tindex];
  88.              // some convenience vars
  89.              $t =& $this->t;
  90.              $pcX =& $t['pcX']; $pcY =& $t['pcY'];
  91.              $mX =& $t['mX']; $mY =& $t['mY'];
  92.              $mem =& $this->Memory;
  93.              $dir =& $t['dir'];
  94.              //          print_r($this->t);
  95.              if ($pcY < 0 || $pcX < 0) throw new Exception('out of code bounds');
  96.              
  97.              if (!isset($this->Code[$pcY])) {
  98.                 $s = 'undefined code vert: ' . $mX.",xxxxxx". $pcX;
  99.                 throw new Exception($s);
  100.              }
  101.              if (!isset($this->Code[$pcY][$pcX])) throw new Exception('undefined code: ' . $pcY.",". $pcX);
  102.              $instruction = $this->Code[$t['pcY']][$pcX];
  103.              $ox = $pcX; $oy = $pcY;
  104.  
  105.              if ($traceIt) echo "[Thread $tindex] <b>$instruction</b> @$ox,$oy [".implode(',', array_slice($this->Memory[$mY], 0, $mX + 1) )."]\n<br>";
  106.              //          if ($traceIt) echo "[Thread $tindex] <b>$instruction</b> @$ox,$oy [".implode(',', array_splice(0, $this->Memory[$this->t['mY']], $mX + 1))."]\n<br>";
  107.  
  108.              // instruction dispatch
  109.              switch ($instruction) {
  110.              case ' ': break;
  111.              case '0': $this->Push(0); break;
  112.              case '1': $this->Push(1); break;
  113.              case '2': $this->Push(2); break;
  114.              case '3': $this->Push(3); break;
  115.              case '4': $this->Push(4); break;
  116.              case '5': $this->Push(5); break;
  117.              case '6': $this->Push(6); break;
  118.              case '7': $this->Push(7); break;
  119.              case '8': $this->Push(8); break;
  120.              case '9': $this->Push(9); break;
  121.              case '+': $this->Push($this->Pop()+$this->Pop()); break;
  122.  
  123.              case '-': $a = $this->Pop(); $b = $this->Pop(); $this->Push($b-$a); break;
  124.              case '*': $this->Push($this->Pop()*$this->Pop()); break;
  125.              case 'd': $a = $this->Pop(); $b = $this->Pop(); $this->Push(floor($b/$a)); break;
  126.              case '\\': $dir = ($dir ^ 3); break;
  127.              case '/': $dir = ($dir ^ 1); break;
  128.              case 'p': $output .= $this->Pop(); break;
  129.              case 'P': $output .= chr($this->Pop()&0x7F); break;
  130.              case ':': $a = $this->Pop(); $b = $this->Pop(); if ($b<$a) $dir = ($dir + 1) % 4; else if ($b > $a) $dir = ($dir + 3) % 4; break;
  131.                 //  case ':': $a = $this->Pop(); $b = $this->Pop(); $this->Push( ($b<$a)?-1:(($b==$a)?0:1)); break;
  132.              case ',': if (count($this->user_input) > 0) $this->Push(array_pop($this->user_input)); else $this->Push(0); break;
  133.              case 's': $this->MoveOneStep(); break;
  134.              case '?': $a = $this->Pop(); if ($a == 0) $this->MoveOneStep(); break;
  135.              case '@':
  136.                 array_push($this->t['cs'], array($pcX, $pcY, $dir));
  137.                 break;
  138.              case '$':
  139.                 if (count($this->t['cs']) == 0) throw new Exception("call stack underflow");
  140.                 $c = array_pop($this->t['cs']);
  141.                 $pcX = $c[0]; $pcY = $c[1]; $dir = $c[2];
  142.                 $this->MoveOneStep();
  143.                 break;
  144.              case '<':
  145.                 $x = $this->Pop(); $y = $this->Pop();
  146.                 if ($x < 0 || $y < 0) throw new Exception('memory read access violation @'.$x.",".$y);
  147.                 if ($y >= count($this->Memory))
  148.                   $this->Push(0);
  149.                 else {
  150.                   $this->Push($this->Memory[$y][$x]);
  151.                 }
  152.                 break;
  153.              case '>':
  154.                 $x = $this->Pop(); $y = $this->Pop();
  155.                 if ($x < 0 || $y < 0) throw new Exception('memory read access violation @'.$x.",".$y);
  156.                 $val = $this->Pop();
  157.                 $this->Memory[$y][$x] = $val;
  158.                 //    print_r($mem);
  159.                 break;
  160.              case '[': $i = $this->Pop(); $mX -= $i; break;
  161.              case ']': $i = $this->Pop(); $mX += $i; break;
  162.              case '{': $mY--; if ($mY < 0) throw new Exception("mem cannot go neg"); break;
  163.              case '}': $mY++; if ($mY == $this->MEM_HEIGHT) throw new Exception("mem too big"); break;
  164.              case 'x': $a = $this->Pop(); $this->Push($a); $this->Push($a); break;
  165.              case '^': $a = $this->Pop();
  166.                 if ($a < 0 || $mX < $a) throw new Exception("out of mem bounds: $a, $mX");
  167.                 $this->Push($this->Memory[$mY][$mX - $a]); break;
  168.              case 'v':
  169.                 $a = $this->Pop();
  170.                 if ($a < 0 || $mX < $a) throw new Exception("out of mem bounds: $a, $mX");
  171.                 $v = array_splice($this->Memory[$mY], $mX - $a, 1);
  172.                 array_splice($this->Memory[$mY], $mX, 0, $v[0]); // insert value at mem
  173.                 break;
  174.              case 'g':
  175.                 $x = $this->Pop(); $y = $this->Pop();
  176.                 $v = ord($this->Code[$y][$x]);
  177.                 $this->Push($v);
  178.                 break;
  179.              case 'w':
  180.                 $x = $this->Pop(); $y = $this->Pop(); $c = $this->Pop();
  181.                 $this->Code[$y][$x] = chr($c & 0x7f);
  182.                 break;
  183.              case '&':
  184.                 if (count($this->Threads) == $this->MAX_THREADS) throw new Exception("max threads exceeded: " . $this->MAX_THREADS);
  185.                 $nt = array();
  186.                 $nt['pcX'] = $pcX; $nt['pcY'] = $pcY;
  187.                 $nt['mX'] = $mX; $nt['mY'] = $mY;
  188.                 $nt['dir'] = $dir;
  189.                 $nt['cs'] = array();
  190.                 $nt['pcX'] += $this->movin[$dir][0];
  191.                 $nt['pcY'] += $this->movin[$dir][1];
  192.                 array_push($this->Threads, $nt);
  193.                 $this->MoveOneStep();
  194.                 break;
  195.              case '!': $this->timeToQuit = true; break;
  196.              default: break;
  197.              }
  198.              
  199.              $this->MoveOneStep();
  200.           }
  201.       }
  202.     } catch (Exception $e) {
  203.       $message = $e->getMessage() . " (PC=" . ($this->t['pcX'] . ", " . $this->t['pcY']) . ")";
  204.       $result = -1;
  205.       //      print_r($this);
  206.     }
  207.    
  208.     return array("result" => $result, "message" => $message, "cycles" => $this->cycle_count, "output" => $output);
  209.   }
  210. }
  211. ?>
Add Comment
Please, Sign In to add comment