C++ 解释器模式详解

解释器模式(Interpreter Pattern)是一种行为设计模式,它定义了一种语言的文法表示 ,并提供一个解释器来解释这种语言中的句子。

核心概念

设计原则

解释器模式遵循以下设计原则:

  1. 单一职责原则:将文法规则分解为多个类

  2. 开闭原则:可以扩展新的解释方式而不修改现有代码

  3. 封装性:封装语言解释的具体实现

主要优点

  1. 易于扩展:可以方便地扩展语言的文法

  2. 实现简单:每个文法规则都可以表示为一个类

  3. 灵活解释:可以灵活改变解释方式

  4. 领域特定语言:适合实现简单的领域特定语言(DSL)

模式结构

主要组件

  1. AbstractExpression(抽象表达式)

    • 声明一个抽象的解释操作
  2. TerminalExpression(终结符表达式)

    • 实现与文法中的终结符相关的解释操作
  3. NonterminalExpression(非终结符表达式)

    • 实现文法规则的解释操作

    • 通常包含对其他表达式的引用

  4. Context(上下文)

    • 包含解释器之外的全局信息
  5. Client(客户端)

    • 构建抽象语法树

    • 调用解释操作

完整代码示例

复制代码
#include <iostream>
#include <string>
#include <memory>
#include <unordered_map>
#include <stack>
#include <stdexcept>

// ==================== 上下文类 ====================
class Context {
    std::unordered_map<std::string, int> variables_;
    
public:
    void setVariable(const std::string& var, int value) {
        variables_[var] = value;
    }
    
    int getVariable(const std::string& var) const {
        return variables_.at(var);
    }
};

// ==================== 抽象表达式 ====================
class Expression {
public:
    virtual int interpret(Context& context) = 0;
    virtual ~Expression() = default;
};

// ==================== 终结符表达式 ====================
class Number : public Expression {
    int number_;
    
public:
    explicit Number(int number) : number_(number) {}
    
    int interpret(Context&) override {
        return number_;
    }
};

class Variable : public Expression {
    std::string name_;
    
public:
    explicit Variable(const std::string& name) : name_(name) {}
    
    int interpret(Context& context) override {
        return context.getVariable(name_);
    }
};

// ==================== 非终结符表达式 ====================
class Add : public Expression {
    std::unique_ptr<Expression> left_;
    std::unique_ptr<Expression> right_;
    
public:
    Add(std::unique_ptr<Expression> left, std::unique_ptr<Expression> right)
        : left_(std::move(left)), right_(std::move(right)) {}
    
    int interpret(Context& context) override {
        return left_->interpret(context) + right_->interpret(context);
    }
};

class Subtract : public Expression {
    std::unique_ptr<Expression> left_;
    std::unique_ptr<Expression> right_;
    
public:
    Subtract(std::unique_ptr<Expression> left, std::unique_ptr<Expression> right)
        : left_(std::move(left)), right_(std::move(right)) {}
    
    int interpret(Context& context) override {
        return left_->interpret(context) - right_->interpret(context);
    }
};

class Multiply : public Expression {
    std::unique_ptr<Expression> left_;
    std::unique_ptr<Expression> right_;
    
public:
    Multiply(std::unique_ptr<Expression> left, std::unique_ptr<Expression> right)
        : left_(std::move(left)), right_(std::move(right)) {}
    
    int interpret(Context& context) override {
        return left_->interpret(context) * right_->interpret(context);
    }
};

// ==================== 解析器 ====================
class Parser {
    std::vector<std::string> tokens_;
    size_t currentToken_;
    
    std::unique_ptr<Expression> parseExpression() {
        auto left = parseTerm();
        
        while (currentToken_ < tokens_.size()) {
            const auto& token = tokens_[currentToken_];
            
            if (token == "+") {
                currentToken_++;
                auto right = parseTerm();
                left = std::make_unique<Add>(std::move(left), std::move(right));
            } else if (token == "-") {
                currentToken_++;
                auto right = parseTerm();
                left = std::make_unique<Subtract>(std::move(left), std::move(right));
            } else {
                break;
            }
        }
        
        return left;
    }
    
    std::unique_ptr<Expression> parseTerm() {
        auto left = parseFactor();
        
        while (currentToken_ < tokens_.size()) {
            const auto& token = tokens_[currentToken_];
            
            if (token == "*") {
                currentToken_++;
                auto right = parseFactor();
                left = std::make_unique<Multiply>(std::move(left), std::move(right));
            } else {
                break;
            }
        }
        
        return left;
    }
    
    std::unique_ptr<Expression> parseFactor() {
        const auto& token = tokens_[currentToken_++];
        
        if (token == "(") {
            auto expr = parseExpression();
            if (tokens_[currentToken_++] != ")") {
                throw std::runtime_error("缺少右括号");
            }
            return expr;
        } else if (isdigit(token[0])) {
            return std::make_unique<Number>(std::stoi(token));
        } else {
            return std::make_unique<Variable>(token);
        }
    }
    
public:
    std::unique_ptr<Expression> parse(const std::string& expression) {
        // 简单分词 - 实际应用中可能需要更复杂的词法分析
        tokens_.clear();
        std::string token;
        for (char ch : expression) {
            if (isspace(ch)) {
                if (!token.empty()) {
                    tokens_.push_back(token);
                    token.clear();
                }
            } else if (ch == '(' || ch == ')' || ch == '+' || ch == '-' || ch == '*') {
                if (!token.empty()) {
                    tokens_.push_back(token);
                    token.clear();
                }
                tokens_.push_back(std::string(1, ch));
            } else {
                token += ch;
            }
        }
        
        if (!token.empty()) {
            tokens_.push_back(token);
        }
        
        currentToken_ = 0;
        return parseExpression();
    }
};

// ==================== 客户端代码 ====================
int main() {
    std::cout << "=== 解释器模式演示: 简单数学表达式计算 ===" << std::endl;
    
    Context context;
    context.setVariable("x", 10);
    context.setVariable("y", 5);
    context.setVariable("z", 2);
    
    Parser parser;
    
    try {
        // 解析并计算表达式
        auto expr1 = parser.parse("x + y * z");
        std::cout << "x + y * z = " << expr1->interpret(context) << std::endl;
        
        auto expr2 = parser.parse("(x + y) * z");
        std::cout << "(x + y) * z = " << expr2->interpret(context) << std::endl;
        
        auto expr3 = parser.parse("x * y + z");
        std::cout << "x * y + z = " << expr3->interpret(context) << std::endl;
        
        // 更复杂的表达式
        auto expr4 = parser.parse("x + y * z + (x - y)");
        std::cout << "x + y * z + (x - y) = " << expr4->interpret(context) << std::endl;
        
    } catch (const std::exception& e) {
        std::cerr << "错误: " << e.what() << std::endl;
    }
    
    return 0;
}

模式变体

1. 使用抽象语法树(AST)

复制代码
// AST节点基类
class ASTNode {
public:
    virtual int evaluate(Context&) = 0;
    virtual ~ASTNode() = default;
};

// 更复杂的AST节点类型
class IfNode : public ASTNode {
    std::unique_ptr<ASTNode> condition_;
    std::unique_ptr<ASTNode> thenBranch_;
    std::unique_ptr<ASTNode> elseBranch_;
    
public:
    int evaluate(Context& context) override {
        if (condition_->evaluate(context)) {
            return thenBranch_->evaluate(context);
        } else if (elseBranch_) {
            return elseBranch_->evaluate(context);
        }
        return 0;
    }
};

2. 使用访问者模式遍历AST

复制代码
class ASTVisitor {
public:
    virtual void visit(NumberNode* node) = 0;
    virtual void visit(VariableNode* node) = 0;
    virtual void visit(BinaryOpNode* node) = 0;
    virtual ~ASTVisitor() = default;
};

class InterpreterVisitor : public ASTVisitor {
    Context& context_;
    int result_;
    
public:
    explicit InterpreterVisitor(Context& context) : context_(context) {}
    
    int getResult() const { return result_; }
    
    void visit(NumberNode* node) override {
        result_ = node->getValue();
    }
    
    void visit(VariableNode* node) override {
        result_ = context_.getVariable(node->getName());
    }
    
    void visit(BinaryOpNode* node) override {
        InterpreterVisitor leftVisitor(context_), rightVisitor(context_);
        node->getLeft()->accept(&leftVisitor);
        node->getRight()->accept(&rightVisitor);
        
        int left = leftVisitor.getResult();
        int right = rightVisitor.getResult();
        
        switch (node->getOp()) {
            case '+': result_ = left + right; break;
            case '-': result_ = left - right; break;
            case '*': result_ = left * right; break;
            default: throw std::runtime_error("未知操作符");
        }
    }
};

实际应用场景

  1. 正则表达式:解释正则表达式模式

  2. SQL解析:解析SQL查询语句

  3. 数学公式计算:如示例中的表达式计算

  4. 编译器设计:解释编程语言的语法

  5. 业务规则引擎:解释和执行业务规则

相关推荐
敲代码的 蜡笔小新5 小时前
【行为型之解释器模式】游戏开发实战——Unity动态公式解析与脚本系统的架构奥秘
unity·设计模式·游戏引擎·解释器模式
wenbin_java1 个月前
设计模式之解释器模式:原理、实现与应用
java·设计模式·解释器模式
南七行者1 个月前
对解释器模式的理解
解释器模式
cijiancao1 个月前
23 种设计模式中的解释器模式
java·设计模式·解释器模式
hope_wisdom2 个月前
实战设计模式之解释器模式
设计模式·解释器模式·软件工程·软件构建·架构设计
LuckyLay2 个月前
Golang学习笔记_49——解释器模式
笔记·学习·设计模式·golang·解释器模式
码熔burning2 个月前
(二 十 三)趣学设计模式 之 解释器模式!
java·设计模式·解释器模式
_真相只有一个2 个月前
行为型模式 - 解释器模式 (Interpreter Pattern)
设计模式·解释器模式
千里码!2 个月前
java23种设计模式-解释器模式
java·设计模式·解释器模式