Skip to content
Parsing Statements & Declarations
step 1/5

Reading — step 1 of 5

Read

~2 min readLexing & Parsing

Parsing Statements & Declarations

Expressions are only half of the story. A C function body is a sequence of statements: declarations, assignments, control flow, blocks, returns.

int x = 5;          // declaration
x = x + 1;          // assignment expression statement
if (x > 0) ...      // selection statement
while (x) x = x - 1;// iteration statement
return x;           // jump statement
{ int y; ... }      // compound statement

Grammar

A typical hand-written recursive descent parser dispatches on the first token:

stmt    := decl
         | "if" "(" expr ")" stmt ("else" stmt)?
         | "while" "(" expr ")" stmt
         | "return" expr? ";"
         | "{" stmt* "}"
         | IDENT "=" expr ";"
         | expr ";"

decl    := type IDENT ("=" expr)? ";"
type    := "int" | "char" | type "*"

Why one-token lookahead is enough

C is almost LL(1). Each statement form is distinguishable by its first token:

  • int / char → declaration.
  • if / while / return → control flow.
  • { → compound block.
  • IDENT → could be assignment OR expression — peek one token ahead.

The IDENT vs. assignment ambiguity is resolved with a tiny lookahead: see = after the identifier → assignment; otherwise it's a primary expression.

Compound statements introduce scope

A { ... } block opens a new lexical scope. Local declarations inside the block are not visible outside it. The parser usually emits a Block AST node; the type checker pushes/pops a symbol-table scope as it walks in/out.

Dangling-else

The classic ambiguity: if (a) if (b) X else Y — does else bind to the inner or outer if? C says inner (closest unmatched if). The recursive descent grammar above already handles this naturally: parse_if greedily consumes a trailing else if one is there.

What our exercise builds

A parser that turns a single mini-C statement (per input line) into an S-expression. The supported forms cover declarations (with/without init), assignments, if (no else), while, return (with/without value), blocks, and plain expression statements. We use a flat left-associative expr (no precedence inside this exercise — the previous lesson already covered that).

References: chibicc parse.c, Sandler Ch. 5 (parsing statements), Crafting Interpreters Ch. 8.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…