Skip to content

Instantly share code, notes, and snippets.

@DrakiaXYZ
Created August 30, 2012 03:47
Show Gist options
  • Save DrakiaXYZ/3522114 to your computer and use it in GitHub Desktop.
Save DrakiaXYZ/3522114 to your computer and use it in GitHub Desktop.
Stack Machine Assembler
<?php
if (!isset($_REQUEST['asm'])) {
echo "Stack Machine Assembler<br/>";
echo "<form method=\"post\">";
echo "<textarea name=\"asm\" rows=\"30\" cols=\"100\"></textarea><br>";
echo "<input type=\"submit\" value=\"Assemble\">";
echo "</form>";
} else {
$lines = explode("\n", $_REQUEST['asm']);
if (count($lines) == 0) {
echo "You need to supply input";
die();
}
$SYMBOLTABLE = array('PSW' => 'FFFB',
'A' => 'FFFC',
'B' => 'FFFD',
'C' => 'FFFE',
'D' => 'FFFF');
$FUNCTABLE = array('nop' => array('00', 0),
'halt' => array('01', 0),
'pushimm' => array('02', 1),
'pushext' => array('03', 2),
'popinh' => array('04', 0),
'popext' => array('05', 2),
'jnz' => array('06', 2),
'jnn' => array('0A', 2),
'add' => array('07', 0),
'sub' => array('08', 0),
'nor' => array('09', 0));
// Pass 1, parse commands, throw symbols into tables.
for ($i = 0; $i < count($lines); $i++) {
$line = $lines[$i];
// Find comment on line if it exists. Strip it from line.
$commPos = strpos($line, '--'); // Find comment position (If it exists)
$comment = '';
if ($commPos === false) $commPos = strlen($line);
else $comment = substr($line, $commPos); // Store comment
$line = substr($line, 0, $commPos); // Strip comment.
$line = trim($line); // Remove space from before/after command.
if ($line== '') continue; // If line is blank, not a command, skip it.
// Find if there's a label, add it to symbol table.
$symPos = strpos($line, ':');
$symbol = '';
if ($symPos !== false) {
$symbol = substr($line, 0, $symPos);
$line = trim(substr($line, $symPos + 1));
if ($line == '') continue;
$SYMBOLTABLE[$symbol] = dechex(count($parse)); // Set symbol table entry to address.
}
// Replace the line in the list with the line minus symbol, and minus comment.
$lines2[] = $line;
// Check for function, replace. Make sure to leave room for operand
$funcEnd = strpos($line, ' ');
if ($funcEnd === false) $funcEnd = strlen($line);
$func = substr($line, 0, $funcEnd);
if (array_key_exists($func, $FUNCTABLE)) {
$parse[] = str_pad(base_convert($FUNCTABLE[$func][0], 16, 2), 8, '0', STR_PAD_LEFT).' '.$line;
if ($symbol != '') $parse[count($parse) - 1] .= ' ['.$symbol.' = 0x'.$SYMBOLTABLE[$symbol].']';
// Create room for the added data in parse 2
for ($j = 0; $j < $FUNCTABLE[$func][1]; $j++)
$parse[] = '';
} else
die("Problem parsing ASM, unknown function $func");
}
$pLoc = 0;
for ($i = 0; $i < count($parse); $i++) {
// Increase our internal pointer if this is a command. And skip over it.
if ($parse[$i] != '') {
$pLoc++;
$parse2[] = $parse[$i];
continue;
}
// Grab the current working line. This will be function and operand only
$line = $lines2[$pLoc - 1];
$funcEnd = strpos($line, ' ');
if ($funcEnd === false) $funcEnd = strlen($line);
$func = substr($line, 0, $funcEnd);
$operand = substr($line, $funcEnd + 1);
// Check if we have a symbol that matches this, a function, or a +/- operation. Otherwise it is a hex value.
$fun = '';
if (strpos($operand, "(") !== false) {
$fun = $operand[0];
if ($fun != 'L' && $fun != 'H') {
die("Invalid function call");
}
$operand = substr($operand, 2, -1);
}
if ($operand[0] == '+' || $operand[0] == '-') {
if ($operand[strlen($operand)-1] == 'h') $base = 16;
else $base = 10;
$operand = $i + intval(substr($operand, 0, strlen($operand)-1), $base) - 1;
$operand = base_convert($operand, 10, 2);
} else if (@array_key_exists($operand, $SYMBOLTABLE)) {
$operand = base_convert($SYMBOLTABLE[$operand], 16, 2);
} else {
$pos = strpos($operand, '+');
if ($pos === false) $pos = strpos($operand, '-');
if ($pos === false)
$operand = base_convert($operand, 16, 2);
else {
$off = substr($operand, $pos + 1);
if (substr($off, -1) == 'h') $off = intval(base_convert(substr($off, 0, -1), 16, 10));
else if (substr($off, -1) == 'd') $off = intval(substr($off, 0, -1));
else $off = intval($off);
$operand = substr($operand, 0, $pos);
if (@array_key_exists($operand, $SYMBOLTABLE)) {
$operand = base_convert((hexdec($SYMBOLTABLE[$operand]) + $off), 10, 2);
} else
die("Can't offset constant value");
}
}
if ($fun != '') {
$operand = str_pad($operand, 16, '0', STR_PAD_LEFT);
if ($fun == 'L')
$operand = substr($operand, 8, 8);
else
$operand = substr($operand, 0, 8);
} else
$operand = str_pad($operand, $FUNCTABLE[$func][1]*8, '0', STR_PAD_LEFT);
// Push the output value to parse2, the final machine code.
for ($j = 0; $j < $FUNCTABLE[$func][1]; $j++) {
$parse2[] = substr($operand, $j * 8, 8);
}
// We are on the first operand, so increase i by one less than the operand count.
$i += $FUNCTABLE[$func][1] - 1;
}
// Output the machine code to console
for ($i = 0; $i < count($parse2); $i++) {
echo $parse2[$i]."\n";
}
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment