Error Recovery
Learn how parsers detect syntax errors and recover from them to continue parsing — so the compiler can report multiple errors in one pass rather than stopping at the first one.
Why Does Error Recovery Matter?
When a parser encounters a token it did not expect, it has found a syntax error. The simplest approach is to stop immediately and report the error — but this is bad for the developer.
Imagine compiling a file with 10 syntax errors. A compiler that stops at the first error forces you to fix one error, recompile, find the next error, fix it, recompile... 10 times.
A good compiler detects one error, recovers, and continues parsing to find as many subsequent errors as possible. This way, the developer sees all problems at once.
Error recovery is the difference between a frustrating compiler and a helpful one.
Types of Errors in a Compiler
Before looking at recovery strategies, it helps to know what kinds of errors a compiler can encounter:
| Error Type | Phase | Example |
|---|---|---|
| Lexical error | Lexer | Illegal character @ in code |
| Syntax error | Parser | Missing semicolon, unbalanced parenthesis |
| Semantic error | Semantic analysis | Using undeclared variable |
| Logical error | (Not caught by compiler) | Wrong algorithm, off-by-one |
The parser handles syntax errors. It knows what token it expected (based on the grammar) and what it actually received — and uses that information to recover.
How the Parser Detects an Error
A parser reports an error when the current input token does not match any valid production for the current grammar rule.
Panic Mode Recovery
Panic mode is the simplest and most widely used error recovery strategy. When an error is found, the parser:
- Discards input tokens one at a time until it finds a synchronisation token — a token that is likely to start a new valid statement (like
;,}, or a keyword likeif,while,return). - Resumes parsing from that synchronisation point.
Example — Panic Mode in Action
Grammar (simplified C-like statements):
Input with error:
What happens:
Choosing Synchronisation Tokens
The choice of synchronisation tokens is critical:
| Language Feature | Typical Synchronisation Tokens |
|---|---|
| Statement-based (C, Java) | ;, }, { |
| Block-based | Keywords: end, fi, else |
| Declaration-based | int, void, class |
Good synchronisation tokens are ones that cannot appear inside most expressions — they clearly mark the boundary between statements.
Pros and Cons
| Aspect | Detail |
|---|---|
| ✓ Simple to implement | No complex state tracking needed |
| ✓ Never enters infinite loop | Always makes forward progress |
| ✗ May miss errors | Skipping tokens hides nearby errors |
| ✗ Can skip too much | Large chunks of valid code may be discarded |
Phrase-Level Recovery
Phrase-level recovery is more precise than panic mode. Instead of blindly skipping tokens, the parser makes a local correction — inserting or deleting a single token to make the input valid.
Common Corrections
| Problem | Correction |
|---|---|
| Missing token | Insert the expected token into the input stream |
| Extra token | Delete the unexpected token |
| Misspelled keyword | Replace the token with the correct one |
Example — Inserting a Missing Token
Example — Deleting an Extra Token
Pros and Cons
| Aspect | Detail |
|---|---|
| ✓ Precise | Minimal disruption to the parse |
| ✓ Good error messages | "Expected '(' here" is actionable |
| ✗ Can loop | Inserting the wrong token may cause another error immediately |
| ✗ Harder to implement | Must choose corrections carefully |
Error Productions
Error productions augment the grammar with special rules that match common mistakes. The grammar explicitly handles known error patterns so the parser can report a useful message and continue.
How It Works
You add extra productions to the grammar of the form:
When the parser matches the error form, it reports a specific, targeted error message.
Example — Common Mistake: Exponent Operator
In some languages, beginners confuse ^ (bitwise XOR in C) with the power operator. We can add an error production:
When the parser sees term ^ factor, it reports:
Example — Missing Operator
Error message: Missing operator between expressions on line 7
Pros and Cons
| Aspect | Detail |
|---|---|
| ✓ Very user-friendly | Error messages target specific common mistakes |
| ✓ Compiler can still build a partial tree | Good for IDEs |
| ✗ Grammar grows larger | More productions to maintain |
| ✗ Only handles anticipated mistakes | Does not catch unexpected errors |
Global Correction
Global correction is the theoretically ideal strategy. Given the erroneous input string, find the minimum number of insertions, deletions, and replacements needed to turn it into a valid string, and report those as the errors.
This is similar to computing the edit distance between two strings.
Why Global Correction is Rarely Used
| Reason | Detail |
|---|---|
| Very slow | Computing the minimum edit is expensive — O(n · |
| Not always useful | "Minimum edits" may not match the programmer's intent |
| Complex to implement | Requires powerful dynamic programming algorithms |
Global correction is mainly a theoretical concept. Real compilers use panic mode or phrase-level recovery because they are fast and good enough in practice.
Summary of Recovery Strategies
| Strategy | Approach | When to Use |
|---|---|---|
| Panic mode | Skip tokens until a sync token | Fast, simple — most common |
| Phrase-level | Insert or delete a single token | When precise messages are needed |
| Error productions | Add grammar rules for common mistakes | When you know the typical errors |
| Global correction | Find minimum edits | Theoretical; rarely practical |