Stack Machines and Machine Language
An expression tree is a data structure that represents an expression, with operators as internal nodes and numbers as leaves.
Two Ways to Use an Expression
So far, the work has been about evaluation: given an expression, find its value. A natural next question is how that skill connects to translating programs into machine language. The answer is less surprising than it first seems. Instead of computing the value of an expression directly, a program could produce a list of machine language instructions that would compute that value. Both approaches start from the same expression, so the real question becomes what those instructions look like and how the structure of an expression can be used to produce them.
What do you think happens?
Suppose a machine can only work with a stack of values, and it is given the instructions push 3, push 4, and then apply +. How many values are on the stack just before the apply + instruction runs?
Reveal answer
Two
Each push places one number on the stack, so after push 3 and push 4 there are two values waiting. The apply + instruction will take those two values, add them, and leave one result behind. Keep this in mind as you read the rest of the article: the stack is where the work happens.
Expressions as Trees
An expression tree is a data structure that represents an expression. Operators are internal nodes, and numbers are leaves. A leaf is a node with no children, and an internal node has the parts it acts on as its children.
Think of the expression as a set of nested operations. The operation that is applied last sits near the top of the tree, and the smaller pieces it works on hang beneath it. A number has nothing beneath it, while an operator has the parts it acts on as its children. Seen this way, the grouping of an expression becomes visible. In the written form, parentheses are needed to show which part is computed first. In the tree, the shape already says so, and no parentheses are needed.
In this diagram, the plus node sits below the multiply node because the sum must be formed before it is multiplied by 2. The leaves, which hold the numbers 3, 4, and 2, have no children. If you read the tree from its leaves up to the root, you follow the order in which the operations must be carried out. This bottom-up reading is the key idea that makes the tree useful for generating instructions.
What Push and Apply Do
The source names two kinds of stack operations: push a number, and apply a + operation. A stack machine works with a stack of values. A push operation places a number onto the stack. An apply operation takes values from the stack, performs an operation on them, and leaves a result behind. A complete instruction list is simply a sequence of these operations, executed in order.
- 1Push a number: a value is placed on top of the stack. The stack grows by one value.
- 2Apply an operator such as +: the operation takes the values it needs from the stack, computes the result, and leaves that single result on the stack. The stack shrinks, because the operands are consumed and one result takes their place.
- 3Run the instructions in order: each apply can only run once the values it needs have already been pushed.
From Tree to Instructions
The next step is to connect the tree to the instructions. Use the same tree as before, for (3 + 4) multiplied by 2. Read it bottom-up. The deepest operations are formed first, so the first numbers to be pushed are the leaves under the plus node. Then the plus is applied. The 2 is pushed, and finally the multiply is applied. The list can be read straight off the tree's structure.
Building the instruction list for (3 + 4) multiplied by 2
Given the expression tree whose root is multiply, with a plus node holding 3 and 4 as its left subtree and the leaf 2 as its right subtree, produce a matching sequence of stack machine operations.
- 1Find the first leaf to visit
Start at the bottom left. The leaf 3 has no children, so it is pushed onto the stack first.
- 2Visit the sibling leaf
The plus node's other child is the leaf 4. Push 4. The stack now holds two values, 3 and 4.
- 3Apply the plus operator
The plus node has both of its children processed, so its operation can run. Apply + takes 3 and 4 from the stack and leaves 7.
- 4Push the right operand of the multiply
The multiply node's other child is the leaf 2. Push 2. The stack now holds 7 and 2.
- 5Apply the multiply operator
The root's two children are both done, so apply the multiply. It takes 7 and 2 and leaves 14, which is the value of the whole expression.
push 3, push 4, apply +, push 2, apply *. The final value left on the stack is 14.
Notice that the emitted list is a traversal of the tree in which each operator is written only after its two subtrees have been written. The plus is emitted only after 3 and 4, and the multiply only after the plus and the 2. Because a parent operator needs the results of both of its children, this is the only order in which the instructions can be correct. The list is a generated illustration of the idea, not a record of any particular program's output. It shows that each apply appears only after the operands it consumes.
Tracing the Stack Step by Step
The stack diagram below follows the same instruction list one step at a time. Watch what is on the stack after each instruction, and notice which values are removed and which are added.
At the apply + step, the two values 3 and 4 are removed and the single value 7 is left behind. At the apply * step, the values 7 and 2 are removed and 14 remains. The stack never holds more than two values at once in this run, and it ends with exactly one value, which is the result of the expression.
Why the Tree Helps Translation
A flat text such as (3 + 4) * 2 forces the reader to remember which parts are grouped and which operations come first. The tree removes that burden. The grouping is already recorded in the shape of the structure, so a translator can walk the tree and emit instructions without re-deriving precedence or parentheses from the text. The source also notes that SimpleParser3.java can both evaluate an expression and print the stack machine operations for evaluating that same expression, offering the value and the instructions side by side.
Mistakes Beginners Make
Common mistake Reading the tree from the root downward
What it looks likeEmitting apply * first because it is the top node
Why it failsThe root is applied last, not first. Its operands must already be on the stack before it can run.
Do this insteadRead the tree bottom-up, so that each operator comes after both of its children.
Common mistake Emitting an operator before its operands
What it looks likepush 3, apply +, push 4Why it failsApply + needs two values on the stack. Only one has been pushed, so there is nothing for it to combine.
Do this insteadPush both operands first, then apply the operator.
Common mistake Forgetting that apply consumes its operands
What it looks likeAfter push 3, push 4, apply +, assuming 3 and 4 are still on the stack
Why it failsApply takes the values from the stack and leaves one result, so 3 and 4 are gone.
Do this insteadAfter apply +, the stack holds only 7.
Common mistake Treating numbers as internal nodes instead of leaves
Hand-Building a Tree and Its Instructions
Draw the expression tree for (2 + 5) multiplied by 3, with the plus node below the multiply node. Then write the stack machine instructions that would compute it, in order. Check your answer by tracing the stack: the final value left on it should be 21.
Hints
- Start by making the plus node the left child of the multiply node, since the sum is formed first.
- Read the tree from the leaves upward, and remember that a push is needed for each number.
- After each apply, count how many values remain on the stack.
Key Takeaways
- An expression tree represents an expression with operators as internal nodes and numbers as leaves, and its shape records how the expression is grouped.
- Reading the tree bottom-up gives the order of computation, so each operator comes after the subtrees it acts on.
- A push instruction places a number on the stack, and an apply instruction takes values from the stack, computes a result, and leaves that result behind.
- A complete stack machine program is a sequence of push and apply instructions executed in order, and it can be generated directly from an expression tree.
- The tree removes the need to track precedence and parentheses separately, which makes it a useful intermediate form for translation.