The interpreter pattern (interpreter), given a language, defines a representation of its grammar, and defines an interpreter that uses the representation to interpret a sentence in a language.
The interpreter pattern needs to address that if a particular type of problem occurs at a high frequency, it may be worthwhile to express each instance of the problem as a sentence in a simple language. This allows you to build an interpreter that interprets the sentences to solve the problem. Interpreter mode is used when there is a language that needs to be interpreted, and you can represent a sentence in that language as an abstract syntax tree. Using the interpreter pattern means that you can easily change and extend the grammar, because the pattern uses classes to represent the grammar rules, and you can use inheritance to change or extend the grammar. It is also easier to implement grammars because classes that define the nodes in the abstract syntax tree are generally similar, and these classes are easy to write directly.
Structure Chart:
Instance:
Music Interpreter
PlayContext.h
/************************************************************************
* Description: Performance Content
* Remark:
************************************************************************/
#ifndef _play_context_h_
#define _play_context_h_
#include <string>
#include <iostream>
using namespace std;
Class Playcontext
{public
:
string Getplaytext ()
{return
m_strtext;
}
void Setplaytext (const string& strText)
{
m_strtext = strText;
}
Private:
string m_strtext;
};
#endif//_play_context_h_
Expression.h
/************************************************************************ * Description: Expression class * Remark: ********* /#ifndef _expression_h_ #define _expression_h_
Include "playContext.h" class Expression {public://interpreter void interpret (playcontext& playcontext) {
if (Playcontext.getplaytext (). empty ()) {return;
else {string strplaykey = Playcontext.getplaytext (). substr (0, 1);
String strtemp = Playcontext.getplaytext (). substr (2);
Playcontext.setplaytext (strtemp);
size_t NPOs = Playcontext.getplaytext (). Find ("");
String strplayvalue = Playcontext.getplaytext (). substr (0, NPOs);
int nplayvalue = atoi (Strplayvalue.c_str ());
NPOs = Playcontext.getplaytext (). Find ("");
Playcontext.setplaytext (Playcontext.getplaytext (). substr (NPOs + 1));
Excute (Strplaykey, Nplayvalue); }//Execute Virtual void Excute (string& strkey, const int Nvalue) = 0;
Private:};
#endif//_expression_h_
Note.h
/************************************************************************ * Description: Note class * Remark: ************************************************************************/#ifndef _NOTE_H_ #define _ Note_h_ #include "expression.h" class Note:public expression {public:virtual void Excute (string& strkey, CO
NST int nvalue) {char szkey[2];
strncpy (Szkey, Strkey.c_str (), strkey.length ());
String Strnote;
Switch (szkey[0]) {case ' C ': strnote = ' 1 ';
Break
Case ' D ': Strnote = "2";
Break
Case ' E ': Strnote = "3";
Break
Case ' F ': strnote = "4";
Break
Case ' G ': strnote = "5";
Break
Case ' A ': strnote = "6";
Break
Case ' B ': strnote = "7";
Break
Default:strnote = "Error";
Break
} cout << strnote << "";
}
}; #endif//_note_h_
Scale.h
/************************************************************************
* Description: Scale class
* remark:
************************************************************************/
#ifndef _scale_h_
# Define _scale_h_
#include "expression.h"
class Scale:public expression
{public
:
virtual void Excute (string& strkey, const int nvalue)
{
string strscale;
Switch (nvalue)
{case
1:
Strscale = "Bass";
break;
Case 2:
strscale = "Alto";
break;
Case 3:
Strscale = "Treble";
break;
Default:
Strscale = "error";
break;
cout << strscale << "";
}
Private:
};
#endif//_scale_h_
Speed.h
#ifndef _speed_h_
#define _speed_h_
#include "expression.h"
class Speed:public expression
{
Public:
virtual void Excute (string& strkey, const int nvalue)
{
string strspeed;
if (Nvalue < 3)
{
strspeed = "Fast";
}
else if (nvalue >= 6)
{
strspeed = "slow";
}
else
{
strspeed = "Medium speed";
}
cout << strspeed << "";
}
};
#endif//_speed_h_
Client: InterpreterApp.cpp
InterpreterApp.cpp: Defines the entry point for a console application. #include "stdafx.h" #include "note.h" #include "scale.h" #include "speed.h" #include "playContext.h" int _tmain (i
NT ARGC, _tchar* argv[]) {Playcontext context;
cout << "Music:";
Context.setplaytext ("T 2 O 2 E 3 G 5 G 5");
expression* expressobj = NULL;
while (!context.getplaytext (). empty ()) {string strsep = Context.getplaytext (). substr (0, 1);
Char szkey[2];
strncpy (Szkey, Strsep.c_str (), strsep.length ());
Switch (szkey[0]) {case ' O ': expressobj = new scale ();
Break
Case ' T ': expressobj = new speed ();
Break
Case ' C ': Case ' D ': Case ' E ': Case ' F ': Case ' G ': Case ' A ': Case ' B ': Case ' P ':
Expressobj = new Note ();
Break
Default:break;
} if (NULL!= expressobj) {Expressobj->interpret (context);
} system ("Pause");
return 0;
}
The inadequacy of the place
The interpreter mode is not sufficient, the interpreter pattern defines at least one class for each rule in the grammar, so a grammar containing many rules may be difficult to manage and maintain. It is recommended that when the grammar is very complex, it is handled using other techniques such as a parser or compiler builder.
Applicable scenarios
- Interpreter mode is used when there is a language that needs to be interpreted, and you can represent a sentence in that language as an abstract syntax tree. This pattern works best when the following conditions are present:
- The grammar is simple for complex grammars, and the class level of the grammar becomes too large to be managed. This is a better choice for a tool like parser builder. They do not need to construct an abstract syntax tree to interpret an expression, which saves space and may also save time.
- Efficiency is not a key problem the most efficient interpreters are not usually implemented by directly interpreting the parsing tree, but by first converting them into another form. For example, regular expressions are usually converted to state machines. However, even in this case, the converter can still be implemented in the interpreter mode, and the pattern is still useful.