Crafting a parser, part 5: error recovery and diagnostics
A parser that gives up on the first syntax error is fine for a homework interpreter and useless for everything else. Compilers and editors must report many errors per run and keep producing a usable tree. This post is about parsing that bends instead of breaking.
Errors are data, not exceptions
Don't panic! or bail with the first surprise. Push a diagnostic into a list, insert an
error node, and keep parsing.
12345678
Panic-mode recovery
When a rule is hopelessly lost, synchronize: skip tokens until you reach a known
boundary — a ;, a }, or the start of the next statement — then resume. You lose one
construct, not the rest of the file.
Good synchronization tokens are statement and block boundaries. Synchronizing on, say,
every + makes a single typo cascade into dozens of nonsense errors. Sync rarely, at
structural seams.
Diagnostics that don't lie
The message is half the product. "expected ;" with the span of the previous token
beats "syntax error" with no location. Carry the expected set and the found token; render
a caret under the source.
Deduplicate cascading errors: once you emit a diagnostic, suppress further ones until you have successfully consumed a token. One typo should yield one message, not ten.
Takeaways
- Record diagnostics and synthesize nodes; never stop at the first error.
- Panic-mode + structural sync points keep the rest of the file parseable.
- Spend effort on the message — expected/found with a real span.