Section 7 · Revision

Compiler Design formula sheet

One-page revision of scanning, FIRST/FOLLOW and LL/LR parsing, attribute grammars, runtime storage, three-address code and data flow analysis.

Full notes Section test

Lexical analysis

  • Token == class (id, num); lexeme == matched text; pattern == regex for the lexemes.
  • Pipeline: regex →\to NFA (Thompson) →\to DFA (subset construction, up to 2n2^n states) →\to minimal DFA →\to table-driven scanner.
  • Thompson counts: symbol =2= 2; N(r∣s)=N(r)+N(s)+2N(r \mid s) = N(r) + N(s) + 2; N(rs)=N(r)+N(s)−1N(rs) = N(r) + N(s) - 1; N(r∗)=N(r)+2N(r^*) = N(r) + 2. (a|b)*abb gives 11.
  • Longest match first, then the pattern listed first: ifx is an identifier, if the keyword.
  • Keywords: preload into the symbol table, scan with the identifier pattern.
  • Sentinel eof per buffer half: one test per character instead of two.
  • Lexical errors: illegal character, unterminated string or comment. Missing ; is syntactic; undeclared name is semantic.
  • Token counting in C: comments and whitespace give 0; a string literal is 1; >=, ++, -> are 1 each; a+++b is a ++ + b; /* opens a comment that ends at the first */.

Parsing

FIRST and FOLLOW

Rule Effect
X→Y1Y2…X \to Y_1 Y_2 \dots add FIRST(Y1)−{ε}\text{FIRST}(Y_1) - \{\varepsilon\}; go on to Y2Y_2 only if Y1⇒∗εY_1 \Rightarrow^* \varepsilon
all YiY_i derive ε\varepsilon ε∈FIRST(X)\varepsilon \in \text{FIRST}(X)
start symbol $∈FOLLOW(S)\text{\textdollar} \in \text{FOLLOW}(S)
A→αBβA \to \alpha B \beta FIRST(β)−{ε}⊆FOLLOW(B)\text{FIRST}(\beta) - \{\varepsilon\} \subseteq \text{FOLLOW}(B)
A→αBA \to \alpha B, or β⇒∗ε\beta \Rightarrow^* \varepsilon FOLLOW(A)⊆FOLLOW(B)\text{FOLLOW}(A) \subseteq \text{FOLLOW}(B)

LL(1)

  • Table: put A→αA \to \alpha in M[A,a]M[A, a] for each a∈FIRST(α)a \in \text{FIRST}(\alpha); if ε∈FIRST(α)\varepsilon \in \text{FIRST}(\alpha), also in M[A,b]M[A, b] for each b∈FOLLOW(A)b \in \text{FOLLOW}(A) (including $\text{\textdollar}).
  • LL(1) iff no cell has two productions. For A→α∣βA \to \alpha \mid \beta: FIRST(α)∩FIRST(β)=∅\text{FIRST}(\alpha) \cap \text{FIRST}(\beta) = \emptyset, at most one derives ε\varepsilon, and if β⇒∗ε\beta \Rightarrow^* \varepsilon then FIRST(α)∩FOLLOW(A)=∅\text{FIRST}(\alpha) \cap \text{FOLLOW}(A) = \emptyset.
  • Never LL(1): left recursive, ambiguous, or not left factored.
  • Left recursion: A→Aα∣βA \to A\alpha \mid \beta becomes A→βA′A \to \beta A', A′→αA′∣εA' \to \alpha A' \mid \varepsilon. Indirect: order nonterminals, substitute earlier ones, then remove immediate recursion.
  • Left factoring: A→αβ1∣αβ2A \to \alpha\beta_1 \mid \alpha\beta_2 becomes A→αA′A \to \alpha A', A′→β1∣β2A' \to \beta_1 \mid \beta_2. Dangling else still conflicts.

LR family

Fact Value
Grammar classes LR(0) ⊂\subset SLR(1) ⊂\subset LALR(1) ⊂\subset CLR(1)
State counts LR(0) == SLR == LALR ≤\le CLR
LR(0) items of A→X1…XkA \to X_1 \dots X_k k+1k + 1
Every LL(1) grammar is LR(1), but not always LALR(1)
Ambiguous grammar never LL(k) or LR(k)
LR(1) languages exactly the deterministic CFLs
Parser Reduce A→α⋅A \to \alpha\cdot on Conflict appears when
LR(0) every terminal complete item plus any other item
SLR(1) FOLLOW(A)\text{FOLLOW}(A) shift on a∈FOLLOW(A)a \in \text{FOLLOW}(A), or FOLLOW sets overlap
CLR(1) item lookahead lookaheads collide in one state
LALR(1) union of merged lookaheads merging can add reduce-reduce, never shift-reduce
  • Bottom-up == reverse rightmost derivation; top-down == leftmost.
  • Handle: right side of the last production of the rightmost derivation. Viable prefixes == paths in the LR(0) DFA (a regular set).
  • On a valid input: shifts == tokens; reductions == interior parse-tree nodes.
  • Operator grammar: no ε\varepsilon-production, no adjacent nonterminals. +⋖∗+ \lessdot *, ∗⋗+* \gtrdot +, left associative +⋗++ \gtrdot +, right associative ↑⋖↑\uparrow \lessdot \uparrow, id⋗\text{id} \gtrdot any operator.
  • Yacc: later %left/%right lines bind tighter; shift-reduce defaults to shift; reduce-reduce to the earlier production.

Syntax-directed translation

Kind Attributes Evaluation
S-attributed synthesized only postorder; during LR parsing on a value stack
L-attributed inherited from parent's inherited attrs and LEFT siblings only one left-to-right depth-first pass; LL parsing, or LR with markers
  • Every S-attributed SDD is L-attributed. A dependency cycle means no evaluation order.
  • In A→XBYA \to X B Y, BB's inherited attribute may use AA's inherited attributes and XX, never YY.
  • Marker M→εM \to \varepsilon replaces an embedded action for bottom-up parsing.
  • Value stack: reducing A→X1…XrA \to X_1 \dots X_r, XiX_i is at top−r+i\text{top} - r + i.
  • End-of-production actions print in postorder (infix to postfix). Embedded actions run as leaves in a left-to-right depth-first walk.
  • Left recursion groups left, right recursion groups right; lower in the grammar binds tighter.
  • Syntax tree nodes == operators ++ operand occurrences; a DAG shares repeats.

Runtime environments

Activation record field Purpose
Parameters, return value communication with caller
Control (dynamic) link caller's record
Access (static) link lexically enclosing procedure's record
Saved status return address, registers
Locals, temporaries callee data
  • Non-local at nesting depth dvd_v from depth dd: follow d−dvd - d_v access links.
  • Caller at depth npn_p calls procedure at depth nxn_x: if nx=np+1n_x = n_p + 1, access link == caller; if nx≤npn_x \le n_p, follow np−nx+1n_p - n_x + 1 links from the caller.
  • Display: display[d] points to the latest record at depth dd; constant-time access.
  • Static allocation cannot support recursion; returning a local's address gives a dangling pointer; closures that outlive the call need the heap.
  • Static scope: nearest enclosing declaration in the text. Dynamic scope: most recent active binding.
Passing Behaviour
Value copy in; callee cannot change actual
Reference address passed; aliasing (p(a, a)) visible
Value-result copy in, copy back on return (order of copy-back matters)
Name argument re-evaluated at every use (swap(i, a[i]) fails)
Need evaluated at first use, then cached

fib with base n≤1n \le 1: C(n)=1+C(n−1)+C(n−2)=2Fn+1−1C(n) = 1 + C(n-1) + C(n-2) = 2F_{n+1} - 1 calls (F1=F2=1F_1 = F_2 = 1; 15 for n=5n = 5); stack depth nn.

Intermediate code generation

Form Fields Note
Quadruple op, arg1, arg2, result easy to move; needs temporaries in symbol table
Triple op, arg1, arg2 result named by position; moving breaks references
Indirect triple triples plus a list of pointers reorder by permuting the list
  • Row-major A[n1][n2], width ww, lower bounds l1,l2l_1, l_2: base+((i−l1)n2+(j−l2))w\text{base} + ((i - l_1) n_2 + (j - l_2)) w. Column-major: base+((j−l2)n1+(i−l1))w\text{base} + ((j - l_2) n_1 + (i - l_1)) w.
  • Leaders: first instruction, every jump target, every instruction right after a jump. Block == leader up to the next leader.
  • Flow graph edges: jump target, and fall-through unless the block ends in an unconditional jump or return.
  • dd dominates nn: every path from entry to nn passes dd. Back edge n→hn \to h with hh dominating nn. Natural loop =h= h plus nodes that reach nn without passing hh.
Backpatching rule Actions
B -> B1 or M B2 patch B1B_1.falselist to MM; true == merge(B1B_1.t, B2B_2.t); false =B2= B_2.f
B -> B1 and M B2 patch B1B_1.truelist to MM; true =B2= B_2.t; false == merge(B1B_1.f, B2B_2.f)
B -> not B1 swap truelist and falselist
x relop y emit if x relop y goto _ and goto _; lists {n}\{n\}, {n+1}\{n+1\}
while M1 B do M2 S1 patch S1S_1.next to M1M_1, BB.t to M2M_2; next =B= B.f; emit goto M1M_1
  • SSA: each name assigned once; ϕ\phi at the iterated dominance frontier of the blocks that assign the variable; ϕ\phi picks the value by incoming edge.

Local optimisation and data flow analysis

Analysis Direction Meet Equation Initial
Reaching definitions forward ∪\cup OUT=gen∪(IN−kill)\text{OUT} = \text{gen} \cup (\text{IN} - \text{kill}) ∅\emptyset
Available expressions forward ∩\cap OUT=e_gen∪(IN−e_kill)\text{OUT} = \text{e\_gen} \cup (\text{IN} - \text{e\_kill}) entry ∅\emptyset, others all
Live variables backward ∪\cup IN=use∪(OUT−def)\text{IN} = \text{use} \cup (\text{OUT} - \text{def}) ∅\emptyset
Very busy expressions backward ∩\cap IN=use∪(OUT−kill)\text{IN} = \text{use} \cup (\text{OUT} - \text{kill}) exit ∅\emptyset, others all
Constant propagation forward lattice meet evaluate statement UNDEF
  • Constant lattice: UNDEF ∧ v=v\wedge\, v = v; c∧c=cc \wedge c = c; c1∧c2=c_1 \wedge c_2 = NAC for c1≠c2c_1 \ne c_2; NAC ∧ v=\wedge\, v = NAC.
  • Liveness →\to dead code, registers (minimum without spills == most values live at once); available expressions →\to global CSE; reaching definitions →\to constant propagation, use-def chains.
Optimisation Scope
Constant folding, algebraic simplification, local CSE (DAG), copy propagation, dead code in a block local
Global CSE, global constant propagation global (data flow)
Loop-invariant code motion, strength reduction, induction variable elimination, unrolling loop
Redundant load/store, jump-to-jump, unreachable code peephole
  • Hoisting x = y op z needs: operands invariant; block dominates all exits (or xx dead after the loop); xx assigned once in the loop; uses of xx in the loop reached only by it.
  • Strength reduction: t = 4 * i becomes t = t + 4 after i = i + 1, with tt set before the loop.
  • Copies left by copy propagation are removed by a separate dead code pass; iterate until nothing changes.