Skip to content

L-Attributed Grammar

Constrain inherited attributes to parent context and earlier siblings so parse-tree attributes can be evaluated left to right.

Version
v1 · 2026-10-03 · History
Domain-specific #
13369
Domain group
Applied Sciences & Engineering
Origin domain
Computer Science & Software Engineering
Subdomains
Compiler Theory, Attribute Grammars → Computer Science & Software Engineering
Aliases
L-attributed definition, Left-attributed grammar

Core Idea

An L-attributed grammar, more precisely an L-attributed syntax-directed definition, is an attribute-grammar discipline that lets semantic information be evaluated in a depth-first, left-to-right traversal of a parse tree. For a production A → X₁ X₂ … Xₙ, an inherited attribute of child Xᵢ may depend on inherited attributes of A and on inherited or synthesized attributes of children to its left, X₁ … Xᵢ₋₁. It cannot require a value that will only become available from a right sibling. Synthesized attributes can be computed from visited children and passed upward.[1][2]

The rule is about semantic-value dependencies on a parse tree, not about which strings the underlying grammar recognizes. It makes it possible to pass a context into a child before visiting that child and receive a result afterward. An S-attributed definition, which has only synthesized attributes, satisfies this restriction as a special case. The L property does not by itself make a grammar suitable for predictive parsing or automatically embed its actions in every parser implementation.[1][2]

Structural Signature

Sig role-phrases:

  • Ordered production carrier — A context-free production and its parse-tree children establish what it means for a sibling to occur to the left or right.
  • Attribute occurrences — Inherited values carry context into a child; synthesized values carry computed results out of a subtree.[1]
  • Leftward dependency restriction — An inherited value for Xᵢ uses inherited context of A or already available attributes of X₁ … Xᵢ₋₁, not future siblings or a parent result that awaits Xᵢ.[2]
  • Evaluation schedule — Before descending into a child, compute its inherited inputs; after visiting it, its synthesized outputs can inform later siblings or the parent.[1]
  • Implementation interface — In recursive descent, inherited attributes resemble function parameters and synthesized attributes resemble returned values; other parsing strategies may require refactoring.[1]

The syntactic grammar and the attribute equations are both needed. An ordered production without semantic equations is not an L-attributed definition merely because it is read from left to right.

What It Is Not

  • Not an LL grammar. LL concerns whether a parser can choose productions from left-to-right input and lookahead; L-attributed concerns when semantic attribute values become available on a chosen parse tree.
  • Not all attribute grammars. A noncircular dependency graph may still require a later sibling's value before an earlier child can be visited and so fail the L restriction.[2]
  • Not distinct from the S-attributed class by exclusion. Every S-attributed definition has no inherited attributes and qualifies as L-attributed; the reverse does not hold.[1]
  • Not guaranteed to work unchanged in a bottom-up parser. Reductions may occur before the parent's inherited context is exposed; marker productions or equivalent action changes may be required.[1]
  • Not an order restriction on recognized strings. It constrains semantic equations, not the language generated by the underlying productions.

Scope of Application

Compiler construction uses the discipline to attach type contexts, environments, expression values, or translation information to syntax trees without a general iterative attribute solver. In a declaration grammar, a type determined at an earlier Type node can be passed as an inherited attribute to the following variable list. In a left-factored expression grammar, a value calculated for the left term can be passed as an inherited accumulator to the right tail.[1][2]

The formal test applies wherever attributes are associated with ordered production trees. Its practical integration depends on the parsing architecture. Recursive descent naturally exposes the “parameter in, result out” schedule; a bottom-up implementation may need transformations even when the attribute equations themselves are L-attributed.[1]

Clarity

The L label answers a precise question: can the value needed before entering each child be computed from parent context and already visited siblings? That is different from asking whether the semantic equations are acyclic in some order. It also separates attribute evaluation from parsing strategy. A grammar can have an L-attributed definition while still requiring separate analysis to decide whether its syntax is LL or how its semantic actions fit an LR parser.

The closest boundary test is a right-sibling dependency. If X₁ needs an inherited value computed from X₂, then a strict visit of X₁ before X₂ cannot supply that value; one must change the equations, change the traversal, or accept a more general attribute-evaluation scheme.[2]

Manages Complexity

The restriction replaces a potentially global dependency-scheduling problem with a local ordering rule. At each production, a compiler writer can inspect the incoming context and the outputs of children already traversed. That allows many semantic operations to be integrated into a single tree walk rather than constructing and solving an arbitrary dependency graph.[1]

The simplicity is purchased by limiting dependencies. A semantic definition that genuinely needs information from a future sibling cannot be expressed in the same evaluation schedule without reformulation. Parser implementation adds another layer: an abstractly valid visit order is not the same as values being exposed at the right moment by a particular parser generator.

Abstract Reasoning

Given A → X₁ … Xₙ, inspect every equation that defines an inherited attribute of Xᵢ. List the attribute occurrences it reads. Parent inherited attributes and attributes of X₁ … Xᵢ₋₁ are available; right-sibling attributes are not. Then check that synthesized equations can be evaluated once their referenced subtrees are complete. Passing these tests supports a constructive left-to-right visit schedule, not a claim about runtime speed or syntactic determinism.[1][2]

A useful counterfactual is to move a required input from a left sibling to a right sibling. The grammatical production can stay unchanged, yet the attribute definition ceases to have the L property. Conversely, removing all inherited attributes yields an S-attributed special case.

Knowledge Transfer

Within compiler theory, the dependency test transfers between type propagation, expression evaluation, syntax-directed translation, and other attributed parse trees. Its literal scope still requires a formal grammar with ordered child positions and semantic attributes. A workflow that passes information left to right resembles the pattern but is not thereby an L-attributed grammar.

