Interpreter
- Given a language, define a represention for its grammar along with an
interpreter that uses the representation to interpret sentences in the
language.

- AbstractExpression(RegularExpression): declares an abstract
Interpret operation that is common to all nodes in the abstract syntax
- TerminalExpression(LiteralExpression): implements an Interpret
operation associated with terminal symbols in the grammar. an instance is
required for every terminal symbol in a sentence.
- NonterminalExpression(AlternationExpression, RepetitionExpression,
SequenceExpressions): one such class is required for every rule R ::= R1
R2 ... Rn in the grammar. maintains instance variables of type
AbstractExpression for each of the symbols R1 through Rn. implements an
Interpret operation for nonterminal symbols in the grammar. Interpret
typically calls itself recursively on the variables representing R1 through
R.
- Context: contains information that's global to the interpreter.
- Client: builds (or is given) an abstract syntax tree representing a
particular sentence in the language that the grammar defines. The abstract
syntax tree is assembled from instances of
the NonterminalExpression and TerminalExpression classes. invokes the
Interpret operation.
- l the grammar is simple. For complex grammars, the class hierarchy for the
grammar becomes large and unmanageable. Tools such as parser generators are
a better alternative in such cases. They can interpret expressions without
building abstract syntax trees, which can save space and possibly time.
- efficiency is not a critical concern. The most efficient interpreters are
usually not implemented by interpreting parse trees directly but by first
translating them into another form. For example,
regular expressions are often transformed into state machines. But even
then, the translator can be implemented by the Interpreter pattern, so the
pattern is still applicable.
- It's easy to change and extend the grammar. Because the pattern
uses classes to represent grammar rules, you can use inheritance to change
or extend the grammar. Existing expressions
can be modified incrementally, and new expressions can be defined as
variations on old ones.
- Implementing the grammar is easy, too. Classes defining nodes in
the abstract syntax tree have similar implementations. These classes are
easy to write, and often their generation can be
automated with a compiler or parser generator.
- Complex grammars are hard to maintain. The Interpreter pattern
defines at least one class for every rule in the grammar (grammar rules
defined using BNF may require multiple classes).
Hence grammars containing many rules can be hard to manage and maintain.
Other design patterns can be applied to mitigate the problem (see
Implementation). But when the grammar is
very complex, other techniques such as parser or compiler generators are
more appropriate.
- Adding new ways to interpret expressions. The Interpreter pattern
makes it easier to evaluate an expression in a new way. For example, you can
support pretty printing or type-checking an expression by defining a new
operation on the expression classes. If you keep creating new ways of
interpreting an expression, then consider using the Visitor pattern to avoid
changing the grammar classes.
กก