Design Pattern Examples
Overview of object-oriented design patterns
Interpreter Pattern

Diagram of the Interpreter Chain pattern

The interpreter pattern is used for situations where one thing needs to be interpreted in order to do or produce something else. What is being interpreted could be, for example, the keywords of a programming language to produce compiled code, the words in a sentence to determine meaning, or a series of numbers to control a robot's motion.

Python is an example of an interpreted scripting language. The commands and expressions typed in are interpreted and converted to tokens (numbers). These tokens are then interpreted to perform a specific set of actions. String all those tokens together and a functional program is the result.

In the same way, C# goes through a similar path of interpretation to produce abstract symbols (tokens) that are converted into an intermediate language that is then interpreted by the .Net (or Mono) runtime.

Programming languages such as C or C++ are interpreted to produce abstract symbols (tokens) that are converted directly into machine language (a discrete series of bytes or numbers) – which the CPU essentially interprets to produce some kind of action.

At a much higher level of abstraction, a domain-specific language could be used to make it simple to create business logic for an application. This domain- specific language typically consists of simple commands and parameters that, when executed in sequence, accomplish some task specific to the application. The process of executing the domain-specific language requires an interpreter. SQL (Structured Query Language) is an example of a domain-specific language, as it is dedicated to reading or writing data to a structured database.

In short, what is interpreted is a set of tokens that represent actions. The tokens can be arranged in an abstract syntax tree to provide more complex relationships between the tokens. Where these tokens come from is outside the interpreter's control.

What form the tokens take and what form the actions take after the tokens are interpreted is up to the application and the interpreter.

Note: Another example of an interpreter (which includes a parser) is shown in the Null Object Pattern example.

How to Use

Links to the Interpreter class or function
C++ C# Python C
Interpreter_Class class Interpreter_Class class Interpreter_Class class Interpreter_Interpret() function

The example provided here takes an array of integers and converts each into a text word or punctuation mark separated by a space from the previous token, forming a complete sentence. In essence, interpreting the list of tokens reverses the effects of a parser.

C++

void Interpreter_Exercise()
{
std::cout << std::endl;
std::cout << "Interpreter Exercise" << std::endl;
Interpreter_Class interpreter;
for (size_t sentenceIndex = 0; sentenceIndex < _sentenceTokenLists.size(); ++sentenceIndex)
{
const IntList& tokenList = _sentenceTokenLists[sentenceIndex];
std::string tokensAsString = _TokensToString(tokenList);
std::string sentence = interpreter.Interpret(tokenList);
// 50 is a magic number corresponding to the longest token list
// expressed as a string. Derived empirically. It makes the
// output easier to, er, interpret.
std::cout
<< Helpers::formatstring(" %-50s ==> \"%s\"", tokensAsString.c_str(), sentence.c_str())
<< std::endl;
}
std::cout << " Done." << std::endl;
}
static int * _sentenceTokenLists[]
A list of pre-defined token lists. Each token list represents a single sentence constructed from the ...
static const char * _TokensToString(int *tokens)
Helper function to convert a list of ints to a string representation.
std::string formatstring(const char *fmt,...)
Use the given string and arguments to return a buffer containing the formatted string....

C#

public void Run()
{
Console.WriteLine();
Console.WriteLine("Interpreter Exercise");
Interpreter_Class interpreter = new Interpreter_Class();
for (int sentenceIndex = 0; sentenceIndex < _sentenceTokenLists.Length; ++sentenceIndex)
{
int[] tokenList = _sentenceTokenLists[sentenceIndex];
string tokensAsString = _TokensToString(tokenList);
string sentence = interpreter.Interpret(tokenList);
// 50 is a magic number corresponding to the longest token list
// expressed as a string. Derived empirically. It makes the
// output easier to, er, interpret.
Console.WriteLine(" {0,-50} ==> \"{1}\"", tokensAsString, sentence);
}
Console.WriteLine(" Done.");
}

Python

def Interpreter_Exercise():
print()
print("Interpreter Exercise")
interpreter = Interpreter_Class()
for sentenceIndex in range(0, len(_sentenceTokenLists)):
tokenList = _sentenceTokenLists[sentenceIndex]
tokensAsString = _TokensToString(tokenList)
sentence = interpreter.Interpret(tokenList)
# 50 is a magic number corresponding to the longest token list
# expressed as a string. Derived empirically. It makes the
# output easier to, er, interpret.
print(" {0:<50} ==> \"{1}\"".format(tokensAsString, sentence))
print(" Done.")

C

void Interpreter_Exercise(void)
{
printf("\nInterpreter Exercise\n");
for (size_t sentenceIndex = 0; _sentenceTokenLists[sentenceIndex] != NULL; ++sentenceIndex)
{
int* tokenList = _sentenceTokenLists[sentenceIndex];
const char* tokensAsString = _TokensToString(tokenList);
DynamicString sentence = { 0 };
bool success = Interpreter_Interpret(tokenList, &sentence);
if (success)
{
// 50 is a magic number corresponding to the longest token list
// expressed as a string. Derived empirically. It makes the
// output easier to, er, interpret.
printf(" %-50s ==> \"%s\"\n", tokensAsString, sentence.string);
}
DynamicString_Clear(&sentence);
if (!success)
{
break;
}
}
printf(" Done.\n");
bool Interpreter_Interpret(const int *tokenList, DynamicString *output)
This function is a simple interpreter.
void DynamicString_Clear(DynamicString *string)
Clear a DynamicString object, releasing any allocated memory. Resets to an empty string.
Definition: dynamicstring.c:27
Represents a string that can be grown dynamically.
Definition: dynamicstring.h:16
char * string
The string that can grow.
Definition: dynamicstring.h:17

RUST

(Apologies. Doxygen does not understand Rust syntax and therefore cannot colorize the code.)

pub fn interpreter_exercise() -> Result<(), String> {
println!("");
println!("Interpreter Exercise");
for sentence_index in 0.._SENTENCE_TOKEN_LISTS.len() {
let token_list = _SENTENCE_TOKEN_LISTS[sentence_index];
let tokens_as_string = _tokens_to_string(token_list);
let sentence = interpreter_interpret(token_list);
// 50 is a magic number corresponding to the longest token list
// expressed as a string. Derived empirically. It makes the
// output easier to, er, interpret.
println!(" {:-50} ==> \"{}\"", tokens_as_string, sentence);
}
println!(" Done.");
Ok(())
}

See Also