1 / 10

Behavioral Pattern: Interpreter

Behavioral Pattern: Interpreter. Chapter 5 – Page 149. Some programs benefit from having a language to describe operations that they can perform. The Interpreter Pattern generally describes defining a grammar for that language and using that grammar to interpret statements in that language.

kris
Download Presentation

Behavioral Pattern: Interpreter

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Behavioral Pattern: Interpreter Chapter 5 – Page 149 Some programs benefit from having a language to describe operations that they can perform. The Interpreter Pattern generally describes defining a grammar for that language and using that grammar to interpret statements in that language.

  2. The Interpreter Pattern Chapter 5 – Page 150 The AbstractExpression defines an interface for executing an operation. The TerminalExpression implements an Interpret operation associated with terminal symbols in the grammar. • The Context contains information that is global to the interpreter. • The Client invokes the interpret operation and builds (or is given) an abstract syntax tree, assembled from CompoundExpressions and TerminalExpressions) representing a particular sentence in the language that the grammar defines. • One CompoundExpression class is required for every rule in the grammar, each one implementing an Interpret operation for nonterminal symbols in the grammar.

  3. Example: Boolean Expressions Chapter 5 – Page 151 A BooleanExpression is either a terminal expression (a Constant) or a compound expression (an AND, OR, or NOT Expression). A BooleanExpression is interpreted (or “interpreted) in the context of its variable names and values. For instance, the BooleanExpression (X AND NOT Y) OR Z in the context of (X,Y,Z) = (true, false, false) evaluates to eval(X AND NOT Y) OR eval(Z), which is (eval(X) AND eval(NOT Y)) OR false, which evaluates to (true AND NOT eval(Y)), which is NOT(false), resulting in an evaluation of true.

  4. Example: Roman Numerals Chapter 5 – Page 152 Reading left to right, a Roman Numeral can be interpreted via four “sub-interpreters”. First, the thousands characters (the leading “M” characters) are read. This is followed by the hundreds characters (either a nine-sequence “CM”, a four-sequence “CD”, or an optional five-sequence “D” followed by zero to three one-sequences “C”). The tens and ones characters are handled similarly. Notice that all of the derived “expressions” are terminal.

  5. Roman Numeral Code in C++ Chapter 5 – Page 153 #include <iostream> #include <string> using namespace std; class Thousand; class Hundred; class Ten; class One; classRomanNumeralInterpreter { public: RomanNumeralInterpreter(); // Creator for client RomanNumeralInterpreter(int){} // Creator for subclasses, avoids infinite loop int interpret(string); // interpret() for client virtual void interpret(string &input, int &total) // interpret() for derived classes { int index = 0; if (input.substr(0, 2) == nine()) { total += 9 * multiplier(); index += 2; } else if (input.substr(0, 2) == four()) { total += 4 * multiplier(); index += 2; }

  6. Chapter 5 – Page 154 else { if (input[0] == five()[0]) { total += 5 * multiplier(); index = 1; } else index = 0; int count = 1; while ( (input[index] == one()[0]) && (count <= 3) ) { total += 1 * multiplier(); index++; count++; } } // remove leading characters processed input = input.substr(index, input.length() - index); } protected: // cannot be pure virtual because client asks for instance virtual string one() { return""; } virtual string four() { return""; } virtual string five() { return""; } virtual string nine() { return""; } virtual intmultiplier() { return 0; } private: RomanNumeralInterpreter *thousands; RomanNumeralInterpreter *hundreds; RomanNumeralInterpreter *tens; RomanNumeralInterpreter *ones; };

  7. class Thousand: publicRomanNumeralInterpreter { public: // provide 1-argument creator to avoid infinite loop in base class creator Thousand(int): RomanNumeralInterpreter(1) {} protected: string one() { return"M"; } string four() { return""; } string five() { return""; } string nine() { return""; } int multiplier() { return 1000; } }; class Hundred: publicRomanNumeralInterpreter { public: Hundred(int): RomanNumeralInterpreter(1) {} protected: string one() { return"C"; } string four() { return"CD"; } string five() { return"D"; } string nine() { return"CM"; } int multiplier() { return 100; } }; class Ten: publicRomanNumeralInterpreter { public: Ten(int): RomanNumeralInterpreter(1) {} protected: string one() { return"X"; } string four() { return"XL"; } string five() { return"L"; } string nine() { return"XC"; } int multiplier() { return 10; } }; Chapter 5 – Page 155

  8. Chapter 5 – Page 156 class One: publicRomanNumeralInterpreter { public: One(int): RomanNumeralInterpreter(1) {} protected: string one() { return"I"; } string four() { return"IV"; } string five() { return"V"; } string nine() { return"IX"; } int multiplier() { return 1; } }; RomanNumeralInterpreter::RomanNumeralInterpreter() { // use 1-argument creator to avoid infinite loop thousands = new Thousand(1); hundreds = new Hundred(1); tens = new Ten(1); ones = new One(1); } intRomanNumeralInterpreter::interpret(string input) { int total; total = 0; thousands->interpret(input, total); hundreds->interpret(input, total); tens->interpret(input, total); ones->interpret(input, total); if (input != "") // Input was invalid return 0; return total; }

  9. Chapter 5 – Page 157 void main() { RomanNumeralInterpreter interpreter; string input; cout << "Enter Roman Numeral: "; cin >> input; while (input != "quit") { cout << " interpretation is " << interpreter.interpret(input) << endl; cout << "Enter Roman Numeral: "; cin >> input; } }

  10. Interpreter Pattern Advantages Chapter 5 – Page 158 • When a program presents a number of different, but somewhat similar, cases with which it must contend, it can be advantageous to use a simple language to describe these cases and then have the program interpret that language. • Recognizing cases where the Interpreter Pattern can be helpful can be problematic, and programmers who lack training in formal languages or compilers often overlook this option. • One fairly obvious place where languages are applicable is when the program must parse algebraic strings in order to carry out operations based on the computation of user-entered equations. • A far more useful situation that uses the Interpreter Pattern is when the program produces varying kinds of output (e.g., generating reports based on a database without having to resort to elaborate SQL queries).

More Related