Labs ICT
Pro Login

CFG Examples

Writing grammars for arithmetic expressions, balanced parentheses, and more.

CFG Examples

Let's build context-free grammars for several important languages. These examples show the expressiveness of CFGs and how they handle structures that regular expressions cannot.

Example 1: Balanced Parentheses

The language of balanced parentheses {(), (()), ((())), ()(), etc.} is a classic context-free language. A regular expression cannot count matching pairs, but a CFG can.

Grammar for balanced parentheses:
  S → ( S ) | S S | ε

Derivation of "(())()":
  S → S S → ( S ) S → ( ( S ) ) S → (()) S → (()) ( S ) → (())()

Key insight: The recursive S → ( S ) rule creates
matching pairs. The S → S S rule allows concatenation.

Example 2: Arithmetic Expressions

CFGs are the standard way to define programming language syntax. Here's a grammar for simple arithmetic:

Grammar for arithmetic expressions:
  E → E + T | E - T | T
  T → T * F | T / F | F
  F → ( E ) | number

Where number is a terminal representing any numeric value.

Precedence is encoded in the grammar:
  * and / bind tighter than + and -
  Parentheses override everything

Derivation of "2 + 3 * 4":
  E → E + T → T + T → F + T → number + T
    → number + T * F → number + F * F
    → number + number * number
    → 2 + 3 * 4

The grammar naturally gives * higher precedence
because T (which handles *) is deeper in the hierarchy.

Example 3: Palindromes over {a,b}

Palindromes (strings that read the same forwards and backwards) are context-free. The grammar uses recursion to mirror characters.

Grammar for palindromes over {a, b}:
  S → aSa | bSb | a | b | ε

Derivation of "abba":
  S → aSa → abSba → abba

Derivation of "aba":
  S → aSa → aba

The recursion ensures characters are added symmetrically.

Example 4: {a^n b^n | n >= 1}

A simple grammar that generates equal numbers of a's followed by b's:

Grammar:
  S → aSb | ab

Derivation of "aaabbb":
  S → aSb → aaSbb → aabbb? No —
  S → aSb → aaSbb → aaaSbbb → aaabbb? No —
  Let's be careful:
  S → aSb → aabbb? No.

  Correct:
  S → aSb → aabbbb? No.

  S → aSb (first step)
  S → aSb → aabb (second step, S → ab)
  Wait: S → aSb, then replace S with ab: a( ab )b = aabb ✓

  For "aaabbb":
  S → aSb → aaSbb → aaaSbbb → aaabbb ✓
  (S → ab at the innermost step)