一、概述
解釋器模式是一種按照規定語法進行解析的方案。給定一門語言,定義它的文法的一種表示,並定義一個解釋器,該解釋器使用該表示來解釋語言中的句子。
二、類圖
AbstractExpression爲抽象解釋器
TerminalExpression爲終結符表達式。實現與文法中的元素相關聯的操作,通常一個解釋器模式中只有一個終結符表達式,但有多個實例,對應不同的終結符。
NonterminalExpression爲非終結符表達式。文法中的每條規則對應於一個非終結表達式,具體到下面的實例就是加減法則分別對應到AddExpression和SubExpression兩個類。非終結符表達式根據邏輯的複雜程度而增加,原則上每個文法規則都對應一個非終結符表達式。
Context爲環境角色。
三、示例
//test.h
#pragma once
class Expression
{
public:
virtual int Interpreter(map<string, int>& mapValueList) = 0;
};
class VarExpression : public Expression
{
public:
VarExpression(string sVarName);
public:
virtual int Interpreter(map<string, int>& mapValueList);
private:
string m_sVarName;
};
class AddSymbolExpression : public Expression
{
public:
AddSymbolExpression(Expression* pLeftExpression, Expression* pRightExpression);
public:
virtual int Interpreter(map<string, int>& mapValueList);
private:
Expression* m_pLeftExpression;
Expression* m_pRightExpression;
};
class DelSymbolExpression : public Expression
{
public:
DelSymbolExpression(Expression* pLeftExpression, Expression* pRightExpression);
public:
virtual int Interpreter(map<string, int>& mapValueList);
private:
Expression* m_pLeftExpression;
Expression* m_pRightExpression;
};
class Calculator
{
public:
void SetExpressionString(string sExpressionString);
int GetResult(map<string,int> mapValueList);
private:
Expression* m_pExpression;
};
//test.cpp
#include <stdio.h>
#include <iostream>
#include <map>
#include <string>
#include <stack>
using namespace std;
#include "Test.h"
VarExpression::VarExpression(string sVarName)
:m_sVarName(sVarName)
{
}
int VarExpression::Interpreter(map<string, int>& mapValueList)
{
map<string, int>::iterator it = mapValueList.find(m_sVarName);
if (it != mapValueList.end())
{
return it->second;
}
return -1;
}
AddSymbolExpression::AddSymbolExpression(Expression* pLeftExpression, Expression* pRightExpression)
:m_pLeftExpression(pLeftExpression),m_pRightExpression(pRightExpression)
{
}
int AddSymbolExpression::Interpreter(map<string, int>& mapValueList)
{
return m_pLeftExpression->Interpreter(mapValueList) + m_pRightExpression->Interpreter(mapValueList);
}
DelSymbolExpression::DelSymbolExpression(Expression* pLeftExpression, Expression* pRightExpression)
:m_pLeftExpression(pLeftExpression), m_pRightExpression(pRightExpression)
{
}
int DelSymbolExpression::Interpreter(map<string, int>& mapValueList)
{
return m_pLeftExpression->Interpreter(mapValueList) - m_pRightExpression->Interpreter(mapValueList);
}
void Calculator::SetExpressionString(string sExpressionString)
{
std::stack<Expression*> stackExpressionList;
Expression* pLeftExpression;
Expression* pRightExpression;
for (int i = 0; i < sExpressionString.size(); i++)
{
char cTem = sExpressionString.at(i);
switch (cTem)
{
case '+':
{
pLeftExpression = stackExpressionList.top();
stackExpressionList.pop();
char buf[5] = { 0 };
sprintf(buf, "%c", sExpressionString.at(++i));
pRightExpression = new VarExpression(buf);
stackExpressionList.push(new AddSymbolExpression(pLeftExpression, pRightExpression));
}
break;
case '-':
{
pLeftExpression = stackExpressionList.top();
stackExpressionList.pop();
char buf[5] = { 0 };
sprintf(buf, "%c", sExpressionString.at(++i));
pRightExpression = new VarExpression(buf);
stackExpressionList.push(new DelSymbolExpression(pLeftExpression, pRightExpression));
}
break;
default:
{
char buf[5] = { 0 };
sprintf(buf, "%c", sExpressionString.at(i));
stackExpressionList.push(new VarExpression(buf));
}
break;
}
}
m_pExpression = stackExpressionList.top();
}
int Calculator::GetResult(map<string, int> mapValueList)
{
return m_pExpression->Interpreter(mapValueList);
}
int main()
{
Calculator cal;
cal.SetExpressionString("a+b-c+d");
map<string, int> mapValueList;
mapValueList["a"] = 100;
mapValueList["b"] = 55;
mapValueList["c"] = 84;
mapValueList["d"] = 1;
int nResult = cal.GetResult(mapValueList);
cout << "the result is: " << nResult << endl;
getchar();
return 0;
}
四、解釋器模式的優點
解釋器模式是一個簡單的語法分析工具,它的優點就是擴展性,修改語法規則只要修改相應的非終結符表達式即可,若擴展語法,則只要增加非終結符類就可以了。
五、解釋器模式的缺點
(1)引起類膨脹,每個語法都要產生一個非終結符表達式,語法規則比較複雜時,就會產生大量的類
(2)解釋器模式採用遞歸調用
每個非終結符表達式只關心與自己有關的表達式,每個表達式需要知道最終的結果,必須一層層遞歸。遞歸不僅使程序調試複雜,而且還會降低效率。