Skip to main content

Formal Languages and Grammar

Learning Objectives

By the end of this page, you should be able to:

  • Define a formal language and explain how an alphabet, strings, and a grammar relate to one another.
  • Classify a grammar into its correct level of the Chomsky hierarchy (Type 0-3) from its production rules.
  • Write a context-free grammar for a simple language, such as balanced parentheses.
  • Apply union, concatenation, and Kleene star to combine two languages.
  • Explain why the Chomsky hierarchy mirrors the automaton hierarchy (FA/PDA/TM) from the previous topic.
  • Identify common mistakes students make when classifying grammars or confusing "language" with "grammar."

Quick Answer

A formal language is simply a precisely defined set of strings built from a fixed alphabet — nothing more mystical than "which sequences of symbols count as valid." A grammar is the rulebook that generates exactly those strings, using production rules that rewrite non-terminal symbols into terminals. Formal languages matter because every programming language, every regular expression, and every data format (JSON, XML, HTML) is, underneath, a formal language defined by a grammar. The Chomsky hierarchy ranks grammars by how restrictive their production rules are — from unrestricted (Type 0) down to regular (Type 3) — and this ranking exactly predicts which automaton (Turing machine, PDA, or finite automaton) is needed to recognize the resulting language. Compiler front-ends are built directly on this theory.

Alphabets, Strings, and Languages

Before grammars make sense, three building blocks need to be nailed down precisely, because casual English is too loose for what comes next.

  • Alphabet (Σ\Sigma): a finite, non-empty set of symbols. For example, Σ={0,1}\Sigma = \{0, 1\} or Σ={a,b,c}\Sigma = \{a, b, c\}.
  • String: a finite sequence of symbols drawn from Σ\Sigma, including the special empty string ϵ\epsilon (length zero).
  • Language: any subset of Σ\Sigma^*, where Σ\Sigma^* denotes the set of all possible strings over Σ\Sigma (including ϵ\epsilon).

So a "language" in this technical sense is not English or Python — it's just a set. {101,111,110}\{ \text{101}, \text{111}, \text{110} \} is a perfectly valid (if boring) language. What makes languages interesting is that most useful ones are infinite sets defined by a rule rather than listed by hand — and that rule is what a grammar provides.

Worked Example: Three Small Languages

LanguageRuleValid stringsInvalid strings
Binary numbers{0,1}\{0,1\}^*101, 11011, 0000102 (not in alphabet)
Palindromes over {a,b}\{a,b\}reads the same forwards and backwardsabba, bab, aaabb
Equal a's then b's{anbnn0}\{a^n b^n \mid n \geq 0\}ε, ab, aabbaab (unequal counts)

Why it matters: notice the third language, anbna^nb^n, is exactly the language a DFA cannot recognize (covered in Automata Theory) — because recognizing it requires counting. Formal language theory is what lets us prove that limitation rigorously instead of just suspecting it.

Common misunderstanding: students often think "formal language" means a natural language like English studied formally. It doesn't — it's a mathematical object (a set of strings), and any resemblance to natural language rules (like grammar in the school sense) is only a loose analogy.

Grammars: The Rulebook Behind a Language

A grammar generates a language by rewriting symbols according to production rules, starting from a designated start symbol. Formally, a grammar is a 4-tuple:

G=(N,T,P,S)G = (N, T, P, S)

ComponentMeaningExample
NNNon-terminal symbols (placeholders, never appear in the final string){S}\{S\}
TTTerminal symbols (the alphabet of the language itself){(,)}\{(, )\}
PPProduction rules (how to rewrite non-terminals)S(S)S \to (S)
SSStart symbolSS

Worked Example: Balanced Parentheses

