Learn the Interpreter Design Pattern
This is the 24th post in a series on design patterns.
Interpreter is a behavioral design pattern
that defines a grammatical representation for a language and provides an interpreter to deal with this grammar.
Interpreter Design Pattern
An example of the Interpreter design pattern is the Java compiler, which interprets Java source code into byte code that can be understood by the JVM.
Defining a domain language as simple language grammar, representing domain rules as language sentences, and interpreting these sentences to solve problems are all aspects of the Interpreter pattern. Grammar rules are represented by classes. Grammars are typically hierarchical in structure, so an inheritance hierarchy of rule classes maps nicely.
The interpreter pattern is used to process user input and build an Abstract Syntax Tree (AST).
The abstract base class specifies the method interpret(). Concrete subclasses implement interpret() by accepting the current state of the language stream and contributing to the problem-solving process.
UML Class Diagram
Not familiar with UML Class Diagram? I have written a detailed post on the UML Class diagram.
Implementation steps
- Decide if a little language is worth the investment.
- Specify the grammar of the language.
- Map the grammar productions to classes.
- Arrange the suite of classes into the Composite pattern.
- Provide an interpret(Context) method in the composition hierarchy.
- Context encapsulates the current state of the input and output as the former is parsed and the latter is accumulated. Each grammar class manipulates it as the interpreting process transforms the input into the output.
Source Code Implementation
There are two methods in the Context class to represent binary and hexadecimal numbers.
All nodes in the AST override the interpret() method defined by the abstract class Expression.
IntToHex extends Expression and implements the interpret() method.
The client calls the interpret() method of the Expression class.
// Output
105 in Binary: 1101001
105 in HexaDecimal: 69
When To Apply Interpreter Design Pattern
- When you need to implement a simple language, consider the Interpreter design pattern.
- When you have simple grammar, simplicity is more important than efficiency.
- Scripts and programming languages use simple grammar.
- The pattern can become cumbersome when the number of grammar rules is large. A parser/compiler generator may be more appropriate in these cases.
Pros of Interpreter Design Pattern
- By representing each grammar rule in a class, the language is easy to implement.
- The grammar is represented by classes, so you can easily modify or extend it.
- By adding methods to the class structure, you can add new behaviors beyond interpretation, such as pretty printing and more sophisticated program validation.