1. 程式人生 > >設計模式C++實現-直譯器模式

設計模式C++實現-直譯器模式



1:概念

直譯器模式(interpreter):給定一個語言,定義它的文法的一種表示,並定義一個直譯器,這個直譯器使用該表示來解釋語言中的句子。

2:說明

包含哪些角色?

(1)AbstractExpression(抽象表示式):宣告一個抽象的解釋操作,這個介面為抽象語法樹中所有的節點所共享。

(2)TerminalExpression(終結符表示式):實現與文法中的終結符相關聯的解釋操作。實現抽象表示式中所要求的介面,主要是一個interpreter()方法。文法中每一個終結符都有一個具體終結表示式與之相對應。

(3)NonterminalExpression(非終結符表示式):為文法中的非終結符實現解釋操作。

(4)Context:包含直譯器之外的一些全域性資訊。

直譯器模式需要解決的問題?

如果一種特定型別的問題發生的頻率足夠高,那麼可能就值得將該問題的各個例項表述為一個簡單語言中的句子。這樣就可以構建一個直譯器,該直譯器通過解釋這些句子來解決該問題。

什麼時候用直譯器模式?

通常當有一個語言需呀解釋執行,並且你可將該語言中的句子表示為一個抽象語法樹時,可使用直譯器模式。

用直譯器模式的好處?

用瞭解釋器模式,就意味著可以很容易地改變和擴充套件文法,因為該模式使用類來表示文法規則,你可使用繼承來改變或擴充套件該文法。也比較容易實現文法,因為定義抽象語法樹種各個節點的類的實現大體類似,這些類都易於直接邊寫。

用直譯器模式的不足?

直譯器模式為文法中的每一條規則至少定義了一個類,因此包含許多規則的文法可能難以管理和維護。建議當文法非常複雜時,使用其他的技術如語法分析程式或編譯器生成器來處理。

由遇到的問題引出直譯器模式一些應用提供了內建(Build-In)的指令碼或者巨集語言來讓使用者可以定義他們能夠在系統中進行的操作。直譯器模式的目的就是使用一個直譯器為使用者提供一個一門定義語言的語法表示的直譯器,然後通過這個直譯器來解釋語言中的句子。

直譯器模式提供了這樣的一個實現語法直譯器的框架,筆者曾經也正在構建一個編譯系統 Visual CMCS,現在已經發布了 Visual CMCS1.0 (Beta),請大家訪問 Visual CMCS 網站獲取詳細資訊。

模式選擇

直譯器模式典型的結構圖為:


圖 2-1:直譯器模式結構圖


直譯器模式中,提供了 TerminalExpression 和 NonterminalExpression 兩種表示式的解釋方式,Context 類用於為解釋過程提供一些附加的資訊(例如全域性的資訊)。

直譯器模式的實現

完整程式碼示例(code):直譯器模式的實現比較簡單,這裡為了方便初學者的學習和參考,將給出完整的實現程式碼(所有程式碼採用 C++實現,並在 VC 6.0 下測試執行)。

程式碼片斷 1:Context.h
//Context.h
#ifndef _CONTEXT_H_
#define _CONTEXT_H_
class Context{
    public:
    Context();
    ~Context();
    protected:
    private:
};
#endif //~_CONTEXT_H_

程式碼片斷 2:Context.cpp
//Context.cpp
#include "Context.h"
Context::Context(){
}
Context::~Context(){
}

程式碼片斷 3:Interpret.h
//Interpret.h
#ifndef _INTERPRET_H_
#define _INTERPRET_H_
#include "Context.h"
#include <string>
using namespace std;
class AbstractExpression{
    public:
    virtual ~AbstractExpression();
    virtual void Interpret(const Context& c);
    protected:
    AbstractExpression();
    private:
};
class TerminalExpression:public AbstractExpression{
    public:
    TerminalExpression(const string& statement);
    ~ TerminalExpression();
    void Interpret(const Context& c);
    protected:
    private:
    string _statement;
};
class NonterminalExpression:public AbstractExpression{
    public:
    NonterminalExpression(AbstractExpression* expression,int times);
    ~ NonterminalExpression();
    void Interpret(const Context& c);
    protected:
    private:
    AbstractExpression* _expression;
    int _times;
};
#endif //~_INTERPRET_H_

程式碼片斷 4:Interpret.cpp
//interpret.cpp
#include "Interpret.h"
#include <iostream>
using namespace std;
AbstractExpression::AbstractExpression(){
}
AbstractExpression::~AbstractExpression(){
}
void AbstractExpression::Interpret(const Context& c){
}
TerminalExpression::TerminalExpression(const string& statement){
    this->_statement = statement;
}
TerminalExpression::~TerminalExpression(){
}
void TerminalExpression::Interpret(const Context& c){
    cout<<this->_statement<<" TerminalExpression"<<endl;
}
NonterminalExpression::NonterminalExpression(AbstractExpression* expression,int times){
    this->_expression = expression;
    this->_times = times;
}
NonterminalExpression::~NonterminalExpression(){
}
void NonterminalExpression::Interpret(const Context& c){
    for (int i = 0; i < _times ; i++){
        this->_expression->Interpret(c);
    }
}

程式碼片斷 5:main.cpp
//main.cpp
#include "Context.h"
#include "Interpret.h"
#include <iostream>
using namespace std;
int main(int argc,char* argv[]){
    Context* c = new Context();
    AbstractExpression* te = new TerminalExpression("hello");
    AbstractExpression* nte = new NonterminalExpression(te,2);
    nte->Interpret(*c);
    return 0;
}

程式碼說明:直譯器模式的示例程式碼很簡單,只是為了說明模式的組織和使用,實際的解釋Interpret 邏輯沒有實際提供。

關於直譯器模式的討論

XML 格式的資料解析是一個在應用開發中很常見並且有時候是很難處理的事情,雖然目前很多的開發平臺、語言都提供了對 XML 格式資料的解析,但是例如到了移動終端裝置上,由於處理速度、計算能力、儲存容量的原因解析 XML 格式的資料卻是很複雜的一件事情,最近也提出了很多的移動裝置的 XML 格式解析器,但是總體上在專案開發時候還是需要自己去設計和實現這一個過程(筆者就有過這個方面的痛苦經歷)。

直譯器模式則提供了一種很好的組織和設計這種解析器的架構。

直譯器模式中使用類來表示文法規則,因此可以很容易實現文法的擴充套件。另外對於終結符我們可以使用享元模式來實現終結符的共享。