Interpreter pattern

Last updated

In computer programming, the interpreter pattern is a design pattern that specifies how to evaluate sentences in a language. The basic idea is to have a class for each symbol (terminal or nonterminal) in a specialized computer language. The syntax tree of a sentence in the language is an instance of the composite pattern and is used to evaluate (interpret) the sentence for a client. [1] :243 See also Composite pattern.

Contents

Overview

The Interpreter [2] design pattern is one of the twenty-three well-known GoF design patterns that describe how to solve recurring design problems to design flexible and reusable object-oriented software, that is, objects that are easier to implement, change, test, and reuse.

What problems can the Interpreter design pattern solve?

Source: [3]

When a problem occurs very often, it could be considered to represent it as a sentence in a simple language (Domain Specific Languages) so that an interpreter can solve the problem by interpreting the sentence.

For example, when many different or complex search expressions must be specified. Implementing (hard-wiring) them directly into a class is inflexible because it commits the class to particular expressions and makes it impossible to specify new expressions or change existing ones independently from (without having to change) the class.

What solution does the Interpreter design pattern describe?

The expression objects are composed recursively into a composite/tree structure that is called abstract syntax tree (see Composite pattern).
The Interpreter pattern doesn't describe how to build an abstract syntax tree. This can be done either manually by a client or automatically by a parser.

See also the UML class and object diagram below.

Uses

Structure

UML class and object diagram

A sample UML class and object diagram for the Interpreter design pattern. W3sDesign Interpreter Design Pattern UML.jpg
A sample UML class and object diagram for the Interpreter design pattern.

In the above UML class diagram, the Client class refers to the common AbstractExpression interface for interpreting an expression interpret(context).
The TerminalExpression class has no children and interprets an expression directly.
The NonTerminalExpression class maintains a container of child expressions (expressions) and forwards interpret requests to these expressions.

The object collaboration diagram shows the run-time interactions: The Client object sends an interpret request to the abstract syntax tree. The request is forwarded to (performed on) all objects downwards the tree structure.
The NonTerminalExpression objects (ntExpr1,ntExpr2) forward the request to their child expressions.
The TerminalExpression objects (tExpr1,tExpr2,) perform the interpretation directly.

UML class diagram

Interpreter UML class diagram.svg

Example

This C++11 implementation is based on the pre C++98 sample code in the book.

#include<iostream>#include<map>#include<cstring>classContext;classBooleanExp{public:BooleanExp()=default;virtual~BooleanExp()=default;virtualboolevaluate(Context&)=0;virtualBooleanExp*replace(constchar*,BooleanExp&)=0;virtualBooleanExp*copy()const=0;};classVariableExp;classContext{public:Context():m(){}boollookup(constVariableExp*key){returnm.at(key);}voidassign(VariableExp*key,boolvalue){m[key]=value;}private:std::map<constVariableExp*,bool>m;};classVariableExp:publicBooleanExp{public:VariableExp(constchar*name_):name(nullptr){name=strdup(name_);}virtual~VariableExp()=default;virtualboolevaluate(Context&aContext){returnaContext.lookup(this);}virtualBooleanExp*replace(constchar*name_,BooleanExp&exp){if(0==strcmp(name_,name)){returnexp.copy();}else{returnnewVariableExp(name);}}virtualBooleanExp*copy()const{returnnewVariableExp(name);}VariableExp(constVariableExp&)=delete;// rule of threeVariableExp&operator=(constVariableExp&)=delete;private:char*name;};classAndExp:publicBooleanExp{public:AndExp(BooleanExp*op1,BooleanExp*op2):operand1(nullptr),operand2(nullptr){operand1=op1;operand2=op2;}virtual~AndExp()=default;virtualboolevaluate(Context&aContext){returnoperand1->evaluate(aContext)&&operand2->evaluate(aContext);}virtualBooleanExp*replace(constchar*name_,BooleanExp&exp){returnnewAndExp(operand1->replace(name_,exp),operand2->replace(name_,exp));}virtualBooleanExp*copy()const{returnnewAndExp(operand1->copy(),operand2->copy());}AndExp(constAndExp&)=delete;// rule of threeAndExp&operator=(constAndExp&)=delete;private:BooleanExp*operand1;BooleanExp*operand2;};intmain(){BooleanExp*expression;Contextcontext;VariableExp*x=newVariableExp("X");VariableExp*y=newVariableExp("Y");expression=newAndExp(x,y);context.assign(x,false);context.assign(y,true);boolresult=expression->evaluate(context);std::cout<<result<<'\n';context.assign(x,true);context.assign(y,true);result=expression->evaluate(context);std::cout<<result<<'\n';}

The program output is:

01

See also

Related Research Articles

<span class="mw-page-title-main">Scheme (programming language)</span> Dialect of Lisp

Scheme is a dialect of the Lisp family of programming languages. Scheme was created during the 1970s at the MIT Computer Science and Artificial Intelligence Laboratory and released by its developers, Guy L. Steele and Gerald Jay Sussman, via a series of memos now known as the Lambda Papers. It was the first dialect of Lisp to choose lexical scope and the first to require implementations to perform tail-call optimization, giving stronger support for functional programming and associated techniques such as recursive algorithms. It was also one of the first programming languages to support first-class continuations. It had a significant influence on the effort that led to the development of Common Lisp.

<span class="mw-page-title-main">Smalltalk</span> Object-oriented programming language released first in 1972

