解释器模式

理论

解释器模式(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类图

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#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 @   KYZH  阅读(138)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
点击右上角即可分享
微信分享提示

目录导航