设计模式 笔记 解释器模式 Interpreter



//---------------------------15/04/26----------------------------


//Interpreter 解释器模式----类行为型模式


/* 

    1:意图:

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

    2:动机:

    3:适用性:

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

        存在以下情况时该模式效果最好:

        1>该文法简单对于复杂的文法,文法的类层次变得庞大而无法管理。此时语法分析程序生成器这样的工具是

          更好的选择。它们无需构建抽象语法树即可解释表达式。这样可以节省空间而且节省时间。

        2>效率不是一个关键问题,最高效的解释器通常不是通过直接解释语法分析树实现的,而是首先将它们转换成

          另外一种形式。

    4:结构:

                    |-----------Context

                    |

        Client------------------>AbstractExpression:<--------------------

                                 Interpret(Context)                     |

                                          |                             |

                                ---------------------                   |

                                |                   |                   |

                        TerminalExpression:     NonterminalExpression:---

                        Interpret(Context)      Interpret(Context)

    5:参与者:

        1>AbstractExpression

            声明一个抽象的解释操作,这个接口为抽象语法树中所有的节点所共享。

        2>TerminalExpression(终结)

            1)实现与文法中的终结符相关联的解释操作。

            2)一个句子中的每个终结符需要该类的一个实例。

        3>NonterminalExpression(非终结)

            1)对文法中的每一条规则R::R1R2...Rn都需要一个NonterminalExpression类。

            2)为从R1Rn的每个符号都维护一个AbstractExpression类型的实例变量。

            3)为文法中的非终结符实现解释操作。解释一般要递归地调用表示R1Rn的那些对象的解释操作。

        4>Context

            包含解释器之外的一些全局信息。

        5>Client

            1)构建表示该文法定义的语言中一个特定的句子的抽象语法树。该抽象语法树由

            NonterminalExpressionTerminalExpression的实例装配而成。

            2)调用解释操作

    6:协作:

        1>Client构建一个句子,它是NonterminalExpressionTerminalExpression的实例的一个抽象语法

          树,然后初始化上下文并调用解释操作。

        2>每一非终结符表达式节点定义相应子表达式的解释操作。而各终结符表达式的解释操作构成了递归的基础。

        3>每一节点的解释操作用上下文来存储和访问解释器的状态。

    7:效果:

        1>优点:

            1)易于改变和扩张文法:

                因为该模式使用类来表示文法规则,你可食用继承来改变或扩展该文法。已有的表达式可被增量式地

                改变,而新的表达式可定义为旧表达式的变体。

            2)易于实现文法:

                定义抽象语法树中各个节点的类的实现大体类似。这些类易于直接编写,通常它们也可用一个编辑器

                或语法分析程序生成器自动生成。

            3)增加了新的解释表达式的方式:

                解释器模式使得实现新表达式变的容易。

        2>缺点:

            1)复杂的文法难以维护:

                解释器模式为文法中的每一条规则至少定义了一个类,所以包含许多规则的文法可能难以管理和维护。

    8:实现:

        1>创建抽象语法树:

            解释器模式并未解释如何创建一个抽象的语法树。它只提供创建的规则。

        2>定义解释操作:

            并不一定要在表达式类中定义解释操作。可以配合Visitor模式,创建新的解释器。

        3>Flyweight模式共享终结符:

            终结节点一般不存储它们在抽象语法树中位置的信息。在解释过程中,任何它们所需要的上下文信息都由父

            节点传递给它们。所以可以配合Flyweight模式。

    9:代码示例:                                                                             */

文法定义:

BooleanExp ::= VariableExp | Constant | OrExp | AndExp | NotExp |'(' BooleanExp ')'

AndExp ::= BooleanExp'and' BooleanExp

OrExp ::= BooleanExp'or' BooleanExp

NotExp ::='not' BooleanExp

Constant ::='true' | 'false'

VariableExp ::='A' | 'B' | ... |'Y' | 'z'


//AbstractExpression:定义了操作

class BooleanExp

{

public:

    BooleanExp();

   virtual ~BooleanExp();

    

   virtual bool Evaluate(Constext&) =0;

   virtual BooleanExp* Replace(constchar*, BooleanExp&) = 0;

   virtual BooleanExp* Copy() const = 0;

};


//Contex:定义了变量到布尔值的映射

class Context

{

public:

    //检查一个变量返回什么bool值。

    bool LookUp(constchar*) const;

   void Assign(VariableExp*, bool);

};


//TerminalExpression:定义了终止符表达式,也就是说这个类既是表达式,也算单个变量,因为

//它是终止符了

class VariableExp :public BooleanExp

{

public:

    VariableExp(constchar*);

   virtual ~VariableExp();

    

   virtual bool Evaluate(Constext&);

   virtual BooleanExp* Replace(constchar*, BooleanExp&);

   virtual BooleanExp* Copy() const ;

private:

   char* _name;

};


VariableExp::VariableExp(constchar*)

{

    _name = strdup(name);

}

//求值,直接借助Context类的LookUp返回布尔值

bool VariableExp::Evaluate(Context& aContext)

{

   return aContext.LookUp(_name);

}



BooleanExp* VariableExp::Copy()const

{

   return new VariableExp(_name);

}

//替换,如果变量的name和自己相等,就返回一个拷贝,否则用自己的name来创建一个变量

BooleanExp* VariableExp::Replace(constchar* name, BooleanExp& exp)

{

   if(strcmp(name, _name) == 0)

    {

       return exp.Copy();

    }

   else

    {

       return new VariableExp(_name);

    }

}


//NonterminalExpressionand操作,借助AbstractExpression接口接可以实现了

class AndExp :public BooleanExp

{

public:

    AndExp(BooleanExp*, BooleanExp*);

   virtual ~AndExp();

    

   virtual bool Evaluate(Constext&);

   virtual BooleanExp* Replace(constchar*, BooleanExp&);

   virtual BooleanExp* Copy() const ;

    

private:

    BooleanExp* _operand1;

    BooleanExp* _operand2;

};


//and就把内部的两个表达式and一下

AndExp::AndExp(BooleanExp* op1, BooleanExp* op2): _operand1(op1), _operand2(op2)

{

}


bool AndExp::Evaluate(Context& aContext)

{

   return _operand1->Evaluate(aContext) && _operand2->Evaluate(aContext);

}



//copy就把内部的两个表达式一起copy一下。

BooleanExp* AndExp::Copy()const

{

   return AndExp(_operand1->Copy(), _operand2->Copy());

}


//要替换就,一起替换。

BooleanExp* AndExp::Replace(constchar* name, BooleanExp& exp)

{

   return new AndExp(_operand1->Replace(name, exp,)

                      _operand2->Replace(name,exp));

}

//说明一下,NonterminalExpression类是无需关心底部具体操作的,这些事归TerminalExpression

//它们只要调用接口就行了。


//使用:

(trueand x) or (yand (not x))

//也就是 OrExp(AndExp(true, x), AndExp(y, NotExp(x)))


BooleanExp* expression;

Context context;


VariableExp* x =new VariableExp("X");

VariableExp* y =new VariableExp("Y");


expression =new OrExp( new AndExp(new Constant(true), x),

                       new AndExp(y, new NotExp(x)));


context.Assign(x,false);

context.Assign(y,true);


bool result = expression->Evaluate(context);


//Constant类也算一个终止符,不过这个终止符不需要context来确定返回值,它不管constext的情况

//都返回固定的值。但是为了接口统一,它也要接受一个context,看起来像这样:


bool Constant::Evaluate(Context&)

{

   return _boolean;

}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值