· 7 years ago · Dec 13, 2018, 03:34 AM
1<?php
2 if (!isset($_REQUEST['asm'])) {
3 echo "Stack Machine Assembler<br/>";
4 echo "<form method=\"post\">";
5 echo "<textarea name=\"asm\" rows=\"30\" cols=\"100\"></textarea><br>";
6 echo "<input type=\"submit\" value=\"Assemble\">";
7 echo "</form>";
8 } else {
9 $lines = explode("\n", $_REQUEST['asm']);
10 if (count($lines) == 0) {
11 echo "You need to supply input";
12 die();
13 }
14 $SYMBOLTABLE = array('PSW' => 'FFFB',
15 'A' => 'FFFC',
16 'B' => 'FFFD',
17 'C' => 'FFFE',
18 'D' => 'FFFF');
19 $FUNCTABLE = array('nop' => array('00', 0),
20 'halt' => array('01', 0),
21 'pushimm' => array('02', 1),
22 'pushext' => array('03', 2),
23 'popinh' => array('04', 0),
24 'popext' => array('05', 2),
25 'jnz' => array('06', 2),
26 'jnn' => array('0A', 2),
27 'add' => array('07', 0),
28 'sub' => array('08', 0),
29 'nor' => array('09', 0));
30
31 // Pass 1, parse commands, throw symbols into tables.
32 for ($i = 0; $i < count($lines); $i++) {
33 $line = $lines[$i];
34
35 // Find comment on line if it exists. Strip it from line.
36 $commPos = strpos($line, '--'); // Find comment position (If it exists)
37 $comment = '';
38 if ($commPos === false) $commPos = strlen($line);
39 else $comment = substr($line, $commPos); // Store comment
40 $line = substr($line, 0, $commPos); // Strip comment.
41 $line = trim($line); // Remove space from before/after command.
42 if ($line== '') continue; // If line is blank, not a command, skip it.
43
44 // Find if there's a label, add it to symbol table.
45 $symPos = strpos($line, ':');
46 $symbol = '';
47 if ($symPos !== false) {
48 $symbol = substr($line, 0, $symPos);
49 $line = trim(substr($line, $symPos + 1));
50 if ($line == '') continue;
51 $SYMBOLTABLE[$symbol] = dechex(count($parse)); // Set symbol table entry to address.
52 }
53
54 // Replace the line in the list with the line minus symbol, and minus comment.
55 $lines2[] = $line;
56
57 // Check for function, replace. Make sure to leave room for operand
58 $funcEnd = strpos($line, ' ');
59 if ($funcEnd === false) $funcEnd = strlen($line);
60 $func = substr($line, 0, $funcEnd);
61 if (array_key_exists($func, $FUNCTABLE)) {
62 $parse[] = str_pad(base_convert($FUNCTABLE[$func][0], 16, 2), 8, '0', STR_PAD_LEFT).' '.$line;
63 if ($symbol != '') $parse[count($parse) - 1] .= ' ['.$symbol.' = 0x'.$SYMBOLTABLE[$symbol].']';
64 // Create room for the added data in parse 2
65 for ($j = 0; $j < $FUNCTABLE[$func][1]; $j++)
66 $parse[] = '';
67 } else
68 die("Problem parsing ASM, unknown function $func");
69 }
70
71 $pLoc = 0;
72 for ($i = 0; $i < count($parse); $i++) {
73 // Increase our internal pointer if this is a command. And skip over it.
74 if ($parse[$i] != '') {
75 $pLoc++;
76 $parse2[] = $parse[$i];
77 continue;
78 }
79
80 // Grab the current working line. This will be function and operand only
81 $line = $lines2[$pLoc - 1];
82 $funcEnd = strpos($line, ' ');
83 if ($funcEnd === false) $funcEnd = strlen($line);
84 $func = substr($line, 0, $funcEnd);
85 $operand = substr($line, $funcEnd + 1);
86
87 // Check if we have a symbol that matches this, a function, or a +/- operation. Otherwise it is a hex value.
88 $fun = '';
89 if (strpos($operand, "(") !== false) {
90 $fun = $operand[0];
91 if ($fun != 'L' && $fun != 'H') {
92 die("Invalid function call");
93 }
94 $operand = substr($operand, 2, -1);
95 }
96 if ($operand[0] == '+' || $operand[0] == '-') {
97 if ($operand[strlen($operand)-1] == 'h') $base = 16;
98 else $base = 10;
99 $operand = $i + intval(substr($operand, 0, strlen($operand)-1), $base) - 1;
100 $operand = base_convert($operand, 10, 2);
101 } else if (@array_key_exists($operand, $SYMBOLTABLE)) {
102 $operand = base_convert($SYMBOLTABLE[$operand], 16, 2);
103 } else {
104 $pos = strpos($operand, '+');
105 if ($pos === false) $pos = strpos($operand, '-');
106 if ($pos === false)
107 $operand = base_convert($operand, 16, 2);
108 else {
109 $off = substr($operand, $pos + 1);
110 if (substr($off, -1) == 'h') $off = intval(base_convert(substr($off, 0, -1), 16, 10));
111 else if (substr($off, -1) == 'd') $off = intval(substr($off, 0, -1));
112 else $off = intval($off);
113 $operand = substr($operand, 0, $pos);
114 if (@array_key_exists($operand, $SYMBOLTABLE)) {
115 $operand = base_convert((hexdec($SYMBOLTABLE[$operand]) + $off), 10, 2);
116 } else
117 die("Can't offset constant value");
118 }
119 }
120 if ($fun != '') {
121 $operand = str_pad($operand, 16, '0', STR_PAD_LEFT);
122 if ($fun == 'L')
123 $operand = substr($operand, 8, 8);
124 else
125 $operand = substr($operand, 0, 8);
126 } else
127 $operand = str_pad($operand, $FUNCTABLE[$func][1]*8, '0', STR_PAD_LEFT);
128
129 // Push the output value to parse2, the final machine code.
130 for ($j = 0; $j < $FUNCTABLE[$func][1]; $j++) {
131 $parse2[] = substr($operand, $j * 8, 8);
132 }
133 // We are on the first operand, so increase i by one less than the operand count.
134 $i += $FUNCTABLE[$func][1] - 1;
135 }
136
137 // Output the machine code to console
138 for ($i = 0; $i < count($parse2); $i++) {
139 echo $parse2[$i]."\n";
140 }
141 }
142?>