设计模式---行为类型---解释器

时间:2022-04-03 17:11:26

1、意图

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

2、动机

如果一种特定类型的问题发生的频率够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。

3、适用性

当有一个语言需要解释执行,并且你可将该语言中的句子表示为一个抽象语法树时,可使用解释器模式。而当存在以下情况时该模式效果最好:

1)该文法简单对于复杂的文法,文法的类层次变得庞大而无法管理。此时语法分析程序生成器这样的工具是更好的选择。它们无需构建抽象语法树即可解释表达式,这样可以节省空间而且还可能节省时间。

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

4、C++实例

// Test.cpp : 定义控制台应用程序的入口点。
//


#include "stdafx.h"
#include <atlstr.h>
#include <iostream>
#include <string>
#include <map>

using namespace std;


#define false 0

#define true 1


class Context;

class BooleanExp
{
public:
BooleanExp()
{

}

virtual ~BooleanExp()
{

}

virtual bool Evaluate( Context& ) =0;

virtual BooleanExp* Replace( const char *, BooleanExp& ) =0;

virtual BooleanExp* Copy() const = 0;

virtual void GetName( std::string& name ) = 0;
};

class VariableExp:public BooleanExp
{
public:
VariableExp()
{

}

VariableExp(const char *);

VariableExp( const VariableExp& exp )
{
_name = new char[strlen(exp._name)+1];
strcpy(_name, exp._name);
}

VariableExp& operator =( const VariableExp & exp )
{
return *this;
}

virtual ~VariableExp();

virtual bool Evaluate( Context& );

virtual BooleanExp* Replace( const char *, BooleanExp& ) ;

virtual BooleanExp* Copy() const ;

virtual void GetName( std::string& name );

private:

char *_name;
};

VariableExp::VariableExp( const char * name )
{
_name = new char[ strlen(name) + 1 ];
if ( NULL != _name )
{
memset( _name, 0 , strlen(name) + 1 );
strncpy( _name, name, strlen( name ) + 1 );
}
}

VariableExp::~VariableExp()
{
if ( NULL != _name )
{
delete []_name;
_name = NULL;
}
}

class Context
{
public:

bool Lookup( const char* name ) const;

void Assign( VariableExp* variable, bool bvalue);

private:

map< VariableExp*, bool > _map_varbool;
};

bool VariableExp::Evaluate( Context& aContext )
{
return aContext.Lookup( _name );
}

BooleanExp* VariableExp::Replace( const char *name, BooleanExp& exp )
{
if ( 0 == strcmp( name, _name ) )
{
return exp.Copy();
}
else
{
return new VariableExp( _name );
}
}

BooleanExp* VariableExp::Copy() const
{
return new VariableExp( _name );
}

void VariableExp::GetName( std::string& name )
{
name = _name;
}

void Context::Assign( VariableExp* variable, bool bvalue )
{

_map_varbool.insert( map< VariableExp*, bool >::value_type( variable, bvalue ) );
}

bool Context::Lookup( const char* name ) const
{
map< VariableExp*, bool >::const_iterator it = _map_varbool.begin();
for ( ; it != _map_varbool.end(); it++ )
{
VariableExp *pVariable = ( it->first );
std::string strname = "";
pVariable->GetName( strname );
if ( 0 == strname.compare( name ) )
{
printf("Context::Lookup name %s, value %d \r\n", name, it->second );
return it->second;
}
}
return false;
}

class AndExp:public BooleanExp
{
public:

AndExp( BooleanExp* op1, BooleanExp* op2 )
{
_operand1 = op1;
_operand2 = op2;
}

virtual ~AndExp()
{

}

virtual bool Evaluate( Context& );

virtual BooleanExp* Replace( const char *, BooleanExp& );

virtual BooleanExp* Copy() const ;


virtual void GetName( std::string &name )
{

}

private:

BooleanExp* _operand1;

BooleanExp* _operand2;
};

bool AndExp::Evaluate( Context& aContext)
{
bool result= _operand1->Evaluate( aContext ) && _operand2->Evaluate( aContext );
printf("AndExp::Evaluate %d\r\n", result );
return result;
}

BooleanExp* AndExp::Replace( const char *name, BooleanExp& exp)
{
return new AndExp( _operand1->Replace( name, exp ), _operand2->Replace( name, exp ) );
}

BooleanExp* AndExp::Copy() const
{
return new AndExp( _operand1->Copy(), _operand2->Copy() );
}

class NotExp:public BooleanExp
{
public:

NotExp( BooleanExp* op )
{
_operand = op;
}

virtual ~NotExp()
{

}

virtual bool Evaluate( Context& );

virtual BooleanExp* Replace( const char *, BooleanExp& );

virtual BooleanExp* Copy() const ;


virtual void GetName( std::string& name )
{

}

private:

BooleanExp* _operand;
};

bool NotExp::Evaluate( Context& aContext)
{
bool result= !(_operand->Evaluate( aContext ));
printf("NotExp::Evaluate %d\r\n", result );
return result;
}

BooleanExp* NotExp::Replace( const char *name, BooleanExp& exp)
{
return new NotExp( _operand->Replace( name, exp ) );
}

BooleanExp* NotExp::Copy() const
{
return new NotExp( _operand->Copy() );
}


class OrExp:public BooleanExp
{
public:

OrExp( BooleanExp* op1, BooleanExp* op2 )
{
_operand1 = op1;
_operand2 = op2;
}

virtual ~OrExp()
{

}

virtual bool Evaluate( Context& );

virtual BooleanExp* Replace( const char *, BooleanExp& );

virtual BooleanExp* Copy() const ;


virtual void GetName( std::string& name )
{

}

private:

BooleanExp* _operand1;

BooleanExp* _operand2;
};

bool OrExp::Evaluate( Context& aContext)
{
return _operand1->Evaluate( aContext ) | _operand2->Evaluate( aContext );
}

BooleanExp* OrExp::Replace( const char *name, BooleanExp& exp)
{
return new OrExp( _operand1->Replace( name, exp ), _operand2->Replace( name, exp ) );
}

BooleanExp* OrExp::Copy() const
{
return new OrExp( _operand1->Copy(), _operand2->Copy() );
}


int _tmain(int argc, _TCHAR* argv[])
{
// ( not y ) and x ) or ( y and ( not x ) )

BooleanExp *expression;

Context context;

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

expression = new OrExp( new AndExp( new NotExp( y ), x ),
new AndExp( y, new NotExp( x ) ) );

context.Assign( x, false );
context.Assign( y, true );
bool result = expression->Evaluate( context );
return 0;
}