Exercise 1: Hand-Assembling -(2 + 3) * 4 — Possible Solution ==================================================================== THE ASSEMBLY ------------------------------ chunk = Chunk() emit_constant(chunk, 2.0, 1) emit_constant(chunk, 3.0, 1) chunk.write(OP_ADD, 1) chunk.write(OP_NEGATE, 1) emit_constant(chunk, 4.0, 1) chunk.write(OP_MULTIPLY, 1) chunk.write(OP_RETURN, 1) DISASSEMBLY (for a sanity check before running) ------------------------------ 0000 1 OP_CONSTANT 0 '2.0' 0002 | OP_CONSTANT 1 '3.0' 0004 | OP_ADD 0005 | OP_NEGATE 0006 | OP_CONSTANT 2 '4.0' 0008 | OP_MULTIPLY 0009 | OP_RETURN RESULT ------------------------------ run_vm(chunk) -> -20.0 Hand-computed: 2 + 3 = 5, -(5) = -5, -5 * 4 = -20. Matches. WHY THIS WORKS AS AN ANSWER ------------------------------ The disassembly output confirms the instruction order matches the intended postfix evaluation order BEFORE running it -- exactly the workflow this chapter's own disassembler exists to support. Reading it left to right: push 2, push 3, add (stack: [5.0]), negate (stack: [-5.0]), push 4, multiply (stack: [-20.0]), return. Negation binds to the (2+3) sum first because OP_NEGATE appears immediately after OP_ADD in the instruction stream, before the second OP_CONSTANT for 4.0 is even pushed -- which is exactly what "-(2+3)*4" means (negate the sum, then multiply by 4), as opposed to "-2+3*4" or "2+(-3)*4", which would need OP_NEGATE placed at a different point in the sequence entirely. Getting the ORDER of instructions right is the whole job of a compiler (Chapter 3) -- this exercise does that job by hand, which is exactly why hand-assembly is worth practicing before automating it.