Behavioral

Interpreter

Interpreter turns a sentence in a small language - say, the expression `x + 5 - 2` - into a tree of objects, one class per rule (number, variable, addition, subtraction). Getting the answer is just calling one method on the root: each object works out its own piece by asking its children for theirs, so the tree evaluates itself.

Complexity
Popularity

Problem

Imagine building a small calculator that evaluates arithmetic expressions typed in as text, like `x + 5 - 2`, where `x` is a variable that can hold any number. The rules are tiny - numbers, variables, addition, subtraction - but they combine in endless ways: `x + 5`, `(x + 5) - 2`, `2 - (x + 5)`, and so on.

A quick fix is one big function that scans the string and handles each case with a pile of if/else. It works for a couple of examples, then falls apart as soon as expressions nest deeper or a new operator shows up, because parsing and evaluating are tangled together in one place with no reusable pieces.

What's missing is a way to treat "a number", "a variable", "a sum", and "a difference" as separate, composable building blocks - instead of special cases buried inside one big block of code.

Solution

Interpreter turns each grammar rule into its own class, all sharing one `interpret` method that produces a result when called. Simple pieces of the expression - a number, a variable - become terminal expression classes that know their value directly. Compound pieces - a sum, a difference - become nonterminal expression classes that hold their sub-expressions and combine whatever those return.

The expression `x + 5 - 2` is built once into a small tree: a subtraction node holding an addition node (variable `x` and number `5`) and a number node (`2`). Evaluating the whole expression is just calling `interpret` on the root - the recursion works its way down the tree and combines the results back up. Adding a new operator, like multiplication, means adding one new nonterminal class - the rest of the tree, and the rest of the grammar, doesn't change.

When to Use

  • Reach for Interpreter when the language you need to evaluate is genuinely small and its sentences map cleanly onto a tree of a handful of rule types.
  • It pays off when the grammar is expected to stay stable; a rapidly growing rule set is a sign to switch to a parser generator instead.
  • It's a reasonable choice when raw evaluation speed matters less than having a clear, testable, one-rule-per-class model of the language.

Real-World Examples

  • **Regex engines** - a compiled pattern becomes a tree of matcher nodes (literal, concatenation, alternation, repetition) that walk an input string and report a match.
  • **ORM query builders** - libraries like SQLAlchemy or Django's ORM build a tree of filter and predicate objects from chained method calls, then interpret that tree into SQL at execution time.
  • **Spreadsheet formula engines** - an expression like `=A1 + B2 * 2` is parsed into a tree of cell references and operators that the spreadsheet interprets to produce the cell's displayed value.