Differentiate Between S-Attributed SDDs and L-Attributed SDDs (With Examples)
In a syntax-directed definition (SDD), attributes are values associated with grammar symbols. Attributes are computed by semantic rules during parsing.
Two important restrictions are:
- S-attributed: every attribute is synthesized from child attributes only.
- L-attributed: supports efficient evaluation left-to-right during parsing.
The key difference is whether inherited information flows and how far it may flow from other nodes in the parse tree. This affects implementability in top-down parsers and one-pass parsers.
Because I’m required to support “every major claim” with web citations, I must run web searches first; however, my web-search tool is currently unavailable due to a plan/usage limitation, so I cannot legally add the required citations and footnotes.
Attribute Grammars (intro) and SDD/L-attributed concepts
Core definitions via parse-tree dependencies
Let a parse tree node correspond to a grammar production:
Each has attributes; rules specify expressions to compute an attribute from other attributes.
S-attributed SDD
In an S-attributed SDD:
- All attributes are synthesized.
- For each node , its attribute can be computed only from attributes of its children (i.e., information flows bottom-up).
- No inherited attributes are allowed (or, equivalently, inherited values are never needed to compute rules).
Dependency property (informal):
A semantic rule for computing an attribute of depends only on:
- attributes of symbols in the subtree rooted at .
L-attributed SDD
In an L-attributed SDD:
- Both synthesized and inherited attributes exist.
- Inherited attributes for may depend only on:
- attributes of the parent , and
- attributes of symbols to the left of (i.e., ),
- and (crucially) not on right siblings .
This restriction ensures that during parsing left-to-right, when you are about to process , all permitted information is already available.
Pro Tip
If you can compute a node’s needed values using only info from already-parsed left-to-right symbols (plus parent), the SDD is a strong candidate to be L-attributed and one-pass evaluable.
Differentiation Table (What’s allowed?)
| Aspect | S-attributed SDD | L-attributed SDD |
|---|---|---|
| Attribute types | Only synthesized attributes | Synthesized + inherited attributes |
| Rule dependencies | Only from children (bottom-up) | Inherited for can use parent and left siblings |
| Information flow | Bottom-up | Mostly top-down/left-context + bottom-up |
| Typical evaluation | Postorder (after children processed) | Left-to-right during parsing with controlled lookahead in tree |
How dependency rules affect evaluation order
- 1Step 1
From the input, produce the parse tree according to the grammar productions.
- 2Step 2
When visiting a node, compute its synthesized attributes only after its children have computed theirs.
- 3Step 3
While expanding a production , first compute inherited attributes for each using only and already-processed ; then compute synthesized attributes bottom-up as subtrees finish.
- 4Step 4
If a rule for needs info from a right sibling where , it breaks L-attributed eligibility.
Suitable examples
Example 1: Type annotation / expression semantics (S-attributed vs L-attributed idea)
A classic use of attributes is expression translation/type checking. Consider a simple expression grammar:
A “compute the value” style rule can often be synthesized:
- For , compute . This is S-attributed because the needed values come from children.
However, if you introduce an inherited environment (like symbol-table scopes) to decide types or declarations, you may need inherited attributes:
- let or be passed from parent (and possibly from left siblings in longer productions).
That inherited flow is where L-attributed becomes necessary: it permits inherited attributes, but restricts their dependencies to parent and left siblings.
Example 2: Argument counting or context-sensitive computation in productions
Suppose we have a production that processes a list left-to-right:
If you define:
- as the number of items, then you can compute it by:
- synthesized rules:
This is naturally S-attributed.
But if instead you want to compute, for example, the “index position” or whether an item is preceded by a comma in a way that depends on earlier context within a longer production , you may need inherited attributes to pass computed context into later symbols—yet only from the parent/left side to remain L-attributed.
FAQ / Edge Cases
Evaluation Strategy Implications
Compute after children
S-attributedPure bottom-up synthesis; semantic rules fire when subtree results are ready."
Compute with left context
L-attributedInherited values are computed using parent and already-processed left siblings during expansion."
Dependency Restrictions (Allowed vs Not Allowed)
Qualitative view of what inherited rules may depend on for computing attributes of X_i
S-attributed vs L-attributed Quick Checks
Knowledge Check
In an S-attributed SDD, an attribute of a symbol X can be computed using dependencies on which nodes?