Differentiate between S-attribute SDT and L-attribute SDT (with Examples)

Differentiate between S-attribute SDT and L-attribute SDT (with Examples)

Verified Sources
Nov 3, 2026

Syntax-directed translation (SDT) associates semantic rules with productions of a grammar, using attributes to compute semantic information (e.g., types, intermediate code). In attribute grammars, attributes are typically synthesized from children upward or inherited from a parent or left siblings downward. Two important classes—S-attributed SDT and L-attributed SDT—impose restrictions that make evaluation efficient and often compatible with parsing strategies.

Below, we formalize the constraints, then contrast them with concrete examples (expression attributes, type checking, and code generation), including a “why it works” evaluation order view using the parse tree.

[VideoBlock] requires a direct URL from tool results; however, web search is currently unavailable in this environment.

Core dependency rules (the whole distinction)

  1. 1
    Step 1

    Mark attributes as synthesized or inherited.

  2. 2
    Step 2

    For each production, every semantic rule may use only attributes from the production’s child nodes—no inherited attributes may be used to compute synthesized values.

  3. 3
    Step 3

    For each production, an inherited attribute of a node may depend on the inherited attributes of the parent and on attributes of symbols to the left in that production (i.e., left siblings).

  4. 4
    Step 4

    "S-attributed typically evaluates using a bottom-up order; L-attributed enables evaluation in a left-to-right traversal consistent with the parsing order."

Key learning terms

  • Attribute grammar: SDT framework with attribute rules.
  • Synthesized attribute: flows upward.
  • Inherited attribute: flows sideways/downward.
  • Evaluation order: required by dependency constraints.

S-attribute SDT (S-attributed): what it means

In an S-attributed (syntax-directed) translation / attribute grammar, the semantic rules attached to each production are restricted so that all values needed to compute attributes for a node come only from its children (i.e., you do not use inherited attributes in a way that depends on parent or left-context).

Practical consequence

  • The translation can be done bottom-up (post-order style on the parse tree).
  • You typically compute synthesized results like expression type, numeric value, or generated code for a subtree once all children are known.

Typical examples suited for S-attributed SDT

  • Type synthesis:
    • For production E→E + TE \to E\ +\ T, synthesize E.typeE.type from E.left.typeE.left.type and T.typeT.type.
  • Constant folding:
    • E.valueE.value computed from child numeric values.

[CalloutBlock]
type: "tip" title: "Pro Tip (S-attributed mindset)" content: "If your semantic needs only “bottom-up info” (children determine everything), you can usually model it as S-attributed."


L-attribute SDT (L-attributed): what it means

An L-attributed attribute grammar is more general: it allows inherited attributes, but still enforces a disciplined dependency structure.

Constraint (the essential rule)

For a production

A→X1 X2 … XnA \to X_1\ X_2\ \dots\ X_n
  • Each semantic rule may assign attributes for any XiX_i.
  • Inherited attributes of XiX_i can depend on:
    1. attributes of the parent AA, and
    2. attributes of symbols to the left: X1,…,Xi−1X_1, \dots, X_{i-1}.
  • Crucially, inherited attributes cannot depend on information from Xi+1,…,XnX_{i+1}, \dots, X_n (right siblings).

Practical consequence

  • The translation can be evaluated in a left-to-right order across the right-hand side of productions, while still allowing inherited flow needed for context-sensitive decisions.

[CalloutBlock]
type: "warning" title: "Common pitfall (L-attributed dependency)" content: "If an inherited attribute for XiX_i needs data from a right sibling (some XjX_j with j>ij>i), then the grammar is not L-attributed."


Direct differentiation: S-attribute vs L-attribute

Comparison table

AspectS-attributed SDTL-attributed SDT
Inherited attributes allowed?Effectively no (dependency restricted to child attributes only)Yes
Dependencies for semantic rulesOnly children attributes (bottom-up)Parent + left siblings (left-to-right compatible)
Typical evaluation orderBottom-upLeft-to-right within productions, consistent with parse
PowerLess expressiveMore expressive (handles more context-sensitive properties)
Parser compatibilityNaturally fits bottom-up computationFits many top-down / recursive-descent-style translation with left-to-right evaluation

Mermaid: dependency arrows


Worked examples

Example 1: Expression type synthesis (S-attributed friendly)

Consider:

E→E+TE→TT→idE \to E + T \quad\quad E \to T \quad\quad T \to id

Goal: synthesize E.typeE.type from children.

  • Attach rules like:
    • E.type=numeric_type_join(E1.type,T.type)E.type = \text{numeric\_type\_join}(E_1.type, T.type)
    • T.type=lookup(id.lexeme)T.type = \text{lookup}(id.lexeme)

All used values come from children; no inherited context is needed. This fits S-attributed SDT.


Example 2: Type checking with inherited environment (L-attributed)

Now add declarations and scoping-like context in a simplified way, e.g.:

Stmt→begin L endStmt \to \text{begin } L \text{ end}

where LL is a list of statements, and an inherited environment EnvEnv must flow into each statement as it is parsed/evaluated left-to-right.

  • Production: L→L1 ; SL \to L_1\ ;\ S
  • Inherited idea: L.EnvL.Env carries the symbol table / type environment accumulated from earlier declarations.
  • Rule shape (conceptual):
    • S.Env:=L.EnvS.Env := L.Env (inherits from left structure)
    • If SS introduces declarations, then update for the next list element.

This requires inherited information that depends on left context (earlier items in the list), which matches L-attributed SDT.

Why not S-attributed?
Because SS may need environment built from left siblings (earlier declarations), which is not available if you restrict to children-only synthesized computation.


Example 3: Code generation needing left context (L-attributed)

For infix expressions you often need left-to-right evaluation to manage:

  • stack layout,
  • temporaries,
  • or concatenation of instruction sequences.

Suppose you generate code while respecting operand order:

  • E→E1 + E2E \to E_1\ +\ E_2
  • Let synthesized pieces code(E1)code(E_1) and code(E2)code(E_2) exist, but let inherited attribute nextTempnextTemp or outputModeoutputMode depend on what was emitted for the left subtree.

If nextTempnextTemp (or similar) depends on emitted instructions from E1E_1 (left sibling context on the RHS), then L-attributed fits; S-attributed generally does not model it without additional structure.


How evaluation typically proceeds

Bottom-up compute

S-attributed

Compute node attributes after children are computed."

Left-to-right + inheritance

L-attributed

Compute inherited attributes using parent + left siblings; then compute dependent attributes."

Consistent translation

Result

Both produce correct attribute values; L-attributed is more flexible."


FAQs and edge cases

S-attributed vs L-attributed quick checks

1 / 5
Question · Term

S-attributed dependency rule?

Click to reveal
Answer · Definition

Semantic rules depend only on children attributes (no left-sibling inherited dependencies).

Knowledge Check

Question 1 of 4
Q1Single choice

In an S-attributed SDT/attribute grammar, a semantic rule for a node can depend on which attributes?