《C++新经典设计模式》之第21章 解释器模式

《C++新经典设计模式》之第21章 解释器模式

解释器模式.cpp
#include <iostream>
#include <map>
#include <stack>
#include <vector>
#include <cstring>
#include <memory>
#include <set>
#include <sstream>
using namespace std;

// 定义一个语言的文法(语法规则),并建立一个解释器解释该语言中的句子
// 4种角色
// AbstractExpression(抽象表达式),声明抽象的解释操作
// TerminalExpression(终结符表达式),实现语言文法中与终结表达式相关的解释操作
// NonterminalExpression(非终结符表达式),实现语言文法中与非终结表达式相关的解释操作
// Context(环境类/上下文类),存储解释器之外的全局信息,变量名与值的映射关系、存储和访问表达式解释器的状态等,作为公共对象的参数传递到表达式的解释操作中

namespace ns1
{
    class Expression // 表达式(节点)父类
    {
    public:              // 以下两个成员变量是为程序跟踪调试时观察某些数据方便而引入
        int m_dbg_num;   // 创建该对象时的一个编号,用于记录本对象是第几个创建的
        char m_dbg_sign; // 标记本对象的类型,可能是个字符v代表变量(终结符表达式),也可能是个加减号(非终结符表达式)
    public:
        Expression(int num, char sign) : m_dbg_num(num), m_dbg_sign(sign) {}
        virtual ~Expression() {}

    public:                                                         // 解析语法树中的当前节点
        virtual int interpret(const map<char, int> &var) const = 0; // 变量名及对应的值
    };

    class VarExpression : public Expression // 变量表达式(终结符表达式)
    {
        char m_key; // 变量名,本范例中诸如a、b、c、d都是变量名
    public:
        VarExpression(const char &key, int num, char sign) : Expression(num, sign), m_key(key) {}
        int interpret(const map<char, int> &var) const override { return var.at(m_key); } // 返回变量名对应的数值
    };

    class SymbolExpression : public Expression // 运算符表达式(非终结符表达式)父类
    {
    protected: // 左右各有一个操作数
        shared_ptr<Expression> m_left;
        shared_ptr<Expression> m_right;

    public:
        SymbolExpression(const shared_ptr<Expression> &left, const shared_ptr<Expression> &right, int num, char sign) : m_left(left), m_right(right), Expression(num, sign) {}
        shared_ptr<Expression> getLeft() const { return m_left; }
        shared_ptr<Expression> getRight() const { return m_right; }
    };

    class AddExpression : public SymbolExpression // 加法运算符表达式(非终结符表达式)
    {
    public:
        AddExpression(const shared_ptr<Expression> &left, const shared_ptr<Expression> &right, int num, char sign) : SymbolExpression(left, right, num, sign) {} // 构造函数

        int interpret(const map<char, int> &var) const override
        {
            // 分步骤拆开写,方便理解和观察
            int value1 = m_left->interpret(var);  // 递归调用左操作数的interpret方法
            int value2 = m_right->interpret(var); // 递归调用右操作数的interpret方法
            int result = value1 + value2;
            return result; // 返回两个变量相加的结果
        }
    };

    class SubExpression : public SymbolExpression // 减法运算符表达式(非终结符表达式)
    {
    public:
        SubExpression(const shared_ptr<Expression> &left, const shared_ptr<Expression> &right, int num, char sign) : SymbolExpression(left, right, num, sign) {} // 构造函数

        int interpret(const map<char, int> &var) const override
        {
            int value1 = m_left->interpret(var);
            int value2 = m_right->interpret(var);
            int result = value1 - value2;
            return result; // 返回两个变量相减的结果
        }
    };

    // 分析—创建语法树(表达式树)
    shared_ptr<Expression> analyse(const string &strExp) // strExp:要计算结果的表达式字符串,比如"a-b+c+d"
    {
        stack<shared_ptr<Expression>> expStack; // #include <stack>,这里用到了栈这种顺序容器
        shared_ptr<Expression> left;
        shared_ptr<Expression> right;
        int icount = 1;
        for (size_t i = 0; i < strExp.size(); ++i) // 循环遍历表达式字符串中的每个字符
        {
            switch (strExp[i])
            {
            case '+':                                                       // 加法运算符表达式(非终结符表达式)
                left = expStack.top();                                      // 返回栈顶元素(左操作数)
                right.reset(new VarExpression(strExp[++i], icount++, 'v')); // v代表是个变量节点
                // 在栈顶增加元素
                expStack.push(make_shared<AddExpression>(left, right, icount++, '+')); //'+'代表是个减法运算符节点
                break;
            case '-':                  // 减法运算符表达式(非终结符表达式)
                left = expStack.top(); // 返回栈顶元素
                right.reset(new VarExpression(strExp[++i], icount++, 'v'));
                expStack.push(make_shared<SubExpression>(left, right, icount++, '-')); //'-'代表是个减法运算符节点
                break;
            default: // 变量表达式(终结符表达式)
                expStack.push(make_shared<VarExpression>(strExp[i], icount++, 'v'));
                break;
            }
        }
        shared_ptr<Expression> expression = expStack.top(); // 返回栈顶元素
        return expression;
    }
}

