Parsing Programs: Declarations and Statements
Work through examples, try the reasoning yourself, then put it into practice.
View SlidesBefore you start
- Use v2 tokens and the expression precedence chain.
What you will practice
- Partition a program into declarations and statements.
- Disambiguate assignment from equality without semantic lookup.
- Build statement fields and enforce v2 function placement.
In this lesson
Lesson
3 min readParsing Programs: Declarations and Statements
Parse now returns *Program, whose Stmts are declarations and statements.
The expression grammar remains a reusable component. At top level, a fn
starts a function declaration; other tokens enter statement dispatch. Inside
blocks, v2 only accepts statements, so a nested fn is a parser error.
Worked reconstruction
Parse let x=2; x=x+3; if (x==5) { x; }:
| Segment | AST statement | Important child |
|---|---|---|
let x=2; |
variable declaration named x | Number(2) initializer |
x=x+3; |
assignment named x | Add(Ident(x),Number(3)) |
if (x==5) { x; } |
if statement | Eq(x,5), body containing an expression statement |
= and == have different token kinds. Assignment dispatch uses an identifier
followed by single =; the double-equality token remains inside the expression
parser. The parser accepts an assignment shape even if x is not declared; name
resolution is the next stage.
A declaration or expression statement owns its final semicolon. A block owns its closing brace. Recursive calls should leave the cursor at the first token after the construct they consumed. On EOF inside an open block, return an error rather than looping forever or pretending a brace appeared.
Call and return boundaries
A v2 call stores its callee name in ExprCall.Value; arbitrary-expression calls
are not available yet. A return with no expression has a nil expression field,
while return nil; has an explicit nil-literal expression. Both return nil at
runtime after compilation, but their syntax trees differ.
return 1; at top level is syntactically a return statement. The analyzer rejects
its placement. This distinction is useful when debugging: moving return legality
into the parser changes which stage owns the diagnostic. Parameter names also
parse without proving they are unique; that is a semantic check.
Debugging lab
A parser handles x==2; as an assignment and rejects top-level return 2; before building a statement. Identify the token-dispatch defect and the phase-ownership defect.
Compare your diagnosis after attempting the lab
Only TokenAssign selects assignment; TokenEqual belongs to expression parsing. Top-level return has valid statement syntax and must reach analysis, which reports return outside function.
Transfer task
Draw the Program tree for a function with two parameters followed by a call used as an expression statement. Then move the function inside an if block and predict the v2 parsing failure. Repeat that placement prediction after studying v3.
Carry forward
Carry complete statement trees into name analysis. Keep syntax tests free of assumptions about whether a referenced variable or function exists.
Build program-parser. Keep a before/after trace of one failing test. Use the checkpoint to diagnose specific skills; passing it does not replace implementing and testing the artifact.
Practice sequence
Use the order below for a guided path, or choose an item to revisit. A pass records a successful attempt; try a fresh example later to check what you can reconstruct.