解释器模式(interpreter),给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
解释器模式需要解决的问题,如果一个特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。
#include <iostream> #include <list> using namespace std; class Context; //AbstractExpression(抽象表达式),声明一个抽象的解释操作,这个接口为抽象语法树中所有的结点所共享 class AbstractExpression { public: virtual void Interpret(Context *context)=0; }; //TerminalExpression(终结符表达式),实现与文法中的终结符相关联的解释操作。实现抽象表达式中所要求的接口, //主要是一个interpret()方法。文法中每一个终结符都有一个具体终结表达式与之相对应。 class TerminalExpression:public AbstractExpression { public: void Interpret(Context *context) { cout << "终端解释器" << endl; } }; //NonterminalExpression(非终结符表达式),为文法中的非终结符实现解释操作。对文法中每一条规则R1、R2......Rn //都需要一个具体的非终结符表达式类。通过实现抽象表达式的interpret()方法实现解释操作。解释操作以递归方式调用 //上面所提到的代表R1、R2......Rn中各个符号的实例变量 class NonterminalExpression:public AbstractExpression { public: void Interpret(Context *context) { cout << "非终端解释器" << endl; } }; //Context,包含解释器之外的一些全局信息 class Context { private: string m_input; string m_output; public: void SetInput(string input) { this->m_input=input; } string GetInput() { return m_input; } void SetOutput(string output) { this->m_output=output; } string GetOutput() { return m_output; } }; //客户端代码,构建表示该文法定义的语言中一个特定的句子的抽象语法树。调用解释操作 int main() { Context *context=new Context(); list<AbstractExpression*> alist; alist.push_back(new TerminalExpression()); alist.push_back(new NonterminalExpression()); alist.push_back(new TerminalExpression()); alist.push_back(new TerminalExpression()); list<AbstractExpression*>::iterator iter=alist.begin(); for(;iter!=alist.end();iter++) (*iter)->Interpret(context); return 0; }
当有一个语言需要解释执行,并且可将该语言中的句子表示为一个抽象语法树时,可使用解释器模式。用了解释器模式,就意味着可以很容易地改变和扩展文法,因为该模式使用类来表示文法规则,你可以使用继承来改变或扩展该文法。也比较容易实现文法,因为定义抽象语法树中各个节点的类的实现大体类似,这些类都易于直接编写。解释器模式也有不足,解释器模式为文法中的每一条规则至少定义了一个类,因此包含许多规则的文法可能难以管理和维护。建议当文法非常复杂时,使用其他的技术如语法分析程序或编译器生成器来处理。
音乐解释器
#include <iostream> #include <list> #include <string> #include <string.h> #include <cstdlib> using namespace std; //演奏内容类 class PlayContext { private: string m_text; public: void SetText(string text) { this->m_text=text; } string GetText() { return m_text; } }; //表达式类 class Expression { public: void Interpret(PlayContext *context) { if(context->GetText().length()==0) return; else { string playKey=context->GetText().substr(0,1); context->SetText(context->GetText().substr(2)); int nPos=context->GetText().find(" "); string strPlayValue=context->GetText().substr(0,nPos); int nPlayValue=atoi(strPlayValue.c_str()); nPos=context->GetText().find(" "); context->SetText(context->GetText().substr(nPos+1)); Execute(playKey,nPlayValue); } } virtual void Execute(string strKey,const int nValue)=0; }; //音符类 class Note:public Expression { public: void Execute(string strKey,const int nValue) { char szKey[2]; strncpy(szKey,strKey.c_str(),strKey.length()); string note=""; switch(szKey[0]) { case 'C': note="1"; break; case 'D': note="2"; break; case 'E': note="3"; break; case 'F': note="4"; break; case 'G': note="5"; break; case 'A': note="6"; break; case 'B': note="7"; break; } cout << note << " "; } }; //音阶类 class Scale:public Expression { public: void Execute(string key,const int value) { string strScale; switch(value) { case 1: strScale="低音"; break; case 2: strScale="中音"; break; case 3: strScale="高音"; break; } cout << strScale << " "; } }; //音速类 class Speed:public Expression { public: void Execute(string key,const int value) { string speed; if(value<500) speed="快速"; else if(value>=1000) speed="慢速"; else speed="中速"; cout << speed << " "; } }; int main() { PlayContext *context=new PlayContext(); cout << "上海滩:"; context->SetText("T 500 O 2 E 0.5 G 0.5 A 3 E 0.5 G 0.5 D 3 E 0.5 G 0.5 A 0.5 O 3 C 1 O 2 A 0.5 G 1 C 0.5 E 0.5 D 3 "); Expression *expression=NULL; while(!context->GetText().empty()) { string str=context->GetText().substr(0,1); char szKey[2]; strncpy(szKey,str.c_str(),str.length()); switch(szKey[0]) { case 'T': expression=new Speed(); break; case 'O': expression=new Scale(); break; case 'C': case 'D': case 'E': case 'F': case 'G': case 'A': case 'B': expression = new Note(); break; default: break; } if(NULL!=expression) expression->Interpret(context); } return 0; }