Skip to content

Instantly share code, notes, and snippets.

@adi928
Created January 28, 2026 07:49
Show Gist options
  • Select an option

  • Save adi928/37efc135fb630c638f2c102a845becd0 to your computer and use it in GitHub Desktop.

Select an option

Save adi928/37efc135fb630c638f2c102a845becd0 to your computer and use it in GitHub Desktop.
prompt-question-failed
/*
Using any language, implement an assembler + simulator for a new assembly language that has the following characteristics:
- Maintains a set of registers (can be thought of as variables) that store integers and can be used to move and process data via instructions
- Instructions are executed sequentially
- Instructions should support constant values for arguments in addition to registers
here are some example instructions:
add 45 5 ra # add 45 + 5, store result in ra
add 10 rb rb # add 10 to rb, store in rb
sub ra rb rc # subtract ra (50) - rb (10) , store the result (40) in rc
The assembler should take a newline separated string of instructions, which then get parsed and executed by the simulator. Feel free to implement whatever sort of abstractions make the most sense to you, but try to design for extensibility. For this entire exercise you can assume that the given input will always be correctly formatted for your implementation.
===================
As a first step, we will be implementing basic arithmetic functionality for our language. To start with, we will implement the add and subtract instructions mentioned in the earlier example, as well as instructions for multiplication and division.
add 45 5 ra
add 10 rb rb
sub ra rb rc
mul ra rc rd
div rd rb re
Registers that are not initialized should be treated as 0, therefore the final register state should be:
ra = 50, rb = 10, rc = 40, rd = 2000, re = 200
This first pass should take in a single string that contains multiple instruction statements separated by newline characters:
add 45 5 ra\nadd 10 rb rb\nsub ra rb rc\nmul ra rc rd\ndiv rd rb re
==============
Now that we have a couple working instructions, it’s time to implement process memory. Most processors have a small, finite amount of pre-defined registers, so they need a larger but slower store for larger sets of data. With that in mind, memory should be some indexable data structure, with each offset capable of storing the full contents of a register. For example, we might want to set memory[55] = 10. To interact with memory, we will need to add two new instruction operand types to our language:
add 0 8 ra # store 8 into ra
add ra 5 [ra] # add 5 to ra (8), store result in memory[ra] (ra is still 8, so mem[8] = 13); memory[ra] = ra + 5
sub [ra] 10 [8] # load memory[ra] and subtract 10 from it, store the result back into memory[8]; memory[8] = memory[ra] - 10
add [ra] [8] rb # should result in rb = 3 + 3
The final register state should show ra = 8, rb = 6, and memory should show memory[8] = 3. We will use this new example as our new test string.
Here is our raw input:
add 0 8 ra\nadd ra 5 [ra]\nsub [ra] 10 [8]\nadd [ra] [8] rb
*/
import java.io.*;
import java.util.*;
// interface instruction {
// abstract void execute(String arg1, String arg2, String arg3);
// }
// class add implements instruction {
// Map<String, Integer> registers;
// add() {
// registers = new HashMap<>();
// }
// public void execute(String arg1, String arg2, String arg3) {
// return;
// }
// }
// class mul implements instruction {
// Map<String, Integer> registers;
// mul() {
// registers = new HashMap<>();
// }
// public void execute(String arg1, String arg2, String arg3) {
// return;
// }
// }
class Solution {
int[] memory = new int[100];
public void main() {
// String inputString = "add 45 5 ra\nadd 10 rb rb\nsub ra rb rc\nmul ra rc rd\ndiv rd rb re";
String inputString = "add 0 8 ra\nadd ra 5 [ra]\nsub [ra] 10 [8]\nadd [ra] [8] rb";
Map<String, Integer> registers = new HashMap<>();
for (String r : List.of("ra", "rb", "rc", "rd", "re")) {
registers.put(r, 0);
}
for(String instruction : inputString.split("\n")) {
String[] instructAsArr = instruction.split(" ");
int a = getArgAsInt(instructAsArr[1], registers);
int b = getArgAsInt(instructAsArr[2], registers);
int output =0;
boolean isMemory = false;
if (instructAsArr[3].charAt(0) == '[') {
instructAsArr[3].substring(1, instructAsArr[3].length());
int memoryAddr = registers.containsKey(instructAsArr[3]) ?
registers.get(instructAsArr[3]) :
Integer.parseInt(instructAsArr[3]);
isMemory = true;
output = memoryAddr;
}
switch(instructAsArr[0]) {
case "add":
if (isMemory) {
memory[output] = a+b;
} else {
registers.put(instructAsArr[3], a+b);
}
break;
case "sub":
if (isMemory) {
memory[output] = a-b;
} else {
registers.put(instructAsArr[3], a-b);
}
break;
case "mul":
if (isMemory) {
memory[output] = a*b;
} else {
registers.put(instructAsArr[3], a*b);
}
break;
case "div":
if (isMemory) {
memory[output] = a/b;
} else {
registers.put(instructAsArr[3], a/b);
}
break;
default:
// throw new Exception("Unsupported operation");
}
}
for (Map.Entry<String, Integer> element : registers.entrySet()) {
System.out.println(element.getKey() + ": " + element.getValue());
}
}
private int getArgAsInt(String arg, Map<String, Integer> registers) {
if (arg.charAt(0) == '[') {
arg.substring(1, arg.length());
int memoryAddr = registers.containsKey(arg) ?
registers.get(arg) :
Integer.parseInt(arg);
return memory[memoryAddr];
}
return registers.containsKey(arg) ?
registers.get(arg) :
Integer.parseInt(arg);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment