Differentiate Between S-attributed SDT and L-attributed SDT (With Examples)
Syntax-directed translation (SDT) associates semantic actions with grammar productions, using attributes on grammar symbols. Two important restrictions on attribute dependencies are S-attributed and L-attributed forms, which determine whether translation can be performed in a single left-to-right pass with a parser.
In an S-attributed SDT, all inherited attributes (if any) of a production’s symbols may depend only on:
- attributes of the production head (the left-hand side nonterminal), and
- attributes of symbols to the left in the production’s right-hand side (including the case where a symbol’s inherited attribute depends on multiple earlier siblings).
In an L-attributed SDT, inherited attributes have an even stricter dependency: each inherited attribute of a symbol may depend only on:
- attributes of the immediately preceding grammar symbols (through “left-to-right” accessibility), and
- attributes of the production head, but still only in a way that enables left-to-right evaluation.
A key relationship (often stated in compiler-construction texts) is that every L-attributed SDT is S-attributed, but not every S-attributed SDT is L-attributed—because S-attributed allows some dependency patterns that break left-to-right evaluation.
Syntax-Directed Translation: L-attributed vs S-attributed (concept overview)
Core Definitions and Dependency Rules
keyword
keyword
keyword
keyword
We consider a production like:
Let:
- be the head (left-hand side),
- be the body (right-hand side symbols).
- Each symbol may carry inherited attributes (typically written as ) and synthesized attributes (typically ).
S-attributed SDT
For any production , the SDT is S-attributed if:
- Any inherited attribute of depends only on:
- attributes of (the head), and
- attributes of symbols (symbols to the left of ).
- Any synthesized attribute can depend on the children’s attributes in the usual upward way (there’s no special left-to-right restriction on synthesized attributes; the main restriction is about inherited dependencies).
L-attributed SDT
For the same production, the SDT is L-attributed if:
- The inherited attributes can be evaluated in a left-to-right manner such that when you reach you already know all values required to compute ’s inherited attributes.
- Formally, inherited dependencies are constrained so that can use information that has been computed by the parser so far (from the left side and the head), enabling a single-pass evaluation strategy (typical with LR/LL parsing variants under constraints).
Practical intuition
If your inherited attribute dependencies can be satisfied while scanning the RHS from left to right, you’re likely in L-attributed territory. If dependencies only require “some left context” but not necessarily the immediate left-to-right computability, you may still be S-attributed.
How to test if an SDT is S-attributed vs L-attributed (dependency check)
- 1Step 1
List every inherited attribute dependency as “Xk.attr depends on (set of attributes)”.
- 2Step 2
Verify every inherited attribute of Xi depends only on attributes of A and attributes of X1…X(i−1). If any inherited dependency uses attributes of X(i+1)…Xn, it violates S-attributed.
- 3Step 3
For each inherited attribute of Xi, ensure the required attributes are available when Xi is processed in a left-to-right traversal. If an inherited attribute needs info that can only be computed from a symbol to the right, then it’s not L-attributed (even if it’s still S-attributed).
- 4Step 4
If you can show an evaluation ordering where LTR fails (because an inherited attribute needs a future value), then the SDT is not L-attributed; otherwise it is.
Example 1: An L-attributed SDT (therefore also S-attributed)
Consider building the string representation with parentheses removal, or more standardly: computing type checking or constant folding with inherited context from the left.
A classic, simple L-attributed example is computing the prefix-based inherited context such as “the value of a variable’s scope to the left” in a left-to-right grammar. Here’s a compact SDT pattern for computing an expression’s value under operator precedence using synthesized attributes and a left-to-right inherited setup for something like an accumulated result.
Example grammar (toy)
Assume a grammar for left-associative addition:
Use synthesized attributes for (common and doesn’t violate either restriction). To illustrate inheritance, consider:
where carries a starting inherited value and uses it.
SDT sketch (L-attributed)
Let:
- Each nonterminal carry synthesized attribute
val. - For an inherited attribute, let compute something that must be available for the next symbol.
For production:
Let:
- has no inherited attribute,
- depends only on (head) and attributes from (left sibling).
Because ’s inherited information depends only on values known after processing (left-to-right), this is consistent with L-attributed constraints.
Dependency reasoning
- Inherited for uses only: head and left symbol .
- Therefore it is allowed for S-attributed, and importantly computable left-to-right ⇒ L-attributed.
Example 2: S-attributed but NOT L-attributed
To show S-attributed but not L-attributed, we need an SDT where:
- inherited attributes satisfy the “only head + left symbols” rule (so it is S-attributed),
- but the particular dependency requires an evaluation order that cannot be produced by left-to-right attribute evaluation.
Key idea
L-attributed SDTs require that when visiting left-to-right, all attributes needed for are already known. If an inherited attribute of depends on a value that, although ultimately coming from the left side, is only computable using information that would require completing evaluation of later parts, then L-attributed fails but S-attributed might still hold structurally.
Concrete SDT pattern (conceptual)
Consider a grammar production:
Define:
- has synthesized attribute
- has inherited attribute
- provides some information needed to compute (but is synthesized of that depends on through its internal subtree evaluation).
Now impose:
- depends on and (head + left sibling)
So it remains within S-attributed rules: depends on head and left symbol . But: - if itself requires completion of ’s subtree (even though is left of ), then when parsing left-to-right you cannot compute at the moment you reach —because is not yet available.
This yields S-attributed (dependency graph respects head+left only) but violates the left-to-right evaluation requirement of L-attributed.
Why this breaks L-attributed evaluation
- In a left-to-right evaluation, by the time you reach , you would need .
- But cannot be computed until after evaluating ’s subtree, creating a “future dependency”.
- L-attributed SDTs are designed to prevent exactly this sort of computability issue for inherited attributes.
Summary of Differences (What to remember)
keyword
keyword
keyword
keyword
| Aspect | S-attributed SDT | L-attributed SDT |
|---|---|---|
| Inherited dependencies | Only depend on head and symbols left of | Same spirit, but restricted to ensure left-to-right computability |
| Evaluation strategy | May require more flexible evaluation order | Supports evaluation in left-to-right manner |
| Expressive power | More general than L-attributed | Strict subset of S-attributed |
| Relationship | Can include cases not computable in one left-to-right pass | Every L-attributed SDT is S-attributed |
Common Exam/Practice Questions
Quick Check: S-attributed vs L-attributed
Expressive Constraints (Qualitative)
Higher indicates stricter left-to-right constraint (not runtime cost).
Knowledge Check
Which dependency restriction defines an S-attributed SDT?