Parsing Programs: Declarations and Statements

Work through examples, try the reasoning yourself, then put it into practice.

View Slides

Before 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 read

Parsing 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.

Join Discord