14.5. Backpatching

The scheme of the previous page has a problem: parser actions need to make a decision before the information needed to make the decision is available. For example, look at the rules for if-then and if-then-else.

S → if
  B.true = newLabel();
  B.false = newLabel();
( B )
  gen(label B.true);
  S1.next = S2.next = S.next;
S1 else
  gen(goto S.next);
  gen(label B.false);
S2
S → if
  B.true = newLabel();
  B.false = S1.next = S.next
( B )
  gen(label B.true);
S1

For if-then-else, B.false should be a new label. For if-then, B.false should be S.next.

It seems to be the inherited attributes that are causing trouble. So let's replace them by synthesized attributes.


Attributes B.truelist and B.falselist

Previously, a boolean expression B needed inherited attributes B.true and B.false so that it would know what to put in branch instructions.

Let's instead ask a boolean expression B to generate incomplete branch instructions without any labels in them.

Recall that 3-address codes are stored in an array for processing later. Synthesized attributes B.truelist and B.falselist are lists of indices of 3-address codes in that array.

B.truelist is a list of indices of 3-address codes that should be patched to hold the label to which B should jump when it is true, once such information becomes available.

B.falselist is similar, but for 3-addressed codes to be patched with the label where B should jump when it is false.


Attributes S.nextlist

Similarly, recall that the previous approach used inherited S.next, where S is a statement. That is replaced by synthesized attribute S.nextlist, a list of 3-address code indices that should be patched with a label at the end of S.


Attributes optElse.elselabel and optElse.endlabel

We will handle else using a nonterminal, optElse, that can generate ε or else S.

Instructions that vary depending on whether else is present are generated by optElse. It needs to say the labels that it used.

  1. Attribute optElse.elselabel is where an if-statement should jump when its condition is false.

  2. Attribute optElse.endlabel is a label at the end of the else part.


Productions and actions

To do this, we need gen to return the index where it has put an instruction.

We also need a function, backpatch(L, lbl) that takes a list of indices L and a label lbl, and stores lbl into each instruction referred to by an index in L.

Production and action
B → E1 == E2
  i = gen(If E1.addr ≠ E2.addr goto 0);
  j = gen(goto 0);
  B.falselist = [i]; (singleton list i)
  B.truelist = [j];
B → E1 < E2
  i = gen(If E1.addr ≥ E2.addr goto 0);
  j = gen(goto 0);
  B.falselist = [i]; (singleton list i)
  B.truelist = [j];
B → true
  i = gen(goto 0);
  B.falselist = []; (empty list)
  B.truelist = [i];
B → false
  i =gen(goto 0);
  B.falselist = [i];
  B.truelist = [];
B →  B1 and
  L1 = newLabel();
  gen(label L1);
B2
  backpatch(B1.truelist, L1);
  B.falselist = B1.falselist ++ B2.falselist
  B.truelist = B2.truelist
B →  B1
or
  L1 = newLabel();
  gen(label L1);
B2
  backpatch(B1.falselist, L1);
  B.falselist = B2.falselist
  B.truelist = B1.truelist ++ B2.truelist;
B →  not B1
  B.falselist = B1.truelist;
  B.truelist = B1.falselist;
S → id = E
  gen(id.name = E.addr);   S.nextlist = [];
S → { SL }
  S.nextlist = SL.nextlist;
SL → SL1
  if(SL1.nextlist != []) {
    L1 = newLabel();
    gen(label L1);
    backpatch(SL1.nextlist, L1);
  }
S
  SL.nextlist = S.nextlist;
SL → ε
  SL.nextlist = [];
S → if ( B )
  L1 = newLabel();
  backpatch(B.truelist, L1);
  gen(label L1);
S1 optElse
  backpatch(B.falselist, optElse.elselabel);
  backpatch(S1.nextlist, optElse.endlabel)
optElse → ε
  L2 = newLabel();
  gen(label L2);
  optElse.elselabel = L2;
  optElse.endlabel = L2;
optElse → else
  L2 = newLabel();
  L3 = newLabel();
  gen(goto L3);
  gen(label L2);
S
  gen(label L3);
  backpatch(S.nextlist, L3);
  optElse.endlabel = L3;
  optElse.elselabel = L2;
S → while
  L1 = newLabel();
  L2 = newLabel();
  L3 = newLabel();
  gen(label L1)
( B )
  gen(label L2);
S1
  gen(goto L1);
  gen(label L3);
  backpatch(B.truelist, L2);
  backpatch(B.falselist, L3);
  backpatch(S1.nextlist, L1);