Your Guide to Design Patterns – Interpreter Pattern (Part 1)

Design Patterns - Interpreter Pattern

This week we’ll continue our exploration of design patterns and look at another behavioural pattern, the Interpreter pattern.

The Gang of Four book defines the Interpreter pattern as:

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

Understanding the Interpreter Pattern

The Interpreter pattern allows us to implement a simple language to use inside an application. We define a class to represent each rule of the language (its grammar). We also implement an interpreter that operates on instances of these classes. This interpreter parses and executes the sentences of the language.

The pattern works well when we have a simple language/grammar to implement. As the grammar gets more complex, it becomes harder to maintain. With a large number of language rules, tools like parser generators are better options. These tools can interpret expressions without building abstract syntax trees. This is more efficient and can save memory space.

We very rarely use the Interpreter pattern, because as developers we hardly ever create our own languages. To use it properly, we need to know a lot about formal grammars. Formal grammars are used to create languages.

Examples of the Interpreter Pattern

A well-known example of an interpreter is JavaScript code that runs in a web page on a browser. JavaScript is an programming language, and as such, has a grammar representation. A JavaScript interpreter uses that grammar representation to interpret and run JavaScript code. A JavaScript interpreter is built into every major browser.

SQL is another good example. An SQL interpreter is built into all relational database management systems.

In Java SE, the Interpreter pattern is used in the java.util.Pattern and java.text.Normalizer classes and all subclasses of java.text.Format.

Other examples of the Interpreter pattern are the Unified Expression Language (javax.el API) used in JSP and JSF, and the Spring Expression Language (SpEL).

Expression Hierarchy

We use the Interpreter pattern to define a class-based representation for the grammar of our language.

We create an AbstractExpression interface (or abstract class) as the root of our class hierarchy. This is used to interpret a context. The interface defines an abstract interpret() method that takes the context as a parameter. The context is an input stream (generally a string) containing the language sentences that must be parsed.

We then create concrete classes implementing the AbstractExpression interface. Each class represents an expression in our language. Each expression can be either a terminal or non-terminal expression:

  • Terminal expressions are the basic elements of our language. We define these with a formal grammar.
  • Non-terminal expressions (also called syntactic variables) are replaced by groups of terminal symbols based on the grammar rules. The non-terminal classes are generally implemented using a composite design pattern, while the terminal expressions are leaf objects.

A non-terminal expression may have one or more AbstractExpressions associated in it. This means it can be recursively interpreted. The interpretation process ends with a terminal expression that returns the result.

Representing each grammar rule as a class makes the language easy to implement, change or extend. We can even add extra methods to the classes (other than the interpret() method) to support extra functionality like validation and pretty printing.

The Interpreter

We also need to create an interpreter that deals with this grammar. All of the expressions need to be processed, and from them we build an Abstract Syntax Tree (AST). The AST is just a sentence defined using the syntax of our language. This sentence is the context. The interpreter then parses the AST and produces the required output.

To interpret the language, we call the interpret() method on each expression type. The interpret() method is passed the context. It then matches and evaluates the expressions, and returns a result. Each expression will affect the context, change its state, and either continue the interpretation or return the result. The context is reused by all expressions during the interpretation process.

Interpreter Pattern: Design Example

Going back to our first person shooter game, we’ve already created mechanised fighting units. We’ve also developed remote controls that allow us to command them to fight and move towards specific targets. (See the post on the Command pattern).

We now decide that it will be a great new feature for players to be able to type in a string of commands that the fighting units could interpret and run. A player could even strategise an entire troop deployment and attack plan, and save this as a small text file that could be run by the command interpreter.

We will have to define a grammar for this language. At first we’ll make it fairly small, with the possibility of expanding it later. What sort of commands would we like to run? Our first thoughts may lead us to a set of commands like:

with unit #number
   move x, y
   attack if enemy found
   retreat if health < 20%
end with

Implementation

The code implementation of this language is somewhat long for one post, so we’ll leave this post on a cliff-hanger, and continue it in the next post.

Stay tuned, and watch out for the conclusion of the Interpreter pattern!

As always, please share your comments and questions.

Leave a Comment

Your email address will not be published. Required fields are marked *

Code like a Java Guru!

Thank You

We're Excited!

Thank you for completing the form. We're excited that you have chosen to contact us about training. We will process the information as soon as we can, and we will do our best to contact you within 1 working day. (Please note that our offices are closed over weekends and public holidays.)

Don't Worry

Our privacy policy ensures your data is safe: Incus Data does not sell or otherwise distribute email addresses. We will not divulge your personal information to anyone unless specifically authorised by you.

If you need any further information, please contact us on tel: (27) 12-666-2020 or email info@incusdata.com

How can we help you?

Let us contact you about your training requirements. Just fill in a few details, and we’ll get right back to you.

Your Java tip is on its way!

Check that incusdata.com is an approved sender, so that your Java tips don’t land up in the spam folder.

Our privacy policy means your data is safe. You can unsubscribe from these tips at any time.