/******************************************************************************
* Name: Reference Solution
* NetID: refsoln
* Precept: P00
*
* Description: Renumbers TOY programs.
******************************************************************************/
public class ToyStory {
// a symbol table whose keys are memory locations and whose values are instructions
private ST<String, String> code = new ST<String, String>();
// adds each line to the ST, where a line is a String in the format: "XX: XXXX"
public ToyStory(String[] lines) {
for (String line : lines)
code.put(line.substring(0, 2), line.substring(4));
}
// return a String containing the program, in the form: "XX: XXXX\nXX: XXXX\n"
public String toString() {
StringBuilder result = new StringBuilder();
for (String line : code.keys())
result.append(line + ": " + code.get(line) + "\n");
return result.toString();
}
// returns true if there is an instruction defined at memory location 'mem'
public boolean isDefined(String mem) {
return code.contains(mem);
}
// returns true if instruction at 'mem' has op code C or D and ends in 'addr'
// assumes that there is an instruction defined at 'mem'
public boolean containsJumpTo(String mem, String addr) {
String instruction = code.get(mem);
char opCode = instruction.charAt(0);
return (opCode == 'C' || opCode == 'D') &&
instruction.substring(2).equals(addr);
}
// FOR FULL CREDIT, MUST CORRECTLY USE containsJumpTo() AND increment() (SEE BELOW)
// finds all instructions that jump to 'addr' and changes them to jump to 'addr'+1
public void incrementAllJumpsTo(String addr) {
for (String mem : code.keys())
if (containsJumpTo(mem, addr))
code.put(mem, code.get(mem).substring(0, 2) + increment(code.get(mem).substring(2)));
}
// DO NOT EDIT THIS METHOD
// IT IS PROVIDED TO MAKE INCREMENTING EASIER IN THE METHOD ABOVE
// takes a 2-hex-digit number as input, gives the next 2-digit-hex number as output
// for example, increment("19") returns "1A"
public static String increment(String addr) {
return String.format("%02X", Integer.parseInt(addr, 16) + 1);
}
// EXTRA CREDIT
// FOR ONE POINT, IMPLEMENT A WORKING NON-RECURSIVE SOLUTION
// FOR TWO POINTS, IMPLEMENT A WORKING RECURSIVE SOLUTION
// move all consecutive instructions at and after memory address 'min' down
// to the following memory address. also, maintains connections between all
// jumps and the instructions they jump to by calling incrementAllJumpsTo()
public void renumberAfter(String min) {
if (isDefined(increment(min)))
renumberAfter(increment(min));
code.put(increment(min), code.get(min));
incrementAllJumpsTo(min);
code.remove(min);
}
// DO NOT EDIT THIS METHOD
// IT IS PROVIDED TO HELP YOU TEST YOUR EXTRA CREDIT SOLUTION
// associates 'mem' with 'instruction' and updates the existing code accordingly
public void addLine(String mem, String instruction) {
// before we add this line, let's push everything down
if (isDefined(mem)) renumberAfter(mem);
// then add this line
code.put(mem, instruction);
}
// YOU MAY EDIT THIS METHOD BUT CODE WRITTEN HERE WILL NOT BE GRADED
public static void main(String[] args) {
// THIS IS JUST A DUMMY TOY PROGRAM TO TEST YOUR CODE
String[] toy = {"10: 1000", "11: C010"};
// READ IT IN, PRINT IT OUT
ToyStory story = new ToyStory(toy);
StdOut.println(story.toString());
// ARE THERE INSTRUCTIONS DEFINED AT THESE MEMORY LOCATIONS?
StdOut.println(story.isDefined("10")); // TRUE
StdOut.println(story.isDefined("12")); // FALSE
// DO THE FOLLOWING LINES CONTAIN JUMPS TO THESE ADDRESSES?
StdOut.println(story.containsJumpTo("11", "10")); // TRUE
StdOut.println(story.containsJumpTo("11", "11")); // FALSE
// LET'S CHANGE ALL JUMPS TO 10 TO JUMP TO 11 INSTEAD
story.incrementAllJumpsTo("10");
StdOut.println(story); // RESULT: "10: 1000\n11: C011\n"
}
}