Master the fundamental concepts of syntax analysis through this focused micro-challenge.
You have read the whole brief, and the concepts above stay free on every task. Writing and running the code needs a plan.
Three hints are available for this task, revealed one at a time inside the code workspace so you can struggle productively before seeing them.
Every task includes starter code, theory, and hidden tests so you can implement and verify locally in the browser.
How it worksA parser that stops at the first syntax error frustrates users fixing large files. GCC and Clang use panic-mode recovery and synchronization tokens (semicolons, braces) to skip to a safe point and continue. Rust's parser reports multiple errors in one run using similar techniques.
On unexpected token, report the error, then skip tokens until a synchronizing token appears: ;, }, or a statement keyword. Resume parsing at the next statement boundary. Insert an error node in the AST if you need to preserve structure.
cLoading…
Production compilers embed this step inside a longer pipeline. GCC flows through cpp, cc1, assembly, and ld; Clang uses the driver, Sema, LLVM IR passes, and a target backend. LLVM bitcode, JVM bytecode, and WASM are other familiar IRs at the same layer. The exercise isolates one pass so you can test it alone before chaining it to the next stage.
You will add error recovery to your parser so syntax errors do not abort the entire parse. This exercise asks you to synchronize at statement boundaries and continue building a partial AST after reporting each error.
Add panic-mode error recovery to the statement parser from Statement Parsing, so one run reports every syntax error in the file instead of stopping at the first one: without drowning the user in cascading errors.
Statements on stdin, using exactly the grammar, tokens and error messages of Statement Parsing (blocks, if/else, while, return, empty statements, expression statements, right-associative assignment).
Report, then panic. When a rule hits an error, print it immediately as error at LINE:COL: MESSAGE and enter panic mode. While in panic mode no further errors are reported; every rule returns as soon as possible.
Synchronize in the nearest statement list. Control returns to the innermost enclosing statement list (a block's { ... } loop, or the top-level program loop). That loop then synchronizes: it discards tokens until either
; has been discarded (resume right after it), or}, {, if, while or return (resume at it, without discarding), orPanic mode ends and the loop parses the next statement.
Top-level stray }. If synchronization at the top level stops at a }, discard that } too (otherwise the parser would stop on it forever).
A block that reaches EOF reports expected '}' at the EOF position. Each unclosed block reports its own error, innermost first.
Each error line as it is found, then:
cLoading…
N is the number of top-level statements that were parsed without any error inside them; M is the number of error lines printed. A clean file prints only the summary line.
Input:
cLoading…
Output:
cLoading…
Line 3 shows both recovery paths: the if fails at b, synchronization stops at {, and the block then gets its own error at }.
panic flag on the parser plus a synchronize() function; statement lists call it after any statement that set the flag.Hidden tests put errors inside nested blocks and loops, include a stray }, an unclosed block at EOF, and a fully valid file.