Yasir Explains/Compiler Design/Grammars and Expressions/Left Linear Grammar
Grammars and Expressions

Left Linear Grammar

On this page

DefinitionExample 1 — Strings of a's Ending in bExample 2 — Strings Starting with abLeft vs Right Linear — Side by SideRegular Grammars — The Full Picture
Grammars and Expressions

Left Linear Grammar

Explore left linear grammars — the mirror image of right linear grammars — where every production places the non-terminal at the left end, and understand how they relate to right linear grammars and regular languages.

Definition

A left linear grammar (also called a left regular grammar) is a grammar G = (V, T, P, S) where every production rule has one of these three forms:

FormMeaning
A → BaNon-terminal B on the left, terminal a on the right
A → aJust a single terminal (or any string of terminals)
A → εThe empty string

The defining feature: the non-terminal always appears at the left end of the right-hand side (if it appears at all).

Example
Allowed:
S → Sa ← non-terminal S is on the LEFT ✓
S → Ab ← non-terminal A is on the LEFT ✓
A → b ← no non-terminal on RHS ✓
A → ε ← empty production ✓
NOT allowed:
S → aS ← non-terminal S is on the RIGHT ✗ (that is right-linear)
S → aBc ← non-terminal B is in the MIDDLE ✗
S → AB ← two non-terminals ✗

Like right linear grammars, left linear grammars also generate exactly the regular languages. The two types of grammars are equally powerful — they differ only in the direction from which they build strings.

Example 1 — Strings of a's Ending in b

Language: L = {aⁿb | n ≥ 0} = {b, ab, aab, aaab, ...}

Left Linear Grammar:

Example
G: S → Ab
A → Aa | ε
  • A → ε : A can be the empty string (generating zero a's)
  • A → Aa : A generates one more 'a' on the right (builds up a string of a's)
  • S → Ab : Append 'b' to whatever A generates

Derivation of "aab":

Example
Step Sentential Form Rule Applied
──── ───────────────── ──────────────────
0 S
1 Ab S → Ab
2 Aab A → Aa (A becomes Aa, so "Ab" becomes "Aab")
3 Aaab A → Aa (A becomes Aa, so "Aab" becomes "Aaab")
4 aab A → ε (remove A, leaving "aab")

Why does this work?

A → Aa | ε makes A generate any string in {aⁿ | n ≥ 0}:

  • A → ε → A = "" (zero a's)
  • A → Aa → εa → A = "a" (one a)
  • A → Aa → Aaa → εaa → A = "aa" (two a's)

Then S → Ab appends a 'b', giving {aⁿb | n ≥ 0} ✓

Notice how the grammar builds from the inside out, growing the string of a's to the right of A, then finally removing A when done. This is the opposite of right linear grammars, which build left to right one step at a time.

Example 2 — Strings Starting with ab

Language: L = {ab · w | w ∈ {a, b}*} — strings that start with "ab" Examples: ab, aba, abb, abaa, abab, abba, ...

Left Linear Grammar:

Example
G: S → Aa | Ab
A → Ba
B → b | Bb | Ba

Hmm, this is getting complex. Let me use a cleaner approach.

Because left-linear grammars build strings from right to left (the non-terminal is on the left side), it is often easier to think of them as "suffix grammars" — they describe what comes at the END of the derivation and build leftward.

Cleaner grammar for ab · {a,b}*:

Example
S → Sa | Sb | Ab
A → a

Derivation of "abba":

Example
Step Sentential Form Rule Applied
──── ───────────────── ──────────────
0 S
1 Sa S → Sa
2 Sba S → Sb
3 Aba S → Ab
4 aba A → a

Reading the derivation: The rightmost characters are appended first. S reads right-to-left over the string. A marks the point where the prefix "ab" is finally produced.

Left vs Right Linear — Side by Side

The same regular language can always be expressed by both a left linear grammar and a right linear grammar. The difference is purely structural — the direction from which the non-terminal "moves" through the string.


Language: L = {aⁿb | n ≥ 0}

Example
Right Linear Grammar: Left Linear Grammar:
────────────────────── ──────────────────────
S → aS | b S → Ab
A → Aa | ε
Derivation of "aab": Derivation of "aab":
S → aS → aaS → aab S → Ab → Aab → Aaab → aab
(builds left to right) (grows inward, then removes A)

Language: L = {a, b}* (all strings over {a, b}, including ε)

Example
Right Linear Grammar: Left Linear Grammar:
────────────────────── ──────────────────────
S → aS | bS | ε S → Sa | Sb | ε

Formal Comparison Table

PropertyRight Linear GrammarLeft Linear Grammar
Production formA → aB or A → aA → Ba or A → a
Non-terminal positionRight endLeft end
String builtLeft to rightRight to left (or inside-out)
Language class generatedRegularRegular
Equivalent automatonNFA (forward reading)NFA (reverse reading)
Interconvertible?Yes — reverse the string, swap typesYes

The Conversion Trick

Every left linear grammar can be converted to an equivalent right linear grammar by reversing the language:

  1. Replace each left linear rule A → Ba with A' → aB' (mirror the rule)
  2. Reverse the roles of start and accepting states

This works because reversing a regular language always gives another regular language.

Regular Grammars — The Full Picture

Both right linear and left linear grammars are collectively called regular grammars. They sit at the bottom of the Chomsky Hierarchy (Type 3) and are the least powerful class of grammars.

Example
Type 3 — Regular Grammars
├── Right Linear Grammar (A → aB | a | ε)
└── Left Linear Grammar (A → Ba | a | ε)
Both generate: Regular Languages
Both recognised by: Finite Automata (DFA / NFA)
Both equivalent to: Regular Expressions

Why Regular Grammars Matter in Compiler Design

The lexical analysis (scanner/tokeniser) phase of a compiler uses regular grammars:

Example
Token: integer literal
Right linear grammar: D → 0D | 1D | ... | 9D | 0 | 1 | ... | 9
Regular expression: [0-9]+
DFA: state machine that accepts any sequence of digits
Token: identifier
Right linear grammar: I → aI | bI | ... | zI | aF | bF | ...
F → aF | ... | 0F | ... | ε
Regular expression: [a-zA-Z][a-zA-Z0-9]*

The regular grammar describes the structure of each token type. The compiler tool lex (or flex) takes these descriptions and automatically builds the DFA that recognises them.


Key Takeaway

Grammar TypeCan describeCannot describe
Regular (left or right linear)Token patterns, simple repetitionNested structures, balanced brackets
Context-FreeMost programming language syntaxaⁿbⁿcⁿ, context-sensitive rules
Context-SensitiveMore complex languagesTuring-complete computations

Regular grammars are simple, fast, and sufficient for lexical analysis. More power (context-free, context-sensitive) is needed for parsing full programs.