Smalltalk is a purely object oriented programming language (OOP) that was originally created in the 1970s for educational use, specifically for constructionist learning, but later found use in business. It was created at Xerox PARC by Learning Research Group (LRG) scientists, including Alan Kay, Dan Ingalls, Adele Goldberg, Ted Kaehler, Diana Merry, and Scott Wallace.

The prototype pattern is a creational design pattern in software development. It is used when the types of objects to create is determined by a prototypical instance, which is cloned to produce new objects. This pattern is used to avoid subclasses of an object creator in the client application, like the factory method pattern does, and to avoid the inherent cost of creating a new object in the standard way when it is prohibitively expensive for a given application.

In object-oriented (OO) and functional programming, an immutable object is an object whose state cannot be modified after it is created. This is in contrast to a mutable object, which can be modified after it is created. In some cases, an object is considered immutable even if some internally used attributes change, but the object's state appears unchanging from an external point of view. For example, an object that uses memoization to cache the results of expensive computations could still be considered an immutable object.

In computer science, imperative programming is a programming paradigm of software that uses statements that change a program's state. In much the same way that the imperative mood in natural languages expresses commands, an imperative program consists of commands for the computer to perform. Imperative programming focuses on describing how a program operates step by step, rather than on high-level descriptions of its expected results.

In computer science, primitive data types are a set of basic data types from which all other data types are constructed. Specifically it often refers to the limited set of data representations in use by a particular processor, which all compiled programs must use. Most processors support a similar set of primitive data types, although the specific representations vary. More generally, "primitive data types" may refer to the standard data types built into a programming language. Data types which are not primitive are referred to as derived or composite.

In computer programming, a function object is a construct allowing an object to be invoked or called as if it were an ordinary function, usually with the same syntax. In some languages, particularly C++, function objects are often called functors.

In computer programming, the ternary conditional operator is a ternary operator that is part of the syntax for basic conditional expressions in several programming languages. It is commonly referred to as the conditional operator, ternary if, or inline if. An expression a ? b : c evaluates to b if the value of a is true, and otherwise to c. One can read it aloud as "if a then b otherwise c". The form a ? b : c is by far and large the most common, but alternative syntaxes do exist; for example, Raku uses the syntax a ?? b !! c to avoid confusion with the infix operators ? and !, whereas in Visual Basic .NET, it instead takes the form If(a, b, c).

In computer science, the Boolean is a data type that has one of two possible values which is intended to represent the two truth values of logic and Boolean algebra. It is named after George Boole, who first defined an algebraic system of logic in the mid 19th century. The Boolean data type is primarily associated with conditional statements, which allow different actions by changing control flow depending on whether a programmer-specified Boolean condition evaluates to true or false. It is a special case of a more general logical data type—logic does not always need to be Boolean.

The computer programming languages C and Pascal have similar times of origin, influences, and purposes. Both were used to design their own compilers early in their lifetimes. The original Pascal definition appeared in 1969 and a first compiler in 1970. The first version of C appeared in 1972.

In the C programming language, data types constitute the semantics and characteristics of storage of data elements. They are expressed in the language syntax in form of declarations for memory locations or variables. Data types also determine the types of operations or methods of processing of data elements.

In computer science, higher-order abstract syntax is a technique for the representation of abstract syntax trees for languages with variable binders.

Automata-based programming is a programming paradigm in which the program or part of it is thought of as a model of a finite-state machine (FSM) or any other formal automaton. Sometimes a potentially infinite set of possible states is introduced, and such a set can have a complicated structure, not just an enumeration.

<span class="mw-page-title-main">JavaScript syntax</span> Set of rules defining correctly structured programs

The syntax of JavaScript is the set of rules that define a correctly structured JavaScript program.

The C and C++ programming languages are closely related but have many significant differences. C++ began as a fork of an early, pre-standardized C, and was designed to be mostly source-and-link compatible with C compilers of the time. Due to this, development tools for the two languages are often integrated into a single product, with the programmer able to specify C or C++ as their source language.

C++11 is a version of the ISO/IEC 14882 standard for the C++ programming language. C++11 replaced the prior version of the C++ standard, called C++03, and was later replaced by C++14. The name follows the tradition of naming language versions by the publication year of the specification, though it was formerly named C++0x because it was expected to be published before 2010.

<span class="mw-page-title-main">Specification pattern</span> Software design pattern

In computer programming, the specification pattern is a particular software design pattern, whereby business rules can be recombined by chaining the business rules together using boolean logic. The pattern is frequently used in the context of domain-driven design.

Expression templates are a C++ template metaprogramming technique that builds structures representing a computation at compile time, where expressions are evaluated only as needed to produce efficient code for the entire computation. Expression templates thus allow programmers to bypass the normal order of evaluation of the C++ language and achieve optimizations such as loop fusion.

In object-oriented design, the chain-of-responsibility pattern is a behavioral design pattern consisting of a source of command objects and a series of processing objects. Each processing object contains logic that defines the types of command objects that it can handle; the rest are passed to the next processing object in the chain. A mechanism also exists for adding new processing objects to the end of this chain.

References

  1. Gamma, Erich; Helm, Richard; Johnson, Ralph; Vlissides, John (1994). Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley. ISBN   0-201-63361-2.
  2. Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides (1994). Design Patterns: Elements of Reusable Object-Oriented Software . Addison Wesley. pp.  243ff. ISBN   0-201-63361-2.{{cite book}}: CS1 maint: multiple names: authors list (link)
  3. "The Interpreter design pattern - Problem, Solution, and Applicability". w3sDesign.com. Retrieved 2017-08-12.
  4. "The Interpreter design pattern - Structure and Collaboration". w3sDesign.com. Retrieved 2017-08-12.