Thinking Different






Interpreter Pattern - 해석자 패턴


  • 문법 규칙을 클래스화 한 구조로써, 일련의 규칙으로 정의된 언어를 해석하는 패턴이다.
  • 문법 규칙이 많아지면 복잡해지고 무거워지기 때문에 그럴땐 차라리 파서/컴파일러 생성기를 쓰는게 좋다.
  • 언어분석기 라고 생각하면 되며, 스크립트나 컴파일러 문법 등이 있을수 있다.
  • 예로 SQL 구문이나 shell 커멘드 해석기, 통신 프로토콜 등이 있다.






샘플 코드)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <list>
 
#if _UNICODE
typedef wstring tstring;
#else
typedef string tstring;
#endif
 
//------------------------------------------------------------------
// Context 클래스
class Context
{
public:
    Context(const TCHAR* data) : mData(data) {}
 
public:
    const TCHAR* GetData() const { return mData.c_str(); }
    
private:
    tstring mData;
};
 
//------------------------------------------------------------------
// AbstractExpression 인터페이스
class AbstractExpression
{
public:
    virtual void interpret(Context* context) = 0;
};
 
//------------------------------------------------------------------
// TerminalExpression 상속 클래스
class TerminalExpression : public AbstractExpression
{
public:
    void interpret(Context* context) override { cout << "TerminalExpression: " << context->GetData() << endl; }
};
 
//------------------------------------------------------------------
// NonterminalExpression 상속 클래스
class NonterminalExpression : public AbstractExpression
{
public:
    void interpret(Context* context) override { cout << "NonterminalExpression: " << context->GetData() << endl; }
};
 
 
//------------------------------------------------------------------
// Main
int _tmain(int argc, _TCHAR* argv[])
{
    Context pContext("Programming Context Data");
 
    list<AbstractExpression*> mList;
    mList.push_back(new TerminalExpression());
    mList.push_back(new NonterminalExpression());
 
    for each (AbstractExpression* pExpression in mList)
    {
        pExpression->interpret(&pContext);
        delete pExpression;
    }
 
    mList.clear();
 
    return 0;
}




예제를 통한 해석자 패턴(Interpreter Pattern) 알아보기



예제) 문장 규칙 검사기 예제



AndExpression 클래스와 OrExpression을 정의하고 TerminalExpression에서 하나의 문장을 tokenizer하면서 주어진 context 의 명령이 And인지 Or인지 해석해주는 간단한 문장 규칙 검사기 예제이다.



예제 코드)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#include "stringTokenizer.h"
#include <list>
 
//------------------------------------------------------------------
// AbstractExpression 인터페이스
class AbstractExpression
{
public:
    virtual bool interpret(tstring str) = 0;
};
 
//------------------------------------------------------------------
// TerminalExpression 상속 클래스
class TerminalExpression : public AbstractExpression
{
public:
    TerminalExpression(tstring str) : mliteral(str) {}
 
public:
    bool interpret(tstring str) override 
    {
        stringTokenizer st(str, " ");
        while (st.hasMoreTokens())
        {
            tstring test = st.nextToken();
            if (test == mliteral) {
                return true;
            }
        }
        return false;
    }
 
private:
    tstring mliteral;
};
 
//------------------------------------------------------------------
// OrExpression 상속 클래스
class OrExpression : public AbstractExpression
{
public:
    OrExpression(AbstractExpression* e1, AbstractExpression* e2) : pExpression1(e1), pExpression2(e2) {}
    ~OrExpression() { if (pExpression1) delete pExpression1; if (pExpression2) delete pExpression2; }
 
public:
    bool interpret(tstring str) override { return pExpression1->interpret(str) || pExpression2->interpret(str); }
 
private:
    AbstractExpression* pExpression1;
    AbstractExpression* pExpression2;
};
 
//------------------------------------------------------------------
// AndExpression 상속 클래스
class AndExpression : public AbstractExpression
{
public:
    AndExpression(AbstractExpression* e1, AbstractExpression* e2) : pExpression1(e1), pExpression2(e2) {}
    ~AndExpression() { if (pExpression1) delete pExpression1; if (pExpression2) delete pExpression2; }
 
public:
    bool interpret(tstring str) override { return pExpression1->interpret(str) && pExpression2->interpret(str); }
 
private:
    AbstractExpression* pExpression1;
    AbstractExpression* pExpression2;
};
 
//------------------------------------------------------------------
// 해석자 문법 생성 함수 : "Owen and (John or (Henry or Mary))"
AbstractExpression* buildInterpreterTree()
{
    // Literal
    AbstractExpression* terminal1 = new TerminalExpression("John");
    AbstractExpression* terminal2 = new TerminalExpression("Henry");
    AbstractExpression* terminal3 = new TerminalExpression("Mary");
    AbstractExpression* terminal4 = new TerminalExpression("Owen");
 
    // Henry or Mary
    AbstractExpression* alternation1 = new OrExpression(terminal1, terminal2);
 
    // John or (Henry or Mary)
    AbstractExpression* alternation2 = new OrExpression(terminal3, alternation1);
 
    // Owen and (John or (Henry or Mary))
    return new AndExpression(terminal4, alternation2);
}
 
//------------------------------------------------------------------
// Main
int _tmain(int argc, _TCHAR* argv[])
{
    tstring pContext("Mary Owen");
    AbstractExpression* pExpression = buildInterpreterTree();
 
    cout << pContext << " is " << pExpression->interpret(pContext) << endl;
 
    delete pExpression;
 
    return 0;
}


예제 결과)