|
@@ -14,10 +14,17 @@ let tape = [];
|
|
|
* progress the pointer by one position.
|
|
|
*/
|
|
|
let tapePointer = 0;
|
|
|
+/**
|
|
|
+ * A boolean value to determine whether a label is waiting to receive an address
|
|
|
+ */
|
|
|
+let labelStartActive = false;
|
|
|
/**
|
|
|
* A dictionary of labels and the line numbers they start at
|
|
|
*/
|
|
|
-const labelDictionary = {};
|
|
|
+const labelDictionary = {
|
|
|
+ /** Stores labels that haven't had their address found yet */
|
|
|
+ _toSet: undefined,
|
|
|
+};
|
|
|
/**
|
|
|
* A dictionary of variables created in the assembly
|
|
|
*/
|
|
@@ -61,11 +68,27 @@ const ASM_DICTIONARY = {
|
|
|
*/
|
|
|
function transpileAssembly(assembly) {
|
|
|
for (const line of assembly) {
|
|
|
- const instruction = line.shift();
|
|
|
- if (!ASM_DICTIONARY[instruction]) {
|
|
|
+ let instruction = line.shift();
|
|
|
+ // Check if the "instruction" is actually a label start
|
|
|
+ if (isLabelStart(instruction)) {
|
|
|
+ // Store the label in the dictionary, sans the colon
|
|
|
+ labelDictionary._toSet = instruction.substring(0, instruction.length -1);
|
|
|
+ labelStartActive = true;
|
|
|
+
|
|
|
+ // If the line only contained the label start, continue to the next line
|
|
|
+ if (line.length == 0) { continue; }
|
|
|
+ // Otherwise, grab the next next string, which must be the instruction
|
|
|
+ instruction = line.shift();
|
|
|
+ }
|
|
|
+ else if (!ASM_DICTIONARY[instruction]) {
|
|
|
throw new Error(`No function defined for the ${instruction} instruction.`);
|
|
|
}
|
|
|
|
|
|
+ // If a label is waiting to be set, the tape pointer is currently where
|
|
|
+ // the next instruction is going to be put, so we can set the label's
|
|
|
+ // pointer here
|
|
|
+ setLabelStart();
|
|
|
+
|
|
|
// Call the function for this instruction, and pass the rest of the line as parameters
|
|
|
ASM_DICTIONARY[instruction](...line);
|
|
|
}
|
|
@@ -146,10 +169,10 @@ function insertOutput(outputParameter) {
|
|
|
* @param {string} testingParameter The parameter to test. Could be an immediate value or an address
|
|
|
* @param {string} jumpDestination The address to jump to if the test passes
|
|
|
*/
|
|
|
-function insertTestJump(opcode, testingParameter, jumpDestination) {
|
|
|
+function insertTestJump(opcode, testingParameter, jumpDestination, offset) {
|
|
|
tape[tapePointer++] = getParameterMode(jumpDestination) + getParameterMode(testingParameter) + opcode;
|
|
|
tape[tapePointer++] = testingParameter;
|
|
|
- tape[tapePointer++] = jumpDestination;
|
|
|
+ tape[tapePointer++] = validateJumpDestination(jumpDestination, offset);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -213,15 +236,41 @@ function placeVariables() {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Check if a given parameter is, or contains, a label
|
|
|
+ * Check if a given string matches a label start definition
|
|
|
*
|
|
|
* @param {string} parameter The parameter to check
|
|
|
*
|
|
|
* @returns {boolean}
|
|
|
*/
|
|
|
-function isLabel(parameter) {
|
|
|
- const labelMatcher = new RegExp("\w+(?:\s*[+]\s*\d*)?");
|
|
|
- return labelMatcher.test(parameter);
|
|
|
+function isLabelStart(parameter) {
|
|
|
+ return /^\w+:$/.test(parameter);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Confirm that a label exists
|
|
|
+ *
|
|
|
+ * @param {string} labelName The possible label name to check
|
|
|
+ *
|
|
|
+ * @returns {boolean}
|
|
|
+ */
|
|
|
+function validateLabel(labelName) {
|
|
|
+ return labelDictionary.hasOwnProperty(labelName);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Get the address to jump to
|
|
|
+ *
|
|
|
+ * @param {string} jumpDestination The destination to jump to. Could be either a memory address or
|
|
|
+ * @param {number} [offset] An offset for the jump destination. Only used if the jump destination is a label
|
|
|
+ *
|
|
|
+ * @returns {string|number} The address to jump to
|
|
|
+ */
|
|
|
+function validateJumpDestination(jumpDestination, offset = 0) {
|
|
|
+ if (isAddress(jumpDestination)) { return jumpDestination; }
|
|
|
+ if (validateLabel(jumpDestination)) {
|
|
|
+ return labelDictionary[jumpDestination] + offset
|
|
|
+ }
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -281,6 +330,18 @@ function instructionNotYetImplemented(instruction) {
|
|
|
throw new Error(`The ${instruction} instruction has not yet been implemented`);
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * Assigns a label waiting an address to the current pointer position
|
|
|
+ *
|
|
|
+ * @returns {void}
|
|
|
+ */
|
|
|
+function setLabelStart() {
|
|
|
+ if (labelDictionary._toSet === undefined) { return };
|
|
|
+
|
|
|
+ labelDictionary[labelDictionary._toSet] = tapePointer;
|
|
|
+ labelDictionary._toSet = undefined;
|
|
|
+}
|
|
|
+
|
|
|
/* MAIN FUNCTIONALITY */
|
|
|
|
|
|
/**
|
|
@@ -308,15 +369,15 @@ function readFile(filename) {
|
|
|
function main() {
|
|
|
const ret = readFile(process.argv[2]);
|
|
|
|
|
|
- console.log(typeof ret);
|
|
|
- console.log(ret);
|
|
|
+ console.log("Assembly provided: ", ret);
|
|
|
|
|
|
console.log("Parsing assembly...");
|
|
|
|
|
|
transpileAssembly(ret);
|
|
|
|
|
|
- console.log("Parsed Assembly: ")
|
|
|
- console.log(tape.join(", "));
|
|
|
+ console.log("Parsed IntCode: ", tape.join(", "));
|
|
|
+
|
|
|
+ console.log("Labels:", labelDictionary);
|
|
|
}
|
|
|
|
|
|
main();
|