The formal language that describes programming language syntax. Learn the four components, how production rules work, and why grammars define the language a parser recognizes.
A Context-Free Grammar (CFG) is a 4-tuple G = (V, Σ, P, S). Every grammar you'll ever encounter in compiler construction has exactly these four pieces.
We'll use this grammar throughout the entire course. It describes arithmetic expressions with addition and multiplication, handling operator precedence correctly.
Click on any symbol below to learn whether it's a terminal or non-terminal and what role it plays in the grammar.
A production rule A → α says: "the non-terminal A can be replaced by the string α." Understanding the structure of production rules is key to understanding all parsing algorithms.
aAb → aBb (context-dependent), that would be a context-sensitive grammar.
The language defined by a grammar G is the set of all strings of terminals that can be derived from the start symbol. Some strings are in L(G), some are not.
id
— simplest expression: F→id, T→F, E→T
id + id
— addition of two identifiers
id * id
— multiplication of two identifiers
id + id * id
— mixed: * has higher precedence
(id + id) * id
— parentheses override precedence
(id)
— parenthesized single id
id + id + id
— chained addition (left-associative)
+ id
— no production starts with +
id id
— two ids with no operator
* *
— operators without operands
(id
— unmatched parenthesis
id +
— trailing operator, no RHS
id * + id
— two consecutive operators
(empty)
— ε not derivable from E
Left recursion occurs when a non-terminal can eventually derive a string starting with itself. This is perfectly fine for LR parsers, but causes infinite loops in recursive descent (top-down) parsers.
The general algorithm for eliminating direct left recursion converts A → Aα | β into right-recursive form using a new non-terminal A′:
Every CFG has: Terminals (Σ), Non-Terminals (V), Productions (P), and Start Symbol (S). Written G = (V, Σ, P, S).
Always of the form A → α (one NT on left). The | operator provides alternatives. ε means the empty string.
All strings of terminals derivable from the start symbol. The grammar defines exactly which programs are syntactically valid.
A → Aα breaks top-down parsers (infinite loop). Must be eliminated for LL(1)/recursive descent. LR parsers handle it naturally.