By the end of this week you should have the ability to:
Memory is basically like a very long list with each element having an address and a value.
If we have a variable that might change in size, and indirect representation is used - a pointer. This mean that the variable can occupy a fixed size space in memory because it just points to the address of where the data is really stored (usually in the heap).
Stacks are last-in-first-out data structures: think of a stack of paper where you can only add or remove from the top. Stacks are an effective way to store local variables throughout the lifetime of a program.
Stack Storage Allocation:
Example of Routines and returns
let
var g: Integer;
func F(m: Integer, n: Integer): Integer ~
m * n
in
begin
getint(var g)
putint(F(g, g+1))
end
PUSH 1
LOADA 0[SB]
CALL getint
LOAD 0[SB]
LOAD 0[SB]
PUSH 1
CALL add
CALL(SB) F
CALL putint
POP
HALT
F:
LOAD -2[LB]
LOAD -1[LB]
CALL mult
RETURN(1) 2
Heap storage allocation is another way to organise memory, and is good for indirect storage of variables.
A heap variable is allocated by a special command called an allocator in Java. This is whenever you use the keyword new and in C it is malloc(). These return a pointer to the variable in the heap. They exist in memory until it is unallocated (via free() in C or automatically in Java).
Heap is placed in opposite to the stack:
[ Stack ] <-SB
[ a ]
[ b ]
[ ...... ] <-ST
[ ]
[ 8 ] <-HT
[ H ]
[ ]
[ Heap ] <-HB
Heap Storage Allocation:
Code Selection is the process of choosing the specific machine code instructions that are needed to represent a high high-level code structure. Code Templates are used for this purpose, though it is complicated by dealing with special cases.
Storage Allocation is the process of deciding the addresses for each variable in the program. This is why we have spent some time discussing stack and heap memory.
We have parsed the program to an AST and applied contextual analysis to that AST to ensure that all the types are valid! We are now ready to generate the target code for our program.
n := n + 1
LOAD n
LOAD 1
ADD
STORE n
Adding one to a variable is very common thing to do. We can instead use this instruction
LOAD n
SUCC
STORE n
SUCC, means successor instruction to increase the value on the top of the stack by one. This uses 3 instructions instead of 4, meaning it is around 25% faster.
The Triangle Abstract Machine (TAM) is a virtual machine designed as the target for our case study compiler. It is also implemented in Java, and you have a copy of it by virtue of cloning the Triangle-Tools project. TAM has the following features:
Its memory is organised to have a stack at the low-address end and a heap at the high address end. Low level operations are provided for adding and removing data in these
Call and return instructions for routines handle frames automatically; return automatically replaces the arguments in the stack with a result from the functions return.
The only registers are dedicated to specific purposes as we’ve described. SB, ST, HB and HT to locate the stack and heap; LB points to the topmost frame on the stack, and so on. These are updated automatically by the instructions that add or remove things from memory
Several routines such as ADD, MULT, and NOT are provided for basic arithmetic and logic operations. There are also routines for reading and writing text on the console.
A full description of TAM is given in the extracts from Programming Language Processors in Java given in the Canvas Reading List. You don’t need to become familiar with this but the text is there to serve as reference material and you will likely want to refer to it when reading and extending the compiler.
Yarr link be here! https://www.cin.ufpe.br/~jml/programming-language-processors-in-java-compilers-and-interpreters.9780130257864.25356.pdf

All TAM instructions have a common format.
[ op ][ r ][ n ][ d ]
4 bits 4 bits 8 bits 16 bits
