As the authors of the book wrote, you should be able to finish all the projects with implementing a very simple alloc, which just allocates from the empty block, and free, which does nothing. You can start with that and confirm that it works.
One easy way to add some debug info to your alloc function is to designate some memory (let's say 10 bytes) in the start of the heap, and put there meaningful values. For example, you can maintain a count for how many times alloc was called, how many times free was called, how many bytes were requested (total) and how many bytes were freed (again, total). Or some other relevant info, that you might find useful.
If you want to write to the screen, you must take care to only use non-allocating methods. Alternatively, you can have a flag, which tells the allocator whether to print or not. Something like that:
class Memory {
var boolean printDebug;
function void init() {
let printDebug = true;
...
}
function int alloc(int size) {
if (printDebug) {
let printDebug = false;
do Output.print(....);
let printDebug = true;
}
...
}
}
(Sorry, my Jack-fu is a bit rusty. This may be written in a more elegant way.) Note though, that String constants in Jack are replaced with String constructor at the place of the call. This means that if:
do Output.printString("Hi");
is equivalent to
do Output.printString(String.new(2).append(72).append(105));
The memory of the constructed string is then "lost". That is, it's still marked as used, but its address is forgotten. This is called a memory leak. To prevent it, you can do two things: allocate the strings you need in the init method. This way you can reuse them. Or assign the string to a variable and dispose of it after use. In the Memory class, I strongly recommend the former.