Translating expressions and control flow, backpatching
Translating boolean expressions as jumping code with short-circuit evaluation, the fall-through label, if, if-else and while statements, and the single-pass method of backpatching with truelists, falselists, nextlists and marker nonterminals, with counting questions.
Why it exists
Boolean expressions are used in two ways: to compute a value (x = a < b), or, far more often, to decide where control goes (if (a < b) ...). In the second case there is no need to compute a boolean at all: the translator can emit jumps. This makes conditions cheap, and it allows short-circuit evaluation: in B1 || B2, once B1 is true the code never evaluates B2 (a semantic requirement in C). The two main techniques are jumping code with labels and backpatching for one-pass translation.
Prerequisites
You need the three-address instructions, in particular the jumps (goto L, if x relop y goto L, ifFalse) (three-address code).
Precise definitions
Short-circuit (jumping) code for conditions. The grammar . Each gets two labels: B.true, where control goes if is true, and B.false, where it goes if is false. The code of jumps to one of them. Rules:
| Production | Code |
|---|---|
code for and , then if E1.addr rel E2.addr goto B.true and goto B.false | |
B1.true = B.true; B1.false = newlabel() (the start of ); code: B1.code, label B1.false, B2.code; B2.true = B.true, B2.false = B.false | |
B1.false = B.false; B1.true = newlabel() (the start of ); code: B1.code, label B1.true, B2.code | |
exchange the labels: B1.true = B.false, B1.false = B.true | |
goto B.true | |
goto B.false |
Fall-through (the label fall). If one of the targets is the instruction that comes right after the test, no jump is needed. The special label fall means "continue with the next instruction". For the code is then: if both labels are real, if test goto B.true followed by goto B.false; if only B.true is real, just if test goto B.true; if only B.false is real, ifFalse test goto B.false; if both are fall, nothing. The ifFalse instruction is the three-address form of "jump if the test fails". This removes most of the redundant gotos.
Statements. Every statement has an inherited label S.next for the instruction that follows it.
| Statement | Translation |
|---|---|
B.true = fall; B.false = S1.next = S.next; code: B.code, S1.code | |
B.true = fall; B.false = newlabel(); S1.next = S2.next = S.next; code: B.code, S1.code, goto S.next, label B.false, S2.code | |
begin = newlabel(); B.true = fall; B.false = S.next; S1.next = begin; code: label begin, B.code, S1.code, goto begin | |
S1.next = newlabel(); S2.next = S.next; code: S1.code, label S1.next, S2.code |
Boolean values. When a boolean value is needed, as in x = a < b, the translator produces code that sets a temporary to 1 or 0 using the jumping code: if a < b goto L1, t = 0, goto L2, L1: t = 1, L2: x = t.
Backpatching. In the label method a statement must know S.next before its code is generated (an inherited attribute), which forces either two passes or symbolic labels that a later pass resolves. Backpatching generates the jump instructions with empty targets and fills them in later, in one pass with an LR parser. The attributes are lists of instruction numbers:
B.truelist: the jumps in the code of that must go to the code that follows when is true;B.falselistlikewise for false;S.nextlist: the jumps that must go to the instruction after .
Three functions work on lists: makelist(i) creates a list holding the instruction number i; merge(p1, p2) concatenates two lists; backpatch(p, i) sets the target of every jump on list p to i. A global counter nextinstr is the number of the next instruction to be emitted. Marker nonterminals record nextinstr at the right moment: , and emits an unconditional jump with an empty target.
| Production | Actions |
|---|---|
B.truelist = makelist(nextinstr); B.falselist = makelist(nextinstr + 1); gen('if' E1.addr rel E2.addr 'goto _'); gen('goto _') | |
backpatch(B1.falselist, M.instr); B.truelist = merge(B1.truelist, B2.truelist); B.falselist = B2.falselist | |
backpatch(B1.truelist, M.instr); B.truelist = B2.truelist; B.falselist = merge(B1.falselist, B2.falselist) | |
B.truelist = B1.falselist; B.falselist = B1.truelist | |
backpatch(B.truelist, M.instr); S.nextlist = merge(B.falselist, S1.nextlist) | |
backpatch(B.truelist, M1.instr); backpatch(B.falselist, M2.instr); S.nextlist = merge(S1.nextlist, N.nextlist, S2.nextlist) | |
backpatch(S1.nextlist, M1.instr); backpatch(B.truelist, M2.instr); S.nextlist = B.falselist; gen('goto' M1.instr) | |
backpatch(S1.nextlist, M.instr); S.nextlist = S2.nextlist |
At the end the nextlist of the whole program is backpatched to the first instruction after the code.
How it works
Jumping code for the condition in an if. Because the then-part follows the test, B.true is fall, and the code is shown instruction by instruction with the rule that produced it. The first test jumps forward to the body (L2) when true; the other two tests jump to the end (L1) when false.
Jumping code for a condition with || and &&: start
Computed by a script, not typed| label | three-address instruction | |
|---|---|---|
| 1 | ||
| 2 | ||
| 3 | ||
| 4 | ||
| 5 |
Step 0
Jumping code translates a condition into jumps: control falls through into the code when the condition holds, and jumps to the label after the statement when it does not. The special label fall means no jump instruction is needed.
A while loop: the label L1 marks the test, the test jumps out when false, and the body ends with goto L1. (The textbook translation of s = s + i includes the copy from a temporary.)
Jumping code for a while loop: start
Computed by a script, not typed| label | three-address instruction | |
|---|---|---|
| 1 | ||
| 2 | ||
| 3 | ||
| 4 | ||
| 5 | ||
| 6 | ||
| 7 |
Step 0
A while loop starts with a label for the test; the test jumps out of the loop when it fails, and the body ends with a jump back to the test.
The same if statement by backpatching. Instructions are numbered from 100. Every comparison emits two jumps, if ... goto _ and goto _, whose indices go into the truelist and falselist. When the parser reaches || it patches the falselist of the first condition to the start of the second (the marker), and so on. Watch the _ become numbers.
Backpatching: if (x < 100 || x > 200 && x != y) x = 0;: start
Computed by a script, not typed| address | instruction |
|---|---|
| 100 | |
| 101 | |
| 102 | |
| 103 | |
| 104 | |
| 105 | |
| 106 |
Step 0
With backpatching the jumps are emitted first with empty targets (shown as _) and recorded in lists; when the target becomes known, the lists are patched. Addresses start at 100. The truelist and falselist of a condition hold the jumps still to be completed.
And the loop by backpatching. The test is at 100; its false exit stays open until the whole loop is complete; the back jump at the end is patched to the start.
Backpatching: while (i < 10) s = s + i;: start
Computed by a script, not typed| address | instruction |
|---|---|
| 100 | |
| 101 | |
| 102 | |
| 103 | |
| 104 | |
| 105 | |
| 106 |
Step 0
The loop test begins at the first address; the false exit is patched at the end, the true exit to the start of the body, and the jump at the end of the body goes back to the test.
Worked examples
EX 1Jumping code for a simple if
Easyif (a < b) x = 1; With the fall-through convention: ifFalse a < b goto L1, x = 1, and L1: after it. 2 instructions and no goto. Without fall (both labels real) the same statement needs if a < b goto L2, goto L1, L2: x = 1, L1: — 3 instructions and one goto. By backpatching (instructions numbered from 100): 100: if a < b goto 102, 101: goto 103, 102: x = 1: 3 instructions, one goto.
EX 2if-else
Easyif (a < b) x = 1; else x = 2; gives ifFalse a < b goto L2, x = 1, goto L1, L2: x = 2, L1:. 4 instructions, one goto (it jumps over the else part). By backpatching: 100: if a < b goto 102, 101: goto 104, 102: x = 1, 103: goto 105, 104: x = 2: 5 instructions, 2 gotos.
EX 3Short-circuit evaluation: the second test is skipped
Mediumif (a < b || c < d) x = 1; gives if a < b goto L2, ifFalse c < d goto L1, L2: x = 1, L1:. If a < b is true the first instruction jumps directly to x = 1: the comparison c < d is not evaluated, which matters if it has a side effect or can fail (p != 0 || p->v > 0). By backpatching the code has 5 instructions and 2 gotos (the falselist of the first test is patched to 102, the start of the second test).
EX 4Count in a loop with &&
Mediumwhile (a < b && c < d) { x = x + 1; }. Jumping code: L1: ifFalse a < b goto L2, ifFalse c < d goto L2, t1 = x + 1, x = t1, goto L1, L2:: 5 instructions, 1 goto. By backpatching: 100: if a < b goto 102, 101: goto 107, 102: if c < d goto 104, 103: goto 107, 104: t1 = x + 1, 105: x = t1, 106: goto 100: 7 instructions, 3 gotos, and the instruction after the loop is 107, which is the target of the two exits (the falselist of the whole condition, patched at the end of the statement).
EX 5What do the lists contain?
GATE levelFor starting at instruction 100: the first comparison emits 100: if a < b goto _ and 101: goto _, with B1.truelist = {100}, B1.falselist = {101}. The marker records 102. The second emits 102: if c < d goto _, 103: goto _ with B2.truelist = {102}, B2.falselist = {103}. The rule patches 101 to 102, and sets B.truelist = {100, 102}, B.falselist = {103}. Questions of this type ask for the truelist or falselist or for the state of the code after a given step; the method is always the rule table above.
Cheat box
Cheat box
- Conditions become jumps: control reaches
B.trueorB.false.||and&&short-circuit: the second operand is evaluated only if needed. fallmeans "next instruction": it removes redundantgotos;ifFalsejumps when the test fails.if: B.true = fall, B.false = S.next.if-else: extragoto S.nextafter the then part.while: label at the test,goto beginat the end.- Backpatching: emit jumps with empty targets, record them in
truelist,falselist,nextlist;makelist,merge,backpatch; markers (recordnextinstr) and (emit a jump). ||: backpatch B1.falselist to the start of B2;&&: backpatch B1.truelist to the start of B2.- Every comparison emits two instructions in backpatching (a conditional jump and a goto).
Traps and GATE patterns
Connections
Across subjects
No cross-subject links yet.
The instructions used here are those of three-address code; the translation rules are a translation scheme built on the expression translation of intermediate code generation. The jump instructions create the leaders from which basic blocks and the flow graph are built.
PYQs
1 previous year question from your book. I re-solved each one myself (0 by running or simulating, 1 by reasoning only); the book's key is shown next to my answer. All PYQs
Consider the following statements about the use of backpatching in a compiler for intermediate code generation: (I) Backpatching can be used to generate code for Boolean expressions in one pass. (II) Backpatching can be used to generate code for flow-of-control statements in one pass. Which ONE of the following options is CORRECT?
- (a)Only (I) is correct.
- (b)Only (II) is correct.
- (c)Both (I) and (II) are correct.
- (d)Neither (I) nor (II) is correct. COMPILER DESIGN
Self-check
Question 1
How many instructions has the jumping code of if (a < b) x = 1; else x = 2; (fall-through convention)?
Show answerHide
4: ifFalse a < b goto L2, x = 1, goto L1, x = 2 (with the labels L2 and L1 not counted).
Question 2
In backpatching, what do makelist(i), merge(p1, p2) and backpatch(p, i) do?
Show answerHide
makelist(i): a new list with the instruction number i. merge: the union of the two lists. backpatch(p, i): fill i as the target of every jump on list p.
Question 3
For which list of is backpatched, and to what?
Show answerHide
B1.truelist, to M.instr (the start of ); the falselists are merged.
Question 4
Why can a one-pass translator not simply emit the target labels in a while statement?
Show answerHide
The target after the loop (S.next) is not known until the whole loop has been generated; backpatching leaves the jump incomplete and fills it in later.
Revision card
One-screen revision
- Conditions as jumps with
B.trueandB.false;||and&&short-circuit;fallremoves redundant gotos. - if: 2 instructions for
if (a < b) x = 1;; if-else adds a goto; while adds a goto back. - Backpatching: lists +
makelist,merge,backpatch, markers M and N; comparison = 2 jumps. ||: patch falselist of B1 to start of B2;&&: patch truelist.
References
- ·Aho, Lam, Sethi, Ullman, Compilers: Principles, Techniques, and Tools (2nd edition), Chapter 6 Intermediate-Code Generation (6.6 control flow: boolean expressions, short-circuit code, flow-of-control statements, avoiding redundant gotos; 6.7 backpatching)
Verification
Both translation methods are implemented in scripts/cd_icg.py (jumping code with labels and the fall convention, and backpatching with truelist, falselist and nextlist) and checked in scripts/enum-checks/cd_icg.py: for 1500 random programs with nested if, if-else, while, &&, || and ! the generated code is executed and gives the same variables, arrays and output as the source, and every jump is patched to a valid address. The instruction and goto counts quoted for the small statements were computed by the same code. Different books differ in the exact code produced (redundant gotos, label placement), so counts depend on the convention; the page states the conventions used. SECOND PASS (2026-11-02, done by the assistant, not a human check): every Self-check question was solved before the printed answer was read and all agreed; the definitions, worked examples, cheat box and traps were read claim by claim and the numbers re-derived by hand or by a small script (token counts, FIRST and FOLLOW sets, LL(1) tables and moves, LR item sets, state counts and parses, operator-precedence values, attribute evaluation and printing schemes, activation-record counts and access links, parameter-passing results, three-address code, jumping and backpatched code, leaders and blocks, value numbering and DAGs, gen/kill and data flow sets, Sethi-Ullman labels and live ranges); long C programs were not re-read line by line (they are compiled and compared by npm run verify:c, and their printed outputs were checked against the prose); tables and animations are machine output and were read, not re-run; No other defect found. Status raised to self-checked; verified needs a textbook or human check.
last verified: never
My notes (saved in this browser)