解释器模式

理论

解释器模式(interpreter),给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

解释器模式的应用场景:

当有一个语言需要解释执行,并且可将该语言中的句子表示为一个抽象语法树时,可使用解释器模式。

解释器模式的优点:

  1. 可以很容易地改变和扩展文法,因为该模式使用类来表示文法规则,可使用继承来改变和扩展该文法。

  2. 也比较容易实现文法,因为定义抽象语法树中各个节点地类地实现大体类似,这些类都易于直接编写。

解释器模式的缺点:

  解释器模式为文法中地每一条规则至少定义了一个类,因此包含许多规则地文法可能难以管理和维护。建议当文法非常复杂时,使用其他技术如语法分析程序或编译器生成器来处理。

实例

实现音乐解释器,定义一套规则:

T表示速度,以毫秒为单位;

O 表示音阶, O1 表示低音阶, O2 表示中音阶, O3 表示高音阶;

P 表示休止符;

C D E F G A B 表示 “Do-Re-Mi-Fa-So-La-Ti”;

音符长度1表示一拍,2表示二拍,0.5表示半拍,0.25表示四分之一拍;

所有字母和数字都要用半角空格分开。

UML类图

代码实现

#include <iostream>
#include <sstream>
#include <vector>
using namespace std;

//演奏内容类
class PlayContext {
public:
    void SetText(string _text) {
        text = _text;
    }
    string GetText() {
        return text;
    }
private:
    string text;
};

//抽象表达式类
class Expression {
public:
    virtual void Excute(string key, string value) = 0;
    void Interpret(PlayContext* context) {
        if (context->GetText().length() == 0)
            return;
        else {
            vector<string> vs;
            stringstream ss(context->GetText());  //使用字符串构造一个stringstream
            //按空格分割字符串
            string buf; 
            while (ss >> buf)
                vs.push_back(buf);
            //解释前两个字符串
            Excute(vs[0], vs[1]);
            //拼接剩下的字符串
            string tmp;
            vs.erase(vs.begin(), vs.begin() + 2);
            for (vector<string>::iterator it = vs.begin(); it != vs.end(); it++) {
                tmp += *it;
                if (it < vs.end() - 1)
                    tmp += " ";
            }
            //更新字符串
            context->SetText(tmp);
        }
    }
};

//音符类
class Note :public Expression {
public:
    void Excute(string key, string value) {
        string note = " ";
        switch (key[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;
        default:
            break;
        }
        cout << note << " ";
    }
};

//音阶类
class Scale :public Expression {
public:
    virtual void Excute(string key, string value) {
        string scale = " ";
        switch (value[0])
        {
        case'1':
            scale = "低音"; break;
        case'2':
            scale = "中音"; break;
        case'3':
            scale = "高音"; break;
        default:
            break;
        }
        cout << scale << " ";
    }
};

//音速类
class Speed : public Expression
{
public:
    void Excute(string key, string value)
    {
        int v = stoi(value);
        if (v < 500)
            cout << "快速 ";
        else if (v > 1000)
            cout << "慢速 ";
        else
            cout << "中速 ";
    }
};

int main()
{
    PlayContext context;
    cout << "上海滩: " << endl;
    context.SetText("T 600 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");
    Expression* expression = NULL;
    while (context.GetText().length() > 0)
    {
        char str = context.GetText()[0];
        switch (str)
        {
        case'O':
            expression = new Scale; break;
        case'T':
            expression = new Speed; break;
        case'C':
        case'D':
        case'E':
        case'F':
        case'G':
        case'A':
        case'B':
        case'P':
            expression = new Note; break;
        default:
            break;
        }
        expression->Interpret(&context);
        delete expression;
    }
    cout << endl;
    return 0;
}

运行结果:

 

posted @ 2022-09-23 21:12  KYZH  阅读(133)  评论(0编辑  收藏  举报