The interpreter pattern is a design pattern that specifies how to evaluate sentences or given expressions in a language.
Interpreter Design pattern comes under Behavioural Pattern. The main motive behind the Interpreter design pattern is to implement an interface(s) that provides the context(evaluation) of the given expression(s).
- As there are interpreters for programming languages like python, which converts high-level language to low-level language.
- OR, Google Translator, which is also an example of an interpreter pattern where the input can be in any language and we can get the output interpreted in another language.
The Interpreter design pattern lets us define our own set of rules for our application as classes.
As an interpreter for programming language involves first converting tokens in the expression into lexemes, then constructing syntax-tree of lexemes as per given grammar, that is finally used to compute the final result of the expression.
Grammar: A set of rules- defining how our expressions look like, for our language.
Similarly, Interpreter Design Pattern also involves interfaces for converting lexemes and then an interface for constructing syntax-tree.
Since the Interpreter Design Pattern involves the concept of compiler design like lexemes production, syntax tree, and interfaces for same, Interpreter pattern is often overlooked due to its complexity.
Participants of Interpreter Design Pattern:
- Context: The class that contains information available to the interpreter.
- AbstractExpression: An interface that typically defines an operation.
- TerminalExpression: Main interpreter interface that implements an operation associated with the terminal symbols as defined in the grammar.
- NonTerminalExpression: Interface that is typically used to implement the logical operators (AND, OR, etc.) between terminal and nonterminal expressions
- Client: Interface that builds a syntax tree or is provided with a syntax tree that represents a sentence in the language defined by the grammar. The client typically initiates the interpret operations.
Given Expressions –
- a = 5
- b = 10
- c = 15
- d = a*b+c
Syntax tree will be like this:
Here, a, b, and c represents numerical values, assigning values to the variable will be the terminal operation represented by terminal expression(i.e. a=5 or b= 10, etc.) and expression for d (i.e. a*b+c) is a non-terminal expression.
class AbstractExpression(): @abstractmethod def interpret(self): pass
class NonterminalExpression(AbstractExpression): def __init__(self, expression): self._expression = expression def interpret(self): self._expression.interpret()
class TerminalExpression(AbstractExpression): def interpret(self): pass
The driver code will be like this:
def main(): abstract_syntax_tree = NonterminalExpression(TerminalExpression()) abstract_syntax_tree.interpret() if __name__ == "__main__": main()
Pros and Cons Of Interpreter Design Pattern
- Makes it easier to implement our own set of rules(grammar).
- Adds complexity to the code of the application.