Created
August 30, 2012 03:47
-
-
Save DrakiaXYZ/3522114 to your computer and use it in GitHub Desktop.
Stack Machine Assembler
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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