Each non-terminal becomes a function. The parser works by calling those functions recursively, matching the input from left to right.
A top-down parser that matches input by calling mutually recursive functions.
Every non-terminal in the grammar gets its own parsing function. E, T, F each become E(), T(), F().
Each function peeks at the next input token (lookahead) to decide which production rule to apply — no backtracking needed.
The call sequence mirrors the leftmost derivation: calling E()→T()→F() corresponds to E → T → F.
Look at the current input token without consuming it. Returns the terminal at the current position.
Consume the current token if it matches c. Otherwise, report a syntax error and stop.
Call the parsing function for a non-terminal. It recursively parses the input until that NT is fully matched.
Why a naive grammar causes infinite recursion — and stack overflow.
Transform the grammar systematically so recursive descent parsing works.
The right-recursive A' handles the repeating suffix, while A starts fresh with the base case β.
+ T and β = T…
+ T (the left-recursive suffix), β = T (the base case). The new rule E' loops right-recursively or terminates with ε.
* F and β = F…
* F, β = F. Now T() won't call itself first — it calls F() then delegates repetition to T'.
Each non-terminal becomes a function in the recursive descent parser.
#include <iostream> #include <string> using namespace std; string input; int pos = 0; char peek() { return pos < input.size() ? input[pos] : '$'; } void match(char c) { if (peek() == c) pos++; else { cout << "Error: expected '" << c << "'\n"; exit(1); } } void E_prime(); void T(); void T_prime(); void F(); // ── E → T E' ────────────────────────────── void E() { cout << "E()\n"; T(); E_prime(); } // ── E' → + T E' | ε ─────────────────────── void E_prime() { cout << "E_prime()\n"; if (peek() == '+') { match('+'); T(); E_prime(); } // else epsilon — do nothing } // ── T → F T' ────────────────────────────── void T() { cout << "T()\n"; F(); T_prime(); } // ── T' → * F T' | ε ─────────────────────── void T_prime() { cout << "T_prime()\n"; if (peek() == '*') { match('*'); F(); T_prime(); } // else epsilon — do nothing } // ── F → (E) | id ────────────────────────── void F() { cout << "F()\n"; if (peek() == '(') { match('('); E(); match(')'); } else if (peek() == 'i') { // 'id' represented as 'i','d' match('i'); match('d'); } else { cout << "Error: unexpected '" << peek() << "'\n"; exit(1); } } int main() { input = "id+id*id"; E(); if (peek() == '$' || pos >= (int)input.size()) cout << "Accept!\n"; return 0; }
Step through parsing id + id * id and watch the call stack evolve.