Visual walkthrough — Context-free grammars (CFG) — productions, derivations, parse trees
Step 0 — The four things we start with
Before anything grows, we need to agree on our tools. A grammar has four parts. Let us name them with plain words first, then attach the fancy letters.
Our grammar for the whole page:

Look at the picture: the blue box is the placeholder , the orange characters are the terminals it can turn into, and the red is the eraser. That is our entire toolkit. Our goal for the walkthrough: build the string (()) — two brackets nested inside two brackets — and prove it belongs to this grammar.
Step 1 — The seed
WHAT. We begin, as every derivation must, with the start symbol alone:
WHY. There is nothing else to begin with — is the only starting placeholder. Every legal string in this grammar must trace back to this single seed. If we cannot reach a string from , that string is not in the language.
PICTURE. Below, the tree is just one blue node. The tree will grow downward as we apply rules; the leaves read left-to-right will always spell our current string. Right now the only leaf is itself — an unfinished placeholder, so the string is not done.

Step 2 — First rewrite: open a bracket
WHAT. We apply the rule to our single :
The double arrow means "rewrites in one step" — read it as "becomes". (Contrast the single arrow , which lives inside a rule; the double arrow is us using a rule.)
WHY. We want a bracketed string, so we must produce an actual open bracket . The only rule that gives us brackets is . So we choose it.
PICTURE. In the tree, the old node sprouts four children, left to right: . Two of those children ( and , orange) are finished terminals — leaves that will never grow again. Two of them (, blue) are still placeholders and will grow later.

Step 3 — Kill the trailing placeholder
WHAT. Our current string is . We now apply to the rightmost :
WHY. We want (()) — a single outer group with nothing after it. The trailing threatens to add more stuff on the right. To stop that, we erase it: turns it into nothing.
PICTURE. In the tree, the rightmost blue gets one child: a red leaf. An leaf contributes no character to the yield, so reading the leaves left-to-right now gives — the empty leaf simply disappears from the string.

Step 4 — Recurse inward: nest a second bracket
WHAT. Current string: . We apply again, this time to the inner :
WHY. We wanted (()), which has a second pair of brackets living inside the first. The only way to make more brackets is to expand a placeholder with once more. This is the moment recursion earns its keep: the same rule that opened the outer bracket now opens an inner one.
PICTURE. Look at the tree: the inner blue from Step 2 now sprouts its own four children . We now have brackets inside brackets — the tree visibly grows a new layer. This nesting depth is exactly what a finite-state machine (a DFA) cannot count, and why we needed a grammar.

Step 5 — Erase the two remaining placeholders
WHAT. Current string: . Two blue placeholders remain. We erase both with :
Wait — read carefully. After erasing the inner we have ; after erasing the last we have . Two clean-up moves.
WHY. Every remaining is an unfinished placeholder, and a string is only a finished word when no placeholders remain — when every leaf is a terminal. The nesting we wanted is already there; the leftover placeholders would only add clutter, so we switch them off.
PICTURE. Each remaining blue gets a red child. The tree stops growing. Read the bottom leaves left to right, skipping the 's: (()). Done.

Step 6 — Read the final answer
WHAT. No variable is left. The yield — the leaves read left-to-right — is and every symbol in it is a terminal. Therefore where means "rewrites in zero or more steps" — the whole chain we just walked, compressed into one claim.
WHY. Because we reached a string made only of terminals, starting from , this string is officially a member of the language: Term by term: = "all strings over the terminal alphabet", the vertical bar = "such that", and = "the seed can grow into ". So is the set of every string the seed can possibly become.

Step 7 — The degenerate case: building nothing
WHAT. What is the shortest possible member of this language? Apply the eraser immediately:
WHY. We must always check the boundary. The very first rule we may apply to the seed is , which finishes instantly with the empty string. So : the empty string of brackets is balanced (vacuously — nothing is unmatched).
PICTURE. The tiniest legal parse tree: a root with exactly one red leaf. Zero brackets, and still perfectly valid. Every valid nesting story must be allowed to end, and this is that ending in its purest form.

The one-picture summary
Here is the whole walkthrough compressed: the seed at top, the string growing across five rewrites, and the finished parse tree whose leaves spell (()). The left-to-right yield of the leaves is the string — that is the single most important idea on this page.

Recall Feynman retelling — the whole story in plain words
Imagine one magic seed called . You have exactly two spells. Spell A turns a seed into: an open bracket, a new seed, a close bracket, and one more seed. Spell B makes a seed vanish. To build (()), you cast Spell A on the first seed to get a bracket pair with two baby seeds inside and after it. You vanish the after-seed (Spell B) so nothing trails. You cast Spell A on the inner seed to nest a second bracket pair. Then you vanish the last two seeds. When no seeds remain, you read off the brackets left to right: (()). The family tree of which seed split into which is the parse tree — and no matter what order you cast the vanish-spells, the family tree is the same. That sameness is why "more steps" never means "more structure".
Recall What does the double arrow
mean, and how is it different from ? appears inside a rule (a rewrite you're allowed to make). is you actually applying one such rule to the current string ("becomes in one step"). = zero or more such steps chained together.
Recall Why is
? Because in one step via the erase rule — the empty string is derivable from the seed, and it contains only terminals (namely, none), so it qualifies.
Recall Why can this grammar do something no DFA can?
Building (()) required opening a bracket, then recursing inside to open another. That unbounded nesting is unbounded counting, which a finite-state DFA cannot track — it needs the stack of a pushdown automaton.
Connections
- Parent topic
- Regular expressions and DFAs
- Pushdown automata
- Chomsky hierarchy
- Chomsky normal form
- Pumping lemma for CFLs
- Compilers — parsing