Concepts / Stack Machines and Machine Language

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.

  • Programming

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?

  • One

  • Two

  • Three

Reveal answer
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

Definition

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.

*applied last+formed first324left operandright operandleft operandright operand
Which node is the parent of which, and why does the operator sit above its operands instead of between them?

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.

  1. 1
    Push a number: a value is placed on top of the stack. The stack grows by one value.
  2. 2
    Apply 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.
  3. 3
    Run 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.

Worked example

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.

  1. 1
    Find the first leaf to visit

    Start at the bottom left. The leaf 3 has no children, so it is pushed onto the stack first.

  2. 2
    Visit the sibling leaf

    The plus node's other child is the leaf 4. Push 4. The stack now holds two values, 3 and 4.

  3. 3
    Apply 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.

  4. 4
    Push 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.

  5. 5
    Apply 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.

Result

push 3, push 4, apply +, push 2, apply *. The final value left on the stack is 14.

3emit push 34emit push 4+emit apply +2emit push 2*emit apply *thenthenthenthen
In what order are the leaves and operators emitted, and why must both subtrees be processed before their parent operator?

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.

startstack: emptypush 3stack: 3push 4stack: 3, 4apply +stack: 7push 2stack: 7, 2apply *stack: 14nextnextnextnextnext
What is on the stack after each instruction, and which values are removed or added at each step?

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 like

    Emitting apply * first because it is the top node

    Why it fails

    The root is applied last, not first. Its operands must already be on the stack before it can run.

    Do this instead

    Read 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 like
    push 3, apply +, push 4
    Why it fails

    Apply + needs two values on the stack. Only one has been pushed, so there is nothing for it to combine.

    Do this instead

    Push both operands first, then apply the operator.

  • Common mistake

    Forgetting that apply consumes its operands

    What it looks like

    After push 3, push 4, apply +, assuming 3 and 4 are still on the stack

    Why it fails

    Apply takes the values from the stack and leaves one result, so 3 and 4 are gone.

    Do this instead

    After apply +, the stack holds only 7.

  • Common mistake

    Treating numbers as internal nodes instead of leaves

Hand-Building a Tree and Its Instructions

MEDIUM

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.