The Interpreter Pattern provides a way to evaluate the syntax or expressions of a language. It belongs to the behavioral pattern and implements an expression interface that interprets a specific context. The Interpreter Pattern is often used in SQL parsing, symbol processing engines, and more.
In software development, there are often repetitive problems with a certain similarity and regularity. If these problems can be generalized into a simple language, then the instances of these problems will be sentences of that language. This can be implemented using the interpreter pattern from compilation theory. The interpreter pattern defines a language for analyzing objects and represents the grammar of the language. It then designs a parser to interpret the sentences in the language, that is, to analyze instances in the application in the same way as in compiled languages. The concepts of grammar and sentences mentioned here are the same as those described in compilation theory. The grammar refers to the language's syntax rules, while the sentences are elements of the language.
Expression
role: Declares an interface that all concrete expression roles need to implement. This interface mainly consists of an interpret()
method, called the interpretation operation.Terminal Expression
role: Implements the interface required by the abstract expression role, mainly an interpret()
method. Each terminal in the grammar has a specific terminal expression corresponding to it. For example, in a simple formula like R=R1+R2
, R1
and R2
are terminals, and their interpreters are terminal expressions.Nonterminal Expression
role: Each rule in the grammar requires a specific non-terminal expression. Non-terminal expressions are generally operators or other keywords in the grammar. For example, in the formula R=R1+R2
, +
is a non-terminal, and the interpreter for +
is a non-terminal expression.Context
role: The task of this role is generally to store the specific values corresponding to each terminal in the grammar. For example, in R=R1+R2
, we assign 100
to R1
and 200
to R2
. This information needs to be stored in the context role. In many cases, using a Map
as the context role is sufficient.