namespace ns2
{
    class Expression // 表达式父类
    {
    public:
        virtual ~Expression() {}

    public: // 解析语法树中的当前节点
        virtual string interpret() const = 0;
    };

    class DirectionExpression : public Expression // 运动方向表达式(终结符表达式)
    {
        string m_direction; // 运动方向:up、down、left、right分别表示上、下、左、右
    public:
        DirectionExpression(const string &direction) : m_direction(direction) {}
        string interpret() const override
        {
            static set<string> directionSet = {"up", "down", "left", "right"};
            if (directionSet.find(m_direction) != directionSet.end())
                return m_direction;
            else
                return "direction error";
        }
    };

    class ActionExpression : public Expression // 运动方式表达式(终结符表达式)
    {
        string m_action; // 运动方式:walk、run分别表示行走、奔跑
    public:
        ActionExpression(const string &action) : m_action(action) {}
        string interpret() const override
        {
            static set<string> actionSet = {"walk", "run"};
            if (actionSet.find(m_action) != actionSet.end())
                return m_action;
            else
                return "action error";
        }
    };

    class DistanceExpression : public Expression // 运动距离表达式(终结符表达式)
    {
        string m_distance; // 运动距离,用字符串表示即可
    public:
        DistanceExpression(const string &distance) : m_distance(distance) {}
        string interpret() const override
        {
            return m_distance + "m";
        }
    };

    class SentenceExpression : public Expression // “句子”表达式(非终结符表达式),“运动方向 运动方式 运动距离”构成
    {
        shared_ptr<Expression> m_direction; // 运动方向
        shared_ptr<Expression> m_action;    // 运动方式
        shared_ptr<Expression> m_distance;  // 运动距离
    public:
        SentenceExpression(const shared_ptr<Expression> &direction, const shared_ptr<Expression> &action, const shared_ptr<Expression> &distance)
            : m_direction(direction), m_action(action), m_distance(distance) {}
        shared_ptr<Expression> getDirection() const { return m_direction; }
        shared_ptr<Expression> getAction() const { return m_action; }
        shared_ptr<Expression> getDistance() const { return m_distance; }

        string interpret() const override
        {
            return m_direction->interpret() + " " + m_action->interpret() + " " + m_distance->interpret();
        }
    };

    class AndExpression : public Expression // “和”表达式(非终结符表达式)
    {
        shared_ptr<Expression> m_left;
        shared_ptr<Expression> m_right;

    public:
        AndExpression(const shared_ptr<Expression> &left, const shared_ptr<Expression> &right) : m_left(left), m_right(right) {}
        shared_ptr<Expression> getLeft() const { return m_left; }
        shared_ptr<Expression> getRight() const { return m_right; }

        string interpret() const override
        {
            return m_left->interpret() + " and " + m_right->interpret();
        }
    };

    // 分析—创建语法树(表达式树)
    shared_ptr<Expression> analyse(const string &strExp) // strExp:要计算结果的表达式字符串,比如"left walk 15 and down run 20"
    {
        stack<shared_ptr<Expression>> expStack;
        shared_ptr<Expression> direction;
        shared_ptr<Expression> action;
        shared_ptr<Expression> distance;
        shared_ptr<Expression> left;
        shared_ptr<Expression> right;

        // 机器人运动控制命令之间是用空格来分隔的,所以用空格作为分隔字符来对整个字符串进行拆分
        vector<string> resultVec;
        /*
        char *strc = new char[strlen(strExp.c_str()) + 1];
        strcpy(strc, strExp.c_str()); // 若本行编译报错提醒使用strcpy_s,则可以在文件头增加代码行:#pragma warning(disable : 4996)
        char *tmpStr = strtok(strc, " "); // 按空格来切割字符串
        while (tmpStr != nullptr)
        {
            resultVec.push_back(string(tmpStr));
            tmpStr = strtok(NULL, " ");
        }
        delete[] strc;
        */
        stringstream iss(strExp);        // 输入流
        string token;                    // 接收缓冲区
        while (getline(iss, token, ' ')) // 以' '为分隔符
            resultVec.push_back(token);

        for (auto iter = resultVec.begin(); iter != resultVec.end(); ++iter)
        {
            if ((*iter) == "and") // 和
            {
                left = expStack.top(); // 返回栈顶元素(左操作数)
                ++iter;

                direction.reset(new DirectionExpression(*iter)); // 运动方向
                ++iter;
                action.reset(new ActionExpression(*iter)); // 运动方式
                ++iter;
                distance.reset(new DistanceExpression(*iter)); // 运动距离
                right.reset(new SentenceExpression(direction, action, distance));
                expStack.push(make_shared<AndExpression>(left, right));
            }
            else
            {
                direction.reset(new DirectionExpression(*iter)); // 运动方向
                ++iter;
                action.reset(new ActionExpression(*iter)); // 运动方式
                ++iter;
                distance.reset(new DistanceExpression(*iter)); // 运动距离
                expStack.push(make_shared<SentenceExpression>(direction, action, distance));
            }
        }
        shared_ptr<Expression> expression = expStack.top(); // 返回栈顶元素
        return expression;
    }
}