Goal: write a grammar that generates exactly the strings of balanced parentheses — (), (()), ()(), but not (() or )(.

Design thinking: a balanced string is either empty, two balanced strings glued together, or one balanced string wrapped in an extra pair of parentheses. That recursive definition translates almost directly into production rules:

S(S)SSϵS \to (S) \mid SS \mid \epsilon

Trace generating (()): start with SS. Apply S(S)S \to (S) to get (S)(S). Apply S(S)S \to (S) again to the inner SS to get ((S))((S)). Apply SϵS \to \epsilon to get (())(()). Every step rewrote exactly one non-terminal using one production rule — this sequence is called a derivation.

Real-world example: this is precisely the grammar (in spirit) that a JSON or code editor uses to validate bracket matching, and it's the textbook example used to introduce every parser generator (like Yacc/Bison or ANTLR).

Why it matters: this grammar cannot be written as a regular grammar (Type 3) — the recursive nesting S(S)S \to (S) requires context-free power at minimum. That's the direct link back to why a DFA cannot recognize balanced parentheses but a PDA can.

Common misunderstanding: students think a grammar and the language it generates are the same thing. They're not — many different grammars can generate the exact same language (just like many different DFAs can recognize the same regular language). The grammar is a description mechanism; the language is the set it describes.

The Chomsky Hierarchy

Linguist Noam Chomsky classified grammars in 1956 by how restrictive their production rules are. Each restriction level corresponds exactly to one class of automaton from the previous topic — this is not a coincidence, it's a proven equivalence.

TypeNameRule restrictionRecognized byExample language
0UnrestrictedNo restriction — any αβ\alpha \to \beta where α\alpha contains at least one non-terminalTuring machineAny recursively enumerable language
1Context-sensitiveαβ\|\alpha\| \leq \|\beta\| (right side at least as long as left)Linear bounded automaton{anbncnn0}\{a^n b^n c^n \mid n \geq 0\}
2Context-freeLeft side is a single non-terminal: AβA \to \betaPushdown automatonBalanced parentheses, most programming-language syntax
3RegularAaBA \to aB or AaA \to a (single terminal, optionally followed by one non-terminal)Finite automatonStrings ending in ab

Why it matters: each level down is strictly weaker — every regular language is context-free, every context-free language is context-sensitive, and every context-sensitive language is recursively enumerable, but not vice versa. This is why a regex (Type 3 power) can never fully validate nested HTML tags (Type 2 power needed) — a fact that trips up developers who try to "solve" HTML validation with a single regular expression.

Common misunderstanding: students assume "more general grammar" always means "more useful." In practice, weaker grammar classes (regular, context-free) are preferred whenever possible because they support faster parsing — a context-free grammar can typically be parsed in O(n3)O(n^3) or better, while unrestricted (Type 0) grammars correspond to full Turing-machine computation, with no efficiency guarantee at all.

Language Operations

Because a language is just a set of strings, languages can be combined using set-like operations — but two of them are specific to strings.

OperationDefinitionExample (L1={a,ab}L_1 = \{a, ab\}, L2={b}L_2 = \{b\})
UnionL1L2={wwL1 or wL2}L_1 \cup L_2 = \{w \mid w \in L_1 \text{ or } w \in L_2\}{a,ab,b}\{a, ab, b\}
ConcatenationL1L2={w1w2w1L1,w2L2}L_1 L_2 = \{w_1 w_2 \mid w_1 \in L_1, w_2 \in L_2\}{ab,abb}\{ab, abb\}
Kleene starL={ϵ}LLLLLLL^* = \{\epsilon\} \cup L \cup LL \cup LLL \cup \dotsL2={ϵ,b,bb,bbb,}L_2^* = \{\epsilon, b, bb, bbb, \dots\}

Real-world example: regular expressions are literally notation for these three operations. a|b is union, ab is concatenation, and a* is Kleene star — when you write a regex, you're building a language out of these exact primitives, which is why regex power tops out at regular languages.

Why it matters: these operations let us prove closure properties — for instance, regular languages are closed under union, concatenation, and Kleene star, meaning combining two regular languages this way always produces another regular language. This is what guarantees that a regex engine can always compile any combination of these operators into a single working automaton.

Key Terms

TermDefinition
Alphabet (Σ\Sigma)A finite, non-empty set of symbols used to build strings.
StringA finite sequence of symbols from an alphabet, including the empty string ϵ\epsilon.
LanguageA subset of Σ\Sigma^* (all possible strings over an alphabet); the set of "valid" strings.
Grammar (GG)A 4-tuple (N,T,P,S)(N, T, P, S) of non-terminals, terminals, production rules, and a start symbol that generates a language.
Production ruleA rewrite rule showing how a non-terminal can be replaced during a derivation.
DerivationA sequence of production-rule applications that transforms the start symbol into a target string.
Chomsky hierarchyThe four-level classification of grammars (Type 0-3) by restrictiveness of their production rules.
Context-free grammar (CFG)A Type 2 grammar where every rule's left side is a single non-terminal.
Regular grammarA Type 3 grammar restricted to rules of the form AaBA \to aB or AaA \to a.
Closure propertyA guarantee that applying an operation to languages of a given class always produces a language in that same class.

Common Mistakes

Misconception 1: "A formal language is the same thing as a natural language, studied more formally." Why it's wrong: the word "language" tempts students to think of English or Hindi grammar rules. Correct explanation: a formal language is a mathematical set of strings, defined precisely enough that a computer can decide membership. Natural languages are far too ambiguous and context-dependent to be formal languages in this sense — that's why NLP needs statistical and machine-learning methods on top of formal grammars, not instead of them.

Misconception 2: "Every language needs a unique grammar, so if I know the grammar I know everything about the language's power." Why it's wrong: it seems intuitive that one grammar corresponds to one "difficulty level." Correct explanation: the same language can often be generated by grammars of different Chomsky types (a regular language can technically be described by a context-free grammar too, since Type 3 is a subset of Type 2). What matters for classification is the most restrictive type that can still generate the language — that's the language's true "level" in the hierarchy.

Misconception 3: "Context-sensitive grammars are only slightly more powerful than context-free grammars, so they're rarely worth distinguishing." Why it's wrong: the names sound similar and both allow context to influence rewriting, making the gap feel small. Correct explanation: the gap is large in practice — nearly all real programming-language syntax is captured by context-free grammars, and true context-sensitivity (like enforcing that a variable is declared before use) is usually handled outside the grammar, in a separate semantic-analysis phase, precisely because context-sensitive parsing is far more expensive than context-free parsing.

Comparison and Connections

Grammar typeRestrictionRecognizing automatonTypical parsing costExample
Type 3 (Regular)AaBA \to aB or AaA \to aFinite automatonLinear, O(n)O(n)Regex patterns, tokenizers
Type 2 (Context-free)AβA \to \betaPushdown automatonUsually O(n3)O(n^3) or betterProgramming language syntax
Type 1 (Context-sensitive)αβ\|\alpha\| \leq \|\beta\|Linear bounded automatonExponential in generalNatural-language agreement rules
Type 0 (Unrestricted)NoneTuring machineNot guaranteed to haltAny computable rewriting system

Practice Questions

Recall

  1. What are the four components of the formal definition of a grammar? Answer guidance: NN (non-terminals), TT (terminals), PP (production rules), SS (start symbol).
  2. Name the four levels of the Chomsky hierarchy from most to least restrictive. Answer guidance: Type 3 (regular) is most restrictive, then Type 2 (context-free), Type 1 (context-sensitive), Type 0 (unrestricted) is least restrictive.

Understanding

  1. Explain why every regular language is also a context-free language, but not vice versa. Answer guidance: every Type 3 rule (AaBA \to aB or AaA \to a) already satisfies the weaker Type 2 restriction (left side is a single non-terminal), so any regular grammar is automatically a valid context-free grammar. The reverse fails because CFGs allow rules like S(S)S \to (S) that no regular grammar can express.
  2. Why can't balanced parentheses be described by a regular grammar? Answer guidance: recognizing balanced parentheses requires tracking arbitrarily deep nesting (an unbounded count), which needs the recursive self-reference S(S)S \to (S) that only context-free (or higher) grammars allow; a regular grammar's rules can only append one terminal at a time with no way to "remember" nesting depth.

Application

  1. Write a context-free grammar that generates the language {anbnn0}\{a^n b^n \mid n \geq 0\}. Answer guidance: SaSbϵS \to aSb \mid \epsilon. Each application of the first rule adds one a on the left and one b on the right, keeping the counts equal.
  2. A configuration file format allows nested {...} blocks to any depth. Which Chomsky type is the minimum needed to describe its syntax, and why? Answer guidance: Type 2 (context-free) — nesting to arbitrary depth needs the same recursive matching mechanism as balanced parentheses, which is beyond regular (Type 3) grammars.

Analysis

  1. Compare context-free and context-sensitive grammars in terms of rule restrictions and practical parsing cost. Answer guidance: CFG rules must have a single non-terminal on the left (AβA \to \beta); context-sensitive rules only require the right side to be at least as long as the left (αβ|\alpha| \leq |\beta|), which allows context to influence rewriting. This added flexibility makes context-sensitive parsing far more expensive (worst case exponential) than context-free parsing (worst case polynomial), which is why compilers keep syntax rules context-free and push context-sensitive checks (like type checking) into a later phase.
  2. A student claims "since Type 0 grammars can generate any recursively enumerable language, they should be used for compiler front-ends because they're the most powerful." Explain why this reasoning is flawed. Answer guidance: raw generative power is not the goal — efficient, predictable parsing is. Type 0 grammars correspond to full Turing-machine computation, which offers no guarantee that parsing will even terminate, let alone run quickly. Compilers deliberately use the weakest grammar class (context-free, sometimes with limited context-sensitive checks layered on) that can still express the language, because weaker classes admit fast, well-understood parsing algorithms.

FAQ

Q1: Is a "formal language" the same as a programming language? Not exactly — a programming language's syntax is a formal language (usually context-free), but the programming language as a whole also includes semantics (what the code means), which formal language theory alone doesn't capture.

Q2: Why does the Chomsky hierarchy matter if I'll never write a grammar by hand professionally? Because every time you use a regex, write a parser, or debug why a config file "isn't valid JSON," you're bumping into the boundary between regular and context-free power. Knowing the hierarchy tells you immediately whether a problem is solvable with a regex or needs a real parser.

Q3: Can one language have grammars at multiple Chomsky levels? Yes — any regular language technically has a context-free (and context-sensitive, and unrestricted) grammar too, since each class is a superset of the ones below it. What's meaningful is the most restrictive class that can generate the language; that's the language's true classification.

Q4: What's the difference between a derivation and a parse tree? A derivation is the step-by-step sequence of rule applications; a parse tree is a picture of the same process, showing which symbol expanded into which children. Different derivation orders (leftmost vs. rightmost) can produce the same parse tree.

Q5: Why do some grammars generate the same string in two different ways (ambiguity)? This happens when a grammar allows more than one distinct parse tree for the same string — a serious problem for compilers, since it means the same code could be interpreted two different ways. Ambiguous grammars (like the classic "dangling else" in if-statements) are usually rewritten with extra non-terminals to force a single unambiguous parse.

Quick Revision

  • A formal language is a set of strings over a finite alphabet — nothing more.
  • A grammar G=(N,T,P,S)G = (N, T, P, S) generates a language via production rules starting from SS.
  • Derivation = step-by-step rewriting from the start symbol to a target string.
  • Chomsky hierarchy, most to least restrictive: Type 3 (regular) ⊂ Type 2 (context-free) ⊂ Type 1 (context-sensitive) ⊂ Type 0 (unrestricted).
  • Type 3 rules: AaBA \to aB or AaA \to a — recognized by finite automata.
  • Type 2 rules: AβA \to \beta (single non-terminal on the left) — recognized by pushdown automata.
  • Type 1 rules: right side at least as long as left side — recognized by linear bounded automata.
  • Type 0: no restrictions — recognized by Turing machines; may not even halt.
  • Languages support union, concatenation, and Kleene star — the building blocks of regular expressions.
  • Regular languages are closed under all three operations; this guarantees regex engines always compile.
  • The same language can have grammars at multiple Chomsky levels; classification uses the most restrictive one that works.
  • The Chomsky hierarchy mirrors the automaton hierarchy exactly: FA ↔ regular, PDA ↔ context-free, TM ↔ unrestricted.

Prerequisites: Automata Theory (finite automata, PDAs, and the machine hierarchy this grammar hierarchy mirrors), basic set theory.

Related Topics: regular expressions, parser design in compiler construction, closure properties of language classes.

Next Topics: Turing Machines (the machine that recognizes Type 0 languages), Computational Complexity (how efficiently these languages can be parsed and decided).