Skip to content

Instantly share code, notes, and snippets.

@KaeruCT
Last active December 31, 2015 11:08
Show Gist options
  • Save KaeruCT/7977254 to your computer and use it in GitHub Desktop.
Save KaeruCT/7977254 to your computer and use it in GitHub Desktop.
#!/usr/bin/php
<?php
class Gasm { private $code = []; private $pc = 0; private $code_start = 0; private $code_len = 0; private $vars = []; private $labels = []; private $stack = []; private $comparison = false; private function line_number() { return 1 + $this->code_start + $this->pc; } private function strip_comments($line) { return trim(preg_replace('%;(.*)$%m', '', $line)); } private function is_label ($line) { return substr($line, -1) === ':'; } private function parse_line($line) { return array_map('trim', preg_split('%\s%', $line, 2)); } private function parse_args($args) { return array_map('trim', preg_split('%,%', $args)); } private function eval_expression($exp) { $matches = []; $ops = [ '+' => function ($a, $b) {return $a + $b;}, '-' => function ($a, $b) {return $a - $b;}, '*' => function ($a, $b) {return $a * $b;}, '/' => function ($a, $b) {return $a / $b;}, '%' => function ($a, $b) {return $a % $b;}, ]; $literals = [ '\n' => "\n", '\t' => "\t" ]; $ifx = '/(\w+)\s*(['.preg_quote(implode('', array_keys($ops)), '/').'])\s*(\w+)/'; if (preg_match('%^".*"$%', $exp)) { $val = str_replace(array_keys($literals), $literals, substr($exp, 1, -1)); } else if (preg_match($ifx, $exp, $matches)) { list($_, $a, $op, $b) = $matches; if (array_key_exists($a, $this->vars)) $a = $this->vars[$a]; if (array_key_exists($b, $this->vars)) $b = $this->vars[$b]; $val = $ops[$op]((double)$a, (double)$b); } else if (array_key_exists($exp, $this->vars)) { $val = $this->vars[$exp]; } else if (is_numeric($exp)) { $val = (double)$exp; } else { $val = $exp; } return $val; } public function load($handle) { $parse_data = true; for ($i = 0; false !== ($line = fgets($handle)); $i += 1) { $line = $this->strip_comments($line); if ($line === 'CODE') { $parse_data = false; $this->code_start = $i + 1; continue; } if ($parse_data) { if ($line === 'DATA') continue; @list($name, $value) = $this->parse_line($line); if (!empty($name)) $this->vars[$name] = $this->eval_expression($value); } else { if ($this->is_label($line)) { $lname = substr($line, 0, -1); $this->labels[$lname] = $i - $this->code_start; } $this->code[] = $line; } } $this->code_len = sizeof($this->code); } public function execute_line($line) { if ($this->is_label($line)) return; if ($line = $this->parse_line($line)) @list($op, $args) = $line; if (empty($op)) return; $op = strtolower($op); if (!empty($args)) $args = $this->parse_args($args); switch($op) { case 'println': case 'print': $val = $this->eval_expression($args[0]); if ($op === 'println') $val .= "\n"; echo $val; break; case 'inc': $this->vars[$args[0]] += 1; break; case 'dec': $this->vars[$args[0]] -= 1; break; case 'push': $this->stack[] = $this->eval_expression($args[0]); break; case 'pop': $val = array_pop($this->stack); if (!empty($args[0])) $this->vars[$args[0]] = $val; break; case 'mov': $val = $this->eval_expression($args[0]); $this->vars[$args[1]] = $val; break; case 'cmp': $a = $this->eval_expression($args[0]); $b = $this->eval_expression($args[1]); $this->comparison = ($a == $b); break; case 'jne': case 'je': $eq = $this->comparison; if ($op === 'jne') $eq = !$eq; if ($eq) { $this->pc = $this->labels[$args[0]]; } else if (!empty($args[1])) { $this->pc = $this->labels[$args[1]]; } break; case 'jmp': $this->pc = $this->labels[$args[0]]; break; case 'nop': break; default: $line = $this->line_number(); throw new Exception("INSTRUCTION NOT RECOGNIZED: {$op}, at line {$line}\n"); break; } } public function execute() { for ($this->pc = 0; $this->pc < $this->code_len; $this->pc += 1) { $this->execute_line($this->code[$this->pc]); } } } ;$gasm = unserialize('O:4:"Gasm":8:{s:10:"Gasmcode";a:23:{i:0;s:40:"println "here\'s a multiplication table:"";i:1;s:0:"";i:2;s:6:"start:";i:3;s:17:"mov w * h, number";i:4;s:0:"";i:5;s:16:"cmp w, w_max + 1";i:6;s:5:"inc w";i:7;s:19:"je end_row, print_n";i:8;s:0:"";i:9;s:8:"print_n:";i:10;s:12:"print number";i:11;s:10:"print "\t"";i:12;s:9:"jmp start";i:13;s:0:"";i:14;s:8:"end_row:";i:15;s:8:"mov 1, w";i:16;s:10:"print "\n"";i:17;s:12:"cmp h, h_max";i:18;s:5:"inc h";i:19;s:13:"je end, start";i:20;s:0:"";i:21;s:4:"end:";i:22;s:0:"";}s:8:"Gasmpc";i:0;s:16:"Gasmcode_start";i:7;s:14:"Gasmcode_len";i:23;s:10:"Gasmvars";a:4:{s:1:"w";d:1;s:1:"h";d:1;s:5:"w_max";d:12;s:5:"h_max";d:12;}s:12:"Gasmlabels";a:4:{s:5:"start";i:2;s:7:"print_n";i:9;s:7:"end_row";i:14;s:3:"end";i:21;}s:11:"Gasmstack";a:0:{}s:16:"Gasmcomparison";b:0;}');$gasm->execute();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment