Parsing Programs: Declarations and Statements

Lesson, slides, and applied problem sets.

View Slides

Lesson

Parsing Programs: Declarations and Statements

Why this module exists

We already know how to parse expressions. Now we need to parse programs: a list of declarations and statements. This is the step that turns a single expression parser into a real language front end.


1) Program grammar (v2)

program    -> decl* EOF

decl       -> funDecl | stmt
funDecl    -> "fn" IDENT "(" params? ")" block
params     -> IDENT ("," IDENT)*

stmt       -> varDecl
           | ifStmt
           | whileStmt
           | returnStmt
           | block
           | assignStmt
           | exprStmt

varDecl    -> ("let" | "var" | "const") IDENT ("=" expr)? ";"
assignStmt -> IDENT "=" expr ";"
exprStmt   -> expr ";"
block      -> "{" stmt* "}"

ifStmt     -> "if" "(" expr ")" block ("else" block)?
whileStmt  -> "while" "(" expr ")" block
returnStmt -> "return" expr? ";"

We still use the same expression grammar from earlier modules.


2) Structure over cleverness

Parse statements with small, direct functions:

  • parseDecl for top-level
  • parseStmt for statements
  • one function per statement kind

Readable control flow beats clever tricks here.


3) AST shape

We keep a single Stmt struct with a Kind enum and explicit fields (Name, Expr, Body, Else, Params). This is easy to inspect and extend.


4) Errors

Good parse errors are precise:

  • "expected ';' after expression"
  • "expected ')' after condition"

The error message should help the learner fix the input quickly.


Module Items