int main()
{
#if 0
    using namespace ns1;
    map<char, int> varmap;
    // 下面是给字符串表达式中所有参与运算的变量一个对应的数值
    varmap.insert(make_pair('a', 7)); // 类似于赋值语句a = 7
    varmap.insert(make_pair('b', 9)); // 类似于赋值语句b = 9
    varmap.insert(make_pair('c', 3)); // 类似于赋值语句c = 3
    varmap.insert(make_pair('d', 2)); // 类似于赋值语句d = 2

    string strExp = "a-b+c+d";                           // 将要求值的字符串表达式
    shared_ptr<Expression> expression = analyse(strExp); // 调用analyse函数创建语法树
    int result = expression->interpret(varmap);          // 调用interpret接口求解字符串表达式的结果
    cout << strExp << " = " << result << endl;           // 输出字符串表达式结果
#endif

#if 1
    using namespace ns2;
    string strExp = "left walk 15 and down run 20";
    shared_ptr<Expression> expression = analyse(strExp); // 调用analyse函数创建语法树
    cout << expression->interpret() << endl;
#endif

    cout << "Over!\n";
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: "C经典-设计模式"是一本非常重要的书籍,它详细介绍了23种常用的设计模式设计模式是指在软件开发中,经过实践证明有效的解决方案。这本书提供了大量的示例和实践案例,帮助读者理解并应用这些设计模式。 这本书的特点之一是提供了丰富的图示,通过图示直观地展示了设计模式的结构和关系。这对于理解和记忆设计模式非常有帮助。 这本书从简单到复杂地介绍了各种不同类型的设计模式,包括创建型、结构型和行为型设计模式。每种设计模式都包括了详细的定义、应用场景、解决方案和与其他模式的关系。这样的组织结构使得读者可以快速地了解并选择适合自己项目需求的设计模式。 "C经典-设计模式"还提供了大量的实例代码和案例分析,帮助读者更好地理解和应用设计模式。这些案例覆盖了各种不同的编程语言和开发环境,使得读者可以从不同的角度去理解设计模式。 总的来说,"C经典-设计模式"是一本极具价值的书籍,无论是对于初学者还是有经验的开发者都具有很大的帮助。通过学习和应用这些设计模式,读者可以提高软件开发的质量和效率,使得自己的代码更加灵活、可维护和可扩展。 ### 回答2: "C经典设计模式pdf" 是指《C++经典设计模式》这本书的电子版PDF文件。这本书是一本关于C++设计模式经典著作,对于C++开发者学习和应用设计模式非常有帮助。通过阅读这本书的PDF版本,可以更方便地学习和参考其中的内容。 该PDF文件包含了本书的全部内容,包括理论介绍、具体的设计模式实现案例和相关的示意图等。使用该PDF文件,可以将书籍随身携带,随时进行学习和查阅。无论是初学者还是经验丰富的开发者都可以通过研读该书,深入了解各种设计模式的原理和使用方法。 设计模式是一种解决常见软件设计问题的经验总结,它们提供了一套通用且可重复使用的解决方案。通过应用设计模式,我们可以使得我们的代码更加灵活、可扩展和易于维护。在C++开发中使用设计模式,不仅可以提升代码质量和性能,还可以提高开发效率和团队协作能力。 《C++经典设计模式》是一本深入浅出的教材,适合各个层次的C++开发者阅读。无论你是刚入门的初学者,还是已经有一定经验的开发者,都可以从书中学到很多有用的知识和技巧。通过阅读该书的PDF版,可以更便捷地学习和实践设计模式,提升自身的软件设计和编码能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值