The more general idea of evaluating a dependency graph in an available order is portable, but this named abstraction is the compiler-specific restriction on production-bound attribute equations.

Examples

Type passed through a declaration list

In the university lecture example, Decl → Type VarList first computes the type from Type and then supplies that value as the inherited VarList.type. As the list recurses, it passes the same type into its later tail. No list node must wait for a declaration item to its right before receiving its type.[1]

Mapped back: carrier = ordered Decl and VarList productions; attributes = synthesized Type.type and inherited VarList.type; restriction = each needed type comes from a left sibling or parent context; schedule = evaluate Type, then descend through the list.

Value passed into an expression tail

For a left-factored expression grammar E → T R, the East Carolina example computes T.val and sets R.inh = T.val. The tail uses that incoming value while computing its own synthesized result, which then returns to E. The dependency is from left sibling to right child, not the other way around.[2]

Mapped back: carrier = E → T R; attributes = synthesized T.val and R.val, inherited R.inh; restriction = R.inh reads only the already completed left sibling; schedule = visit T before R, then return R.val.

Structural Tensions

Expressive dependencies versus guaranteed traversal. Allowing arbitrary semantic equations can express more relationships among a parse tree's nodes, but a right-to-left inherited dependency may prevent one left-to-right visit. Restricting equations restores a predictable schedule while excluding some convenient definitions. Diagnostic: does any child's input require a sibling that has not yet been evaluated?

Parser timing is a separate implementation boundary, not a second opposed-cost tension. A parse tree may admit left-to-right semantic evaluation while a bottom-up parser reduces a child before its parent context is available. Diagnostic: at the moment that parser processes Xᵢ, have its inherited inputs actually been supplied? Failure of this schedule does not by itself refute the grammar's L-attribution.[1]

Structural–Framed Character

L-attribution is predominantly structural within a formal-language frame. Its evaluative weight is low: the restriction is a mathematical property, not a judgment that a compiler is good. Human-practice dependence enters through choosing syntax and semantic equations, but once those are fixed, dependency direction is testable. The terminology arose in compiler theory, where ordered productions and attributes give the rule its meaning. Words such as inherited or left may travel, yet outside production trees the concept would be imported as an analogy rather than recognized literally. The portable skeleton is scheduling a dependency graph so a node reads only available predecessors; that skeleton does not establish cross-domain instances of the named grammar class. Its character: a formally testable, domain-specific dependency discipline.

Structural Core vs. Domain Accent

The general skeleton is compute each required input from values already available in the chosen order. The live Dependency prime captures the portable directed-reliance relation between an input and the value that supplies it; that is a related skeleton, not the staged strict parent. The actual Context-Free Grammar parent supplies the ordered production carrier that this method presupposes. Its inherited and synthesized attributes, semantic equations, and left-to-right restriction make the test exact: removing them leaves a general dependency schedule, not an L-attributed grammar. The named abstraction therefore does not clear the prime bar merely because dependency ordering appears elsewhere.

This entry presupposes Context-Free Grammar.

A context-free grammar is the nearest production-and-parse-tree carrier: L-attributed equations require the ordered positions in its productions, but they add semantic attributes rather than merely generating strings. The broader Formal grammar is a more remote prerequisite.

S-attributed grammar is a narrower identity that allows only synthesized attributes; it may later be placed beneath L-attributed grammar, but is not yet. LL grammar concerns a parsing property, not the same dependency class. ECLR-attributed grammar addresses a different LR-oriented attributed-grammar discipline, and a resemblance in names alone is no reason to connect the two.

Relationships to Other Abstractions

Local relationship map for L-Attributed GrammarParents appear above the current abstraction, mutual partners to the right, and children below. Node labels state whether each abstraction is prime or domain-specific; colors identify relation types.L-Attributed GrammarDOMAINDomain-specific abstraction: Context-Free Grammar — presupposesContext-FreeGrammarDOMAIN

Current abstraction L-Attributed Grammar Domain-specific

Parents (1) — more general patterns this builds on

  • L-Attributed Grammar presupposes Context-Free Grammar Domain-specific

    L-attributed equations require ordered context-free productions and their parse-tree children.

Hierarchy paths (2) — routes to 2 parentless roots

Neighborhood in Abstraction Space

L-Attributed Grammar sits in a sparse region of the domain-specific corpus (67th percentile for distinctiveness): few abstractions share its structure, so a faithful description tends to retrieve it precisely.

Family — Program Scope & Nesting Disciplines (10 abstractions)

Nearest neighbors

Computed from structural-signature embeddings · 2026-10-08

Not to Be Confused With

  • S-attributed grammar: a valid subset with synthesized attributes only; it need not pass context into children.
  • LL grammar: a syntax-level predictive parsing class; L-attribution classifies semantic equations.
  • Any acyclic attribute grammar: acyclicity permits some evaluation order, not necessarily a single depth-first left-to-right one.
  • The ordinary meaning of “left”: this is a dependency restriction relative to child order in a production, not a claim about source-code indentation or associativity.

References

[1] Stony Brook University CSE 504, “Syntax-Directed Definitions”, especially slides 4–7, 10–11, and 19–22. registry ↩a ↩b ↩c ↩d ↩e ↩f ↩g ↩h ↩i ↩j ↩k ↩l ↩m

[2] East Carolina University, “Synthesized and inherited attributes,” §11.4, including its L-attributed-equations and recursive-descent examples. registry ↩a ↩b ↩c ↩d ↩e ↩f ↩g ↩h