Master the fundamental concepts of syntax analysis through this focused micro-challenge.
Most production parsers start as recursive descent: one function per grammar rule, mutual recursion for expressions and statements. Python's parser, many DSL compilers, and Clang's early parsing paths use this style because it maps directly onto the grammar and produces great errors.
Write parse_expression(), parse_statement(), parse_function() that consume tokens and return AST nodes. Each function checks the current token, dispatches on it, and recursively calls sub-parsers. Left recursion in the grammar must be rewritten or handled with precedence climbing.
cLoading…
peek() inspects without consuming; advance() moves forwardProduction 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 implement a recursive descent parser that consumes your lexer's token stream and builds an AST. This exercise requires parsing expressions with correct operator precedence and handling statements, function declarations, and blocks.
Write a recursive-descent parser for expressions, with one C function per precedence level, and print the tree it builds as an S-expression so precedence and associativity are visible.
One expression per line. Blank lines are ignored. Tokens:
0: 9 runs) and identifiers ([A-Za-z_][A-Za-z0-9_]*)== != < > <= >= + - * / ! and parentheses ( )cLoading…
All binary operators are left-associative: a - b - c is (- (- a b) c).
One line per input line:
(OP LEFT RIGHT);(neg X) and ! as (not X);If the line is not a valid expression, print only the first error instead:
| Situation | Output |
|---|---|
| a character that starts no token | error at column C: unexpected character 'X' |
primary finds no number, identifier or ( | error at column C: expected expression |
a ( group is not closed | error at column C: expected ')' |
| a complete expression is followed by more tokens | error at column C: unexpected token 'TEXT' |
C is the 1-based column where the offending token starts; at the end of the line it is the line length + 1. The lexer's error wins if the bad character is reached first (i.e. tokens are read on demand, left to right).
Input:
cLoading…
Output:
cLoading…
Parser holding the current token, with advance, check and match helpers.Hidden tests cover every comparison operator, chains of unary operators, deep nesting, and each of the four errors.
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 works