Skip to content

Instantly share code, notes, and snippets.

@KaeruCT
Created December 13, 2013 23:22
Show Gist options
  • Save KaeruCT/7953319 to your computer and use it in GitHub Desktop.
Save KaeruCT/7953319 to your computer and use it in GitHub Desktop.
#!/usr/bin/php
<?php
if (empty($argv[1])) {
die("please specify a file\n");
}
function is_str($word) {
return preg_match('%^".*"$%', $word);
}
function is_comment($line) {
return @$line[0] === ';';
}
function is_label($line) {
return substr($line, -1) === ':';
}
function parse_line($line) {
$words = preg_split('%\s%', $line);
return $words;
}
function eval_expression($exp) {
global $vars;
$matches = [];
$operations = [
'+' => 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;},
];
$exprgxp = '/(\w+)(['.preg_quote(implode('', array_keys($operations)), '/').'])(\w+)/';
if (preg_match($exprgxp, $exp, $matches)) {
list($dummy, $a, $op, $b) = $matches;
if (array_key_exists($a, $vars)) {
$a = $vars[$a];
}
if (array_key_exists($b, $vars)) {
$b = $vars[$b];
}
$val = $operations[$op]((int)$a, (int)$b);
} else if (array_key_exists($exp, $vars)) {
$val = $vars[$exp];
} else {
$val = (int)$exp;
}
return $val;
}
$contents = file_get_contents($argv[1]);
@list($datasec, $codesec) = explode("CODE\n", $contents);
$data = array_map('trim', explode("\n", $datasec));
$code = array_map('trim', explode("\n", $codesec));
$vars = [];
$labels = [];
$stack = [];
$pcounter = 0;
// set up vars
foreach ($data as $dline) {
if ($dline !== 'DATA' && !is_comment($dline)) {
@list($name, $value) = parse_line($dline);
if (!empty($name)) {
$vars[$name] = (int)$value;
}
}
}
// set up labels
foreach ($code as $i => $cline) {
if (is_label($cline)) {
$lname = substr($cline, 0, -1);
$labels[$lname] = $i;
}
}
function execute_line($line) {
global $pcounter, $vars, $labels, $stack;
if (is_label($line) || empty($line)) {
$pcounter += 1;
return;
}
$w = parse_line($line);
switch(strtolower($w[0])) {
case 'print':
if (is_str($w[1])) {
$val = substr($w[1], 1, -1);
} else {
$val = eval_expression($vars[$w[1]]);
}
echo "{$val}\n";
$pcounter += 1;
break;
case 'inc':
$vars[$w[1]] += 1;
$pcounter += 1;
break;
case 'push':
$stack[] = eval_expression($w[1]);
$pcounter += 1;
break;
case 'pop':
$times = !empty($w[1]) ? $w[1] : 1;
for ($i = 0; $i < $times; $i += 1) {
array_pop($stack);
}
$pcounter += 1;
break;
case 'jmpeq':
$sl = sizeof($stack);
if ($stack[$sl-1] === $stack[$sl-2]) {
$pcounter = $labels[$w[1]];
} else if (!empty($w[2])) {
$pcounter = $labels[$w[2]];
} else {
$pcounter += 1;
}
break;
case 'jmp':
$pcounter = $labels[$w[1]];
break;
case 'nop':
default:
$pcounter += 1;
break;
}
}
$codelen = sizeof($code);
while ($pcounter < $codelen) {
execute_line($code[$pcounter]);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment