二十二、解释器模式

   一些应用提供了内建(Build-In)的脚本或者宏语言来让用户可以定义他们能够在系统中进行的操作。Interpreter 模式的目的就是使用一个解释器为用户提供一个一门定义语言的语法表示的解释器,然后通过这个解释器来解释语言中的句子。
   Interpreter 模式提供了这样的一个实现语法解释器的框架,笔者曾经也正在构建一个编译系统 ViVisual CMCS,现在已经发布了 ViVisual CMCS1.0 (Beta),请大家访问 Visual CMCS 网站获取详细信息。

角色和职责

解释器模式

抽象表达式角色(AbstractExpression): 声明一个抽象的解释操作,这个接口为所有具体表达式角色都要实现的。
终结符表达式角色(TerminalExpression): 实现与文法中的元素相关联的解释操作,通常一个解释器模式中只有一个终结符表达式,但有多个实例对应不同的终结符,
终结符就是语言中用到的基本元素,一般不能再被分解,如: x -> xa, 这里a是终结符,因为没有别的规则可以把a变成别的符号,不过x可以变成别的符号,所以x是非终结符。
非终结符表达式角色(NonterminalExpression): 文法中的每条规则对应于一个非终结表达式, 非终结表达式根据逻辑的复杂程度而增加,原则上每个文法规则都对应一个非终结符表达式。
环境角色(Context):包含解释器之外的一些全局信息。

案例

class ExpressionContext
{
public:
    ExpressionContext(int num)
    {
        m_num = num;
    }
    
    void setNum(int num)
    {
        m_num = num;
    }
    
    int getNum()
    {
        return m_num;
    }
    
    void setRes(int res)
    {
        m_res = res;
    }
    
    int getRes()
    {
        return m_res;
    }
private:
    int m_num;
    int m_res;
};

class Expression
{
public:
    virtual void interpreter(ExpressionContext *context) = 0;
    virtual ~Expression(){}
};

class PlusExpression : public Expression
{
public:
    virtual void interpreter(ExpressionContext *context)
    {
        int num = context->getNum();
        num ++ ;
        context->setNum(num);
        context->setRes(num);
    }
};

class MinusExpression : public Expression
{
public:
    virtual void interpreter(ExpressionContext *context)
    {
        int num = context->getNum();
        num -- ;
        context->setNum(num);
        context->setRes(num);
    }
};

int main()
{
    ExpressionContext *pcxt = new ExpressionContext(10);
    Expression *e1 = new PlusExpression;
    e1->interpreter(pcxt);
    cout << "PlusExpression:" << pcxt->getRes() << endl;

    Expression *e2 = new MinusExpression;
    e2->interpreter(pcxt);
    cout << "MinusExpression:" << pcxt->getRes() << endl;

    delete e2;
    delete e1;

    return 0;
}

适用性:

在以下情况下可以考虑使用解释器模式:

(1) 可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。

(2) 一些重复出现的问题可以用一种简单的语言来进行表达。

(3) 一个语言的文法较为简单。

(4) 执行效率不是关键问题。(注:高效的解释器通常不是通过直接解释抽象语法树来实现的,而是需要将它们转换成其他形式,使用解释器模式的执行效率并不高。)

优缺点:

优点:
(1) 易于改变和扩展文法。由于在解释器模式中使用类来表示语言的文法规则,因此可以通过继承等机制来改变或扩展文法。

(2) 每一条文法规则都可以表示为一个类,因此可以方便地实现一个简单的语言。

(3) 实现文法较为容易。在抽象语法树中每一个表达式节点类的实现方式都是相似的,这些类的代码编写都不会特别复杂,还可以通过一些工具自动生成节点类代码。

(4) 增加新的解释表达式较为方便。如果用户需要增加新的解释表达式只需要对应增加一个新的终结符表达式或非终结符表达式类,原有表达式类代码无须修改,符合“开闭原则”。

缺点:
(1) 对于复杂文法难以维护。在解释器模式中,每一条规则至少需要定义一个类,因此如果一个语言包含太多文法规则,类的个数将会急剧增加,导致系统难以管理和维护,此时可以考虑使用语法分析程序等方式来取代解释器模式。

(2) 执行效率较低。由于在解释器模式中使用了大量的循环和递归调用,因此在解释较为复杂的句子时其速度很慢,而且代码的调试过程也比较麻烦。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容