Lvalue = expression that appears on the Left in an assignment, such as a variable, an array access, or a pointer-following. Rvalue = expression that appears on the Right in an assignment. The code generator for an Rvalue will expect to put something on the stack. The code generator for an Lvalue might expect to take something from the stack and put it somewhere else. The basic scheme for code generation, given a pares tree as its input is like this: codegen_rvalue(t) is { if (t is a numeric constant) output "PUSHC " value else if (t is a variable) output "PUSHM " name else if (t is an arithmetic operation, + for example) { codegen_rvalue(t's left) codegen_rvalue(t's right) output "POP R1" output "POP R2" output "ADD R2, R1" output "PUSH R2" } etc } codegen_lvalue(t) is { if (t is a variable) output "POP " name else don't know how to do this yet } codegen_assignment(t) is { codegen_rvalue(t's right) codegen_lvalue(t's left) } You could easily keep track of how deep the stack will be at any point by maintaining a global counter. Increment before every push, and decrement after every pop. Then you wouldn't need to bother with a stack pointer at all, you could just use an array. If the stack doesn't get too deep, the registers R1, R2, R3, ... could actually be that array. Then the code would be much faster: int depth = 0 codegen_rvalue(t) is { if (t is a numeric constant) { depth+=1; output " LOAD R"depth "," value } else if (t is a variable) { depth+=1; output " LOAD R"depth "," name } else if (t is an arithmetic operation, + for example) { codegen_rvalue(t's left) codegen_rvalue(t's right) // note R(depth) is the top stack item // R(depth-1) is the previous stack item // after the addition, the stack will be one item smaller // so R(depth-1) will be the new stack top // and the result of the addition should be on top output "ADD R"(depth-1) ", R"depth depth-=1; } etc } codegen_lvalue(t) is { if (t is a variable) { output "STORE R"depth "," name depth-=1; } else don't know how to do this yet } codegen_assignment(t) is { codegen_rvalue(t's right) codegen_lvalue(t's left) } Although this is a lot faster, it still produces far too many instructions. An even better plan is to let codegen_rvalue decide for itself where the value should go. Its job is now to return something you could use as an operand in another instruction (that is, a numeric constant, a variable name, or a register name) codegen_rvalue(t) is { if (t is a numeric constant) return that constant else if (t is a variable) return that variable's name else if (t is an arithmetic operation, + for example) { A = codegen_rvalue(t's left) B = codegen_rvalue(t's right) // if either of A and B is a register, that register // can be reused for the result. If neither is a // register, we need to find one ourselves if (A is a register name && B is a register name) { output "ADD " A "," B note that B is not occupied any more return A } else if (A is a register name) { output "ADD " A "," B return A } else if (B is a register name) { output "ADD " B "," A // note that subtract and divide are a little more // complex in this case return B } else { find a register that is unoccupied, call it X note that X is now occupied output "LOAD " X "," A output "ADD " X "," B return X } } etc } codegen_assignment(t) is { if (t's left is a variable) { A = name of that variable B = codegen_rvalue(t's right) if (B is a register name) { produce "STORE " B "," A note that B is not occupied any more } else { find a register that is unoccupied, call it X output "LOAD " X "," B output "STORE " X "," B } } etc }