3.3 Interpreter
The Interpreter pattern defines a grammar for a little language and implements an interpreter to evaluate its sentences. When your program repeatedly processes some kind of structured expression — arithmetic formulas, boolean rules, query conditions, a configuration DSL — Interpreter maps each grammar rule to a class, parses a sentence into an abstract syntax tree, and evaluates it recursively.
The lab below lets you click numbers and operators to build a postfix (RPN) expression and watch the interpreter evaluate it step by step using a stack.
Grammar as classes
The heart of Interpreter is translating a grammar into a class hierarchy:
interface Expr { boolean interpret(Map<String,Boolean> ctx); }
// terminal expression: a variable
class Var implements Expr {
private String name;
public boolean interpret(Map<String,Boolean> ctx) { return ctx.get(name); }
}
// nonterminal expression: a composition
class And implements Expr {
private Expr left, right;
public boolean interpret(Map<String,Boolean> ctx) {
return left.interpret(ctx) && right.interpret(ctx); // recurse
}
}- Terminal expressions: the grammar's leaves — variables, literals.
- Nonterminal expressions: compositions of subexpressions —
And,Or,Plus.
A whole sentence is an expression tree, and interpret(context) evaluates it top-down recursively. The lab below lets you switch And/Or and flip variable values, watching the boolean expression tree evaluate.
Reality and boundaries
Interpreter is natural for rule engines, template languages, simplified subsets of SQL/regex, and calculators. But stay clear-eyed:
- Once the grammar gets complex, the class count balloons and maintenance hurts.
- Interpreter usually isn't about performance. Real languages use parser generators (like ANTLR), bytecode, or JIT — not an
interpret()per node.
Treat it as an entry-level tool for "small domain languages": best when the grammar is simple, changes often, and benefits from a readable object representation.