Sample Application for GOF's Design Pattern


VISITOR で四則演算?

■この例題で登場するデザインパターン■
VISITORINTERPRETERBUILDER

『VISITOR で四則演算?』では、VISITORを用いて、INTERPRETER で表現された数式を計算するプログラムを作ってみました。構文解析エンジン(Parser)は、『INTERPRETERでデータベースエンジンを作っちゃえ!』で用いたアルゴリズムをそのまま使っています。Parserの詳細については、そちらを参照してください。

ただ、ちょっと注意が必要なのは、このParserでは、正しく四則演算を行うことができません。このParserは、文字列を左から逐次ツリー化する単純なアルゴリズムであるため、掛け算や割り算を交えた計算は間違った答えが返る可能性があります。たとえば、次のような例題を考えます。

例題

1 + 2 * ( 3 + 4 ) = 15

これをそのまま入力すると、次のような構文が生成され、間違った結果となってしまいます。

例題のまま、Parserに入力した場合に生成されるツリーと結果

( 1 + 2 ) * ( 3 + 4 ) = 21

期待する正しい答えを出すには、掛け算が優先であることをParserに明示的に示してあげなければなりません。例題で正しい結果を得るには、次のような書式にしなければなりません。

正しい結果を得るための
入力書式

1 + ( 2 * ( 3 + 4 ) ) = 15

Parserを正しく数式を解釈するように拡張したい場合は、bison や JavaCC等 の構文解析エンジンを用いるのが早道です。興味のある方は『jjtree(JavaCC)で、Visitorパターンをマスター』を参考にしてください。

ということで、あまり使えない計算器ですが、実際の動作をみてみましょう。

$ java VisitorSample
> 480 + 240 + 120 - 160
Expression: (((480 + 240) + 120) - 160) = 680 
// INTERPRETERなので必ず対のツリーになる
> ( 210 * 2 ) + 680 + ( 160 * 4 )
Expression: (((210 * 2) + 680) + (160 * 4)) = 1740
> ( 780 + 1480 + 960 ) / 3
Expression: (((780 + 1480) + 960) / 3) = 1073
> end

$

実用的かどうかは別として、一応動きましたね。

ここからは、VISITOR の薀蓄をたれようと思いますので、興味ない方は飛ばしてください。

VISITOR は、デザインパターンの入門者には、とても難しいもののように捕らえられているようです。しかし、その役割は単純で、クラスに応じた処理を Visitor クラス内にカプセル化したものにすぎません。というと難しいですが、簡単に言うと、 Visitor クラスは、switch をクラス化したものと言えば分かりやすいでしょう。

しかし、なぜ、switch ではなく、VISITOR なのでしょうか?その理由を知る前に次のような場面を想定してください。

例えば、COMPOSITE INTERPRETER パターンでは、クライアントが扱っているオブジェクト(ElementExpression)のクラスが抽象クラスを扱うことになるためオブジェクトの特質が曖昧になるという問題が発生します。

クライアントは、あるオブジェクトA(ElementA::Element)だけがもつ OperationA()、また別のオブジェクトB(ElementB::Element)がもつ OperationB() というメソッドをそれぞれ使い分けなければならない場合、ダイナミック・キャストを用いて、動的にクラスを特定しなければなりません。つまり、オブジェクト指向設計されたプログラムでは、便利な switch は使えず、if-else で全て処理をする必要があるわけです。さらに、ダイナミックキャストは処理系によってはサポートされていなかったり、サポートされているものもコストがかかる(オブジェクトサイズが大きくなり、処理が重くなる)などの問題や、何よりコードの可読性を落とすため、一般的には頻繁に用いるべきものではありません。

ダイナミックキャストを使わずにクラスに応じた処理にスイッチする。そのための解法が VISITOR なのです。

VISITOR パターンは、オブジェクトのクラスを特定するためにコンパイラの型チェック機構を利用し、それぞれのオブジェクトを特定します。この型チェック機構を利用するために、Visitor ならびに、Visitor の処理対象となるクラス (ElementExpression)は、それぞれプロトコルインターフェースを備える必要があります。例えば、処理対象クラスを Element とすると、VisitorElement は以下のようなプロトコルインターフェースを備えることになります。

Visitorパターンに特徴的なプロトコルインターフェース(その1)
Visitor Element
interface Visitor {
    void visit(ElementA a);
    void visit(ElementB b);
    ・・・
    void visit(ElementN n);
};
class Element {
    abstract public void accept(Visitor v);
}
class ElementA extends Element {
    public void accept(Visitor v) {
        v.visit(this);
    } 
}
class ElementB extends Element {
    public void accept(Visitor v) {
        v.visit(this);
    }
}
・・・・
class ElementN extends Element {
    public void accept(Visitor v) {
        v.visit(this);
    }
}

Visitor のインターフェースである visitメソッド の扱いには注意してください。例えば、visit(Element e) などとすると、Visitor が正しく動作しません。常識的に考えれば分かることですが、オーバーロード関数の引数に、抽象クラスと、具象クラスを混在させるようなことをすると、型チェック機構は正しく機能しません。

もし、抽象クラスである Element を対象とした処理を走らせ、その後に具象クラスを処理しなければならないケースが発生する場合は、メソッドを明示的に特定するため、引数の数を変えるか、メソッド名を変える必要があります。以下のような形になるでしょう。

Visitorパターンに特徴的なプロトコルインターフェース(その2)
Visitor Element
interface Visitor {
    void visit(Element e);
    void visitElementA(ElementA a);
    void visitElementB(ElementB b);
    ・・・
    void visitElementN(ElementN n);
};
class Element {
    public void accept(Visitor v) {
        v.visit(this);
        acceptExtendedClass(v);
    }
    abstract protected void acceptExtendedClass(Visitor v);
}
class ElementA extends Element {
    protected void acceptExtendedClass(Visitor v) {
        v.visitElementA(this);
    } 
}
class ElementB extends Element {
    protected void acceptExtendedClass(Visitor v) {
        v.visitElementB(this);
    }
}
・・・・
class ElementN extends Element {
    protected void acceptExtendedClass(Visitor v) {
        v.visitElementN(this);
    }
}

VISITOR については、『jjtree(JavaCC)で、Visitorパターンをマスター』にて詳細な考察を行っています。興味ある方はご参照ください。


■ 『VISITOR で四則演算?』の構造

クラスの数が多くなってしまったため、図中から、divExpressionmulExpression は省略しています。構造は、足し算引き算のオペレータである addExpressionsubExpression と同一です。詳細はソースコードを参照してください。



■ 『VISITOR で四則演算?』 のJavaプログラム・コード

□ Java2版
InterpreterSample.java
// Copyright(C) 2004 Yoshinori Oota All rights reserved.
import java.io.InputStreamReader;
import java.io.BufferedReader;

public class VisitorSample { 
    static public void main(String args[]) { 
        QueryParser parser = new QueryParser();
        dumpVisitor dump = new dumpVisitor();
        calcVisitor calc = new calcVisitor();

        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
            while (true) {
                System.out.print("> ");
                String input = reader.readLine();
                if (input.equals("end")) {
                    break;
                }
                Expression exp = parser.parse(input);
                if (exp == null) {
                    continue;
                }
                System.out.print("Expression: ");
                exp.accept(dump);
                System.out.print(dump.getResult());
                dump.clear();

                exp.accept(calc);
                System.out.println(" = " + calc.getResult());
                exp = null;
            }
        } catch (java.io.IOException e) {
            e.printStackTrace();
            System.err.println(e);
            return;
        } 
    } 
}
QueryParser.java
// Copyright(C) 2004 Yoshinori Oota All rights reserved.
import java.io.StringReader;
import java.io.BufferedReader;
import java.io.StreamTokenizer;
import java.util.LinkedList;

public class QueryParser {
    private Expression _cur = null;
    private LinkedList _stk = new LinkedList();

    public Expression parse(String data) throws java.io.IOException {

        BufferedReader reader = new BufferedReader(new StringReader(data));
        StreamTokenizer in = new StreamTokenizer(reader);
        in.ordinaryChar('/');

        try {
            Expression exp = null;
            _cur = new bracketExpression();
            while (in.nextToken() != StreamTokenizer.TT_EOF) {
                switch (in.ttype) {
                case '+':
                    _cur = new addExpression(_cur);
                    break;
                case '-':
                    _cur = new subExpression(_cur);
                    break;
                case '*':
                    _cur = new mulExpression(_cur);
                    break;
                case '/':
                    _cur = new divExpression(_cur);
                    break;
                case '(':
                    _stk.add(_cur);
                    _cur = new bracketExpression();
                    break;
                case ')':
                    exp = (Expression)_stk.removeLast();
                    if (exp.isOperator()) {
                        exp.addRightHandSide(_cur);
                        _cur = exp;
                    }
                    break;
                case StreamTokenizer.TT_NUMBER:
                    exp = new terminalExpression((int)in.nval); 
                    if (_cur.isOperator()) {
                        _cur.addRightHandSide(exp);
                    } else {
                        _cur = exp;
                    }
                }
            }
        } catch (IllegalStateException e) {
            e.printStackTrace();
            System.err.println(e);
        }
        if (_stk.size() != 0) {
            System.err.println("parse error");
            _stk.clear();
            _cur = null;
        }
        return _cur;
    }
}
Expression.java
// Copyright(C) 2004 Yoshinori Oota All rights reserved.

abstract public class Expression { 
    abstract void addRightHandSide(Expression exp) throws IllegalStateException;
    abstract void addLeftHandSide(Expression exp)  throws IllegalStateException;
    abstract boolean isOperator();
    abstract public void accept(Visitor v);
}
terminalExpression.java
// Copyright(C) 2004 Yoshinori Oota All rights reserved.

public class terminalExpression extends Expression { 
    private int _number = null;
    public terminalExpression(int number) { 
        _number = number; 
    }
    public int getValue() { 
        return _number; 
    }
    void addRightHandSide(Expression exp) throws IllegalStateException {
        throw new IllegalStateException("Invalid call terminalExpression::addRightHandSide");
    }
    void addLeftHandSide(Expression exp) throws IllegalStateException  {
        throw new IllegalStateException("Invalid call terminalExpression::addLeftHandSide");
    }
    boolean isOperator() {
        return false;
    }
    public void accept(Visitor v) {
        v.Visit(this);
    }
}
bracketExpression.java
// Copyright(C) 2004 Yoshinori Oota All rights reserved.

public class bracketExpression extends Expression {
    void addRightHandSide(Expression exp) throws IllegalStateException {
        throw new IllegalStateException("Invalid call terminalExpression::addRightHandSide");
    }
    void addLeftHandSide(Expression exp) throws IllegalStateException  {
        throw new IllegalStateException("Invalid call terminalExpression::addLeftHandSide");
    }
    boolean isOperator() {
        return false;
    }
    public void accept(Visitor v) {
        // do nothing.
    }
} 
sequenceExpression.java
// Copyright(C) 2004 Yoshinori Oota All rights reserved.

public class addExpression extends Expression { 
    private Expression _lhs = null;
    private Expression _rhs = null;

    public addExpression() { }
    public addExpression(Expression lhs) {
        _lhs = lhs;
    }
    void addRightHandSide(Expression rhs) {
        _rhs = rhs;
    }
    void addLeftHandSide(Expression lhs) {
        _lhs = lhs;
    }
    boolean isOperator() {
        return true;
    }
    Expression getRightHandSide() {
        return _rhs;
    }
    Expression getLeftHandSide() {
        return _lhs;
    }
    public void accept(Visitor v) {
        v.Visit(this);
    }
}
subExpression.java
// Copyright(C) 2004 Yoshinori Oota All rights reserved.

public class subExpression extends Expression { 
    private Expression _lhs = null;
    private Expression _rhs = null;

    public subExpression() { }
    public subExpression(Expression lhs) {
        _lhs = lhs;
    }
    void addRightHandSide(Expression rhs) {
        _rhs = rhs;
    }
    void addLeftHandSide(Expression lhs) {
        _lhs = lhs;
    }
    boolean isOperator() {
        return true;
    }
    Expression getRightHandSide() {
        return _rhs;
    }
    Expression getLeftHandSide() {
        return _lhs;
    }
    public void accept(Visitor v) {
        v.Visit(this);
    }
}
mulExpression.java
// Copyright(C) 2004 Yoshinori Oota All rights reserved.

public class mulExpression extends Expression { 
    private Expression _lhs = null;
    private Expression _rhs = null;

    public mulExpression() { }
    public mulExpression(Expression lhs) {
        _lhs = lhs;
    }
    void addRightHandSide(Expression rhs) {
        _rhs = rhs;
    }
    void addLeftHandSide(Expression lhs) {
        _lhs = lhs;
    }
    boolean isOperator() {
        return true;
    }
    Expression getRightHandSide() {
        return _rhs;
    }
    Expression getLeftHandSide() {
        return _lhs;
    }
    public void accept(Visitor v) {
        v.Visit(this);
    }
}
divExpression.java
// Copyright(C) 2004 Yoshinori Oota All rights reserved.

public class divExpression extends Expression { 
    private Expression _lhs = null;
    private Expression _rhs = null;

    public divExpression() { }
    public divExpression(Expression lhs) {
        _lhs = lhs;
    }
    void addRightHandSide(Expression rhs) {
        _rhs = rhs;
    }
    void addLeftHandSide(Expression lhs) {
        _lhs = lhs;
    }
    boolean isOperator() {
        return true;
    }
    Expression getRightHandSide() {
        return _rhs;
    }
    Expression getLeftHandSide() {
        return _lhs;
    }
    public void accept(Visitor v) {
        v.Visit(this);
    }
}
Visitor.java
// Copyright(C) 2004 Yoshinori Oota All rights reserved.

abstract public class Visitor {
    abstract void Visit(terminalExpression exp);
    abstract void Visit(addExpression exp);
    abstract void Visit(subExpression exp);
    abstract void Visit(mulExpression exp);
    abstract void Visit(divExpression exp);
}
dumpVisitor.java
// Copyright(C) 2004 Yoshinori Oota All rights reserved.

public class dumpVisitor extends Visitor {
    private String _expression = "";
    void Visit(terminalExpression exp) {
        _expression += exp.getValue();
    }
    void Visit(addExpression exp) {
        _expression += "(";
        Expression lhs = exp.getLeftHandSide();
        lhs.accept(this);
        _expression += " + ";
        Expression rhs = exp.getRightHandSide();
        rhs.accept(this);
        _expression += ")";
    }
    void Visit(subExpression exp) {
        _expression += "(";
        Expression lhs = exp.getLeftHandSide();
        lhs.accept(this);
        _expression += " - ";
        Expression rhs = exp.getRightHandSide();
        rhs.accept(this);
        _expression += ")";
    }
    void Visit(mulExpression exp) {
        _expression += "(";
        Expression lhs = exp.getLeftHandSide();
        lhs.accept(this);
        _expression += " * ";
        Expression rhs = exp.getRightHandSide();
        rhs.accept(this);
        _expression += ")";
    }
    void Visit(divExpression exp) {
        _expression += "(";
        Expression lhs = exp.getLeftHandSide();
        lhs.accept(this);
        _expression += " / ";
        Expression rhs = exp.getRightHandSide();
        rhs.accept(this);
        _expression += ")";
    }
    public void clear() {
        _expression = "";
    }
    public String getResult() {
        return _expression;
    }
}
calcVisitor.java
// Copyright(C) 2004 Yoshinori Oota All rights reserved.

public class calcVisitor extends Visitor {
    private int _value = 0;
    void Visit(terminalExpression exp) {
        _value = exp.getValue();
    }
    void Visit(addExpression exp) {
        Expression lhs = exp.getLeftHandSide();
        lhs.accept(this);
        int value = _value;
        Expression rhs = exp.getRightHandSide();
        rhs.accept(this);
        _value += value;
    }
    void Visit(subExpression exp) {
        Expression lhs = exp.getLeftHandSide();
        lhs.accept(this);
        int value = _value;
        Expression rhs = exp.getRightHandSide();
        rhs.accept(this);
        _value = value - _value;
    }
    void Visit(mulExpression exp) {
        Expression lhs = exp.getLeftHandSide();
        lhs.accept(this);
        int value = _value;
        Expression rhs = exp.getRightHandSide();
        rhs.accept(this);
        _value = value * _value;
    }
    void Visit(divExpression exp) {
        Expression lhs = exp.getLeftHandSide();
        lhs.accept(this);
        int value = _value;
        Expression rhs = exp.getRightHandSide();
        rhs.accept(this);
        _value = value / _value;
    }
    public void clear() {
        _value = 0;
    }
    public int getResult() {
        return _value;
    }
}


■ 『VISITOR で四則演算?』 のC++(Win32)プログラム・コード

□ C++版
InterpreterSample.cpp
// Copyright(C) 2004 Yoshinori Oota All rights reserved.
#include <string>
#include <iostream>
#include "QueryParser.h"
#include "Expression.h"
#include "calcVisitor.h"
#include "dumpVisitor.h"

#define LINE_BUF 1024

int main(int argc, char* argv[]) {
    using namespace std;

    QueryParser parser;
    dumpVisitor* dump = new dumpVisitor();
    calcVisitor* calc = new calcVisitor();

    char buffer[LINE_BUF];
    while (true) {
        cout << "> ";
        cin.getline(buffer, LINE_BUF);
        string query = buffer;
        if (query == "end") {
            break;
        }
        Expression* exp = parser.parse(query);
        if (exp == NULL) {
            continue;
        }
        std::cout << "Expression: ";
        exp->accept(dump);
        exp->accept(calc);
        std::cout << " = " << calc->getResult() << std::endl;
        calc->clear();

        delete exp;
    }
    delete dump;
    delete calc;
} 
QueryParser
// Copyright(C) 2004 Yoshinori Oota All rights reserved.
#ifndef QUERYPARSER_HEADER_GUARD__
#define QUERYPARSER_HEADER_GUARD__

#include <string>
#include <stack>

class Expression;

class QueryParser {
public:
    QueryParser();
    ~QueryParser();
    Expression* parse(const std::string& line);
private:
    void clearStack();
    Expression* cur_;
    std::stack<Expression*> stk_;

};

#endif  // QUERYPARSER_HEADER_GUARD__
// Copyright(C) 2004 Yoshinori Oota All rights reserved.
#include "QueryParser.h"
#include "terminalExpression.h"
#include "bracketExpression.h"
#include "addExpression.h"
#include "subExpression.h"
#include "mulExpression.h"
#include "divExpression.h"
#include <sstream>
#include <iostream>
#include <cstdlib>


QueryParser::QueryParser() : cur_(NULL) { }
QueryParser::~QueryParser() { 
    cur_ = NULL;
    clearStack();
}

Expression* QueryParser::parse(const std::string& line) {
    using namespace std;
    istringstream is(line);
    string token;

    try {
        Expression* exp = NULL;
        cur_ = new bracketExpression();
        while (is >> token) {
            if (token == "+") {
                cur_ = new addExpression(cur_);
            } else if (token == "-") {
                cur_ = new subExpression(cur_);
            } else if (token == "*") {
                cur_ = new mulExpression(cur_);
            } else if (token == "/") {
                cur_ = new divExpression(cur_);
            } else if (token == "(") {
                stk_.push(cur_);
                cur_ = new bracketExpression();
            } else if (token == ")") {
                exp = stk_.top();
                if (exp->isOperator()) {
                    exp->addRightHandSide(cur_);
                    cur_ = exp;
                } else {
                    delete exp;
                }
                stk_.pop();
            } else {
                exp = new terminalExpression(atoi(token.c_str())); 
                if (cur_->isOperator()) {
                    cur_->addRightHandSide(exp);
                } else {
                    delete cur_;
                    cur_ = exp;
                }
            }
        }
    } catch (invalid_argument& e) {
        cerr << "exception: " << e.what() << endl;
        clearStack();
        if (cur_ != NULL) {
            delete cur_;
            cur_ = NULL;
        }
    }

    if (!stk_.empty()) {
        cerr << "parse error. " << endl;
        clearStack();
        if (cur_ != NULL) {
            delete cur_;
            cur_ = NULL;
        }
    }

    return cur_;
}

void QueryParser::clearStack() {
    while (!stk_.empty()) {
        Expression* exp = stk_.top();
        delete exp;
        stk_.pop();
    }
}
Expression
// Copyright(C) 2004 Yoshinori Oota All rights reserved.
#ifndef EXPRESSION_HEADER_GUARD__
#define EXPRESSION_HEADER_GUARD__

#include <stdexcept>

class Visitor;

class Expression { 
public:
    Expression();
    virtual ~Expression();
    virtual void accept(Visitor* v) const = 0;
protected:
    friend class QueryParser;
    virtual void addRightHandSide(Expression* exp) throw (std::invalid_argument) = 0;
    virtual void addLeftHandSide(Expression* exp) throw (std::invalid_argument) = 0;
    virtual bool isOperator() const = 0;
};

#endif  // EXPRESSION_HEADER_GUARD__
// Copyright(C) 2004 Yoshinori Oota All rights reserved.
#include "Expression.h"

Expression::Expression() { }
Expression::~Expression() { }
terminalExpression
// Copyright(C) 2004 Yoshinori Oota All rights reserved.
#ifndef TERMINALEXPRESSION_HEADER_GUARD__
#define TERMINALEXPRESSION_HEADER_GUARD__

#include "Expression.h"

class terminalExpression : public Expression {
public:
    terminalExpression(int number);
    virtual ~terminalExpression();
    virtual void accept(Visitor* v) const;
    int getValue() const;
protected:
    virtual void addRightHandSide(Expression* rhs) throw (std::invalid_argument);
    virtual void addLeftHandSide(Expression* lhs) throw (std::invalid_argument);
    virtual bool isOperator() const;
private:
    int number_;
};

#endif  // TERMINALEXPRESSION_HEADER_GUARD__
// Copyright(C) 2004 Yoshinori Oota All rights reserved.
#include <iostream>
#include "terminalExpression.h"
#include "Visitor.h"

terminalExpression::terminalExpression(int number) : number_(number) { }
terminalExpression::~terminalExpression() { }

void terminalExpression::addRightHandSide(Expression* exp1) throw (std::invalid_argument) {
    throw std::invalid_argument("invalid call terminalExpression::addRightHandSide()");
}
void terminalExpression::addLeftHandSide(Expression* exp2) throw (std::invalid_argument) {
    throw std::invalid_argument("invalid call terminalExpression::addLeftHandSide()");
}
bool terminalExpression::isOperator() const {
    return false;
}
void terminalExpression::accept(Visitor* v) const {
    v->Visit(this);
}
int terminalExpression::getValue() const {
    return number_;
}
bracketExpression
// Copyright(C) 2004 Yoshinori Oota All rights reserved.
#ifndef BRACKETEXPRESSION_HEADER_GUARD__
#define BRACKETEXPRESSION_HEADER_GUARD__

#include "Expression.h"

class bracketExpression : public Expression {
public:
    bracketExpression();
    virtual ~bracketExpression();
    virtual void accept(Visitor* v) const;
protected:
    virtual void addRightHandSide(Expression* exp1) throw (std::invalid_argument);
    virtual void addLeftHandSide(Expression* exp2) throw (std::invalid_argument);
    virtual bool isOperator() const;
};

#endif  // BRACKETEXPRESSION_HEADER_GUARD__
// Copyright(C) 2004 Yoshinori Oota All rights reserved.
#include "bracketExpression.h"
#include "Visitor.h"

bracketExpression::bracketExpression() { }
bracketExpression::~bracketExpression() { }

void bracketExpression::addRightHandSide(Expression* exp1) throw (std::invalid_argument){
    throw std::invalid_argument("invalid call bracketExpression::addRightHandSide()");
}
void bracketExpression::addLeftHandSide(Expression* exp2) throw (std::invalid_argument){
    throw std::invalid_argument("invalid call bracketExpression::addLeftHandSide()");
}
void bracketExpression::accept(Visitor* v) const {
    // do nothing
}
bool bracketExpression::isOperator() const {
    return false;
}
addExpression
// Copyright(C) 2004 Yoshinori Oota All rights reserved.
#ifndef ADDEXPRESSION_HEADER_GUARD__
#define ADDEXPRESSION_HEADER_GUARD__

#include "Expression.h"

class addExpression : public Expression {
public:
    addExpression();
    addExpression(Expression* lhs);
    virtual ~addExpression();
    virtual void accept(Visitor* v) const;
    const Expression* getRightHandSide() const;
    const Expression* getLeftHandSide() const;
protected:
    friend class QueryParser;
    virtual void addRightHandSide(Expression* rhs) throw (std::invalid_argument);
    virtual void addLeftHandSide(Expression* lhs) throw (std::invalid_argument);
    virtual bool isOperator() const;
private:
    Expression* lhs_;
    Expression* rhs_;
};

#endif  // ADDEXPRESSION_HEADER_GUARD__
// Copyright(C) 2004 Yoshinori Oota All rights reserved.
#include "addExpression.h"
#include "Visitor.h"

addExpression::addExpression() : lhs_(0), rhs_(0) { }
addExpression::addExpression(Expression* lhs) : lhs_(lhs), rhs_(0) { }
addExpression::~addExpression() {
    if (lhs_ != 0) {
        delete lhs_;
    }
    if (rhs_ != 0) {
        delete rhs_;
    }
}
void addExpression::addRightHandSide(Expression* rhs) throw (std::invalid_argument) {
    rhs_ = rhs;
}
void addExpression::addLeftHandSide(Expression* lhs) throw (std::invalid_argument) {
    lhs_ = lhs;
}
bool addExpression::isOperator() const {
    return true;
}
const Expression* addExpression::getRightHandSide() const {
    return rhs_;
}
const Expression* addExpression::getLeftHandSide() const {
    return lhs_;
}
void addExpression::accept(Visitor* v) const {
    v->Visit(this);
}
subExpression
// Copyright(C) 2004 Yoshinori Oota All rights reserved.
#ifndef SUBEXPRESSION_HEADER_GUARD__
#define SUBEXPRESSION_HEADER_GUARD__

#include "Expression.h"

class subExpression : public Expression {
public:
    subExpression();
    subExpression(Expression* lhs);
    virtual ~subExpression();
    virtual void accept(Visitor* v) const;
    const Expression* getRightHandSide() const;
    const Expression* getLeftHandSide() const;
protected:
    friend class QueryParser;
    virtual void addRightHandSide(Expression* rhs) throw (std::invalid_argument);
    virtual void addLeftHandSide(Expression* lhs) throw (std::invalid_argument);
    virtual bool isOperator() const;
private:
    Expression* lhs_;
    Expression* rhs_;
};

#endif  // SUBEXPRESSION_HEADER_GUARD__
// Copyright(C) 2004 Yoshinori Oota All rights reserved.
#include "subExpression.h"
#include "Visitor.h"

subExpression::subExpression() : lhs_(0), rhs_(0) { }
subExpression::subExpression(Expression* lhs) : lhs_(lhs), rhs_(0) { }
subExpression::~subExpression() {
    if (lhs_ != 0) {
        delete lhs_;
    }
    if (rhs_ != 0) {
        delete rhs_;
    }
}
void subExpression::addRightHandSide(Expression* rhs) throw (std::invalid_argument) {
    rhs_ = rhs;
}
void subExpression::addLeftHandSide(Expression* lhs) throw (std::invalid_argument) {
    lhs_ = lhs;
}
bool subExpression::isOperator() const {
    return true;
}
const Expression* subExpression::getRightHandSide() const {
    return rhs_;
}
const Expression* subExpression::getLeftHandSide() const {
    return lhs_;
}
void subExpression::accept(Visitor* v) const {
    v->Visit(this);
}
mulExpression
// Copyright(C) 2004 Yoshinori Oota All rights reserved.
#ifndef MULEXPRESSION_HEADER_GUARD__
#define MULEXPRESSION_HEADER_GUARD__

#include "Expression.h"

class mulExpression : public Expression {
public:
    mulExpression();
    mulExpression(Expression* lhs);
    virtual ~mulExpression();
    virtual void accept(Visitor* v) const;
    const Expression* getRightHandSide() const;
    const Expression* getLeftHandSide() const;
protected:
    friend class QueryParser;
    virtual void addRightHandSide(Expression* rhs) throw (std::invalid_argument);
    virtual void addLeftHandSide(Expression* lhs) throw (std::invalid_argument);
    virtual bool isOperator() const;
private:
    Expression* lhs_;
    Expression* rhs_;
};

#endif  // MULEXPRESSION_HEADER_GUARD__
// Copyright(C) 2004 Yoshinori Oota All rights reserved.
#include "mulExpression.h"
#include "Visitor.h"

mulExpression::mulExpression() : lhs_(0), rhs_(0) { }
mulExpression::mulExpression(Expression* lhs) : lhs_(lhs), rhs_(0) { }
mulExpression::~mulExpression() {
    if (lhs_ != 0) {
        delete lhs_;
    }
    if (rhs_ != 0) {
        delete rhs_;
    }
}
void mulExpression::addRightHandSide(Expression* rhs) throw (std::invalid_argument) {
    rhs_ = rhs;
}
void mulExpression::addLeftHandSide(Expression* lhs) throw (std::invalid_argument) {
    lhs_ = lhs;
}
bool mulExpression::isOperator() const {
    return true;
}
const Expression* mulExpression::getRightHandSide() const {
    return rhs_;
}
const Expression* mulExpression::getLeftHandSide() const {
    return lhs_;
}
void mulExpression::accept(Visitor* v) const {
    v->Visit(this);
}
divExpression
// Copyright(C) 2004 Yoshinori Oota All rights reserved.
#ifndef DIVEXPRESSION_HEADER_GUARD__
#define DIVEXPRESSION_HEADER_GUARD__

#include "Expression.h"

class divExpression : public Expression {
public:
    divExpression();
    divExpression(Expression* lhs);
    virtual ~divExpression();
    virtual void accept(Visitor* v) const;
    const Expression* getRightHandSide() const;
    const Expression* getLeftHandSide() const;
protected:
    friend class QueryParser;
    virtual void addRightHandSide(Expression* rhs) throw (std::invalid_argument);
    virtual void addLeftHandSide(Expression* lhs) throw (std::invalid_argument);
    virtual bool isOperator() const;
private:
    Expression* lhs_;
    Expression* rhs_;
};

#endif  // DIVEXPRESSION_HEADER_GUARD__
// Copyright(C) 2004 Yoshinori Oota All rights reserved.
#include "divExpression.h"
#include "Visitor.h"

divExpression::divExpression() : lhs_(0), rhs_(0) { }
divExpression::divExpression(Expression* lhs) : lhs_(lhs), rhs_(0) { }
divExpression::~divExpression() {
    if (lhs_ != 0) {
        delete lhs_;
    }
    if (rhs_ != 0) {
        delete rhs_;
    }
}
void divExpression::addRightHandSide(Expression* rhs) throw (std::invalid_argument) {
    rhs_ = rhs;
}
void divExpression::addLeftHandSide(Expression* lhs) throw (std::invalid_argument) {
    lhs_ = lhs;
}
bool divExpression::isOperator() const {
    return true;
}
const Expression* divExpression::getRightHandSide() const {
    return rhs_;
}
const Expression* divExpression::getLeftHandSide() const {
    return lhs_;
}
void divExpression::accept(Visitor* v) const {
    v->Visit(this);
}
Visitor
// Copyright(C) 2004 Yoshinori Oota All rights reserved.
#ifndef VISITOR_HEADER_GUARD__
#define VISITOR_HEADER_GUARD__

class terminalExpression;
class addExpression;
class subExpression;
class mulExpression;
class divExpression;

class Visitor {
public:
    Visitor();
    virtual ~Visitor();
    virtual void Visit(const terminalExpression* exp) = 0;
    virtual void Visit(const addExpression* exp) = 0;
    virtual void Visit(const subExpression* exp) = 0;
    virtual void Visit(const mulExpression* exp) = 0;
    virtual void Visit(const divExpression* exp) = 0;
};

#endif  // VISITOR_HEADER_GUARD__
// Copyright(C) 2004 Yoshinori Oota All rights reserved.
#include "Visitor.h"

Visitor::Visitor() { }
Visitor::~Visitor() { }
dumpVisitor
// Copyright(C) 2004 Yoshinori Oota All rights reserved.
#ifndef DUMPVISITOR_HEADER_GUARD__
#define DUMPVISITOR_HEADER_GUARD__

#include "Visitor.h"

class dumpVisitor : public Visitor {
public:
    dumpVisitor();
    virtual ~dumpVisitor();
    virtual void Visit(const terminalExpression* exp);
    virtual void Visit(const addExpression* exp);
    virtual void Visit(const subExpression* exp);
    virtual void Visit(const mulExpression* exp);
    virtual void Visit(const divExpression* exp);
};

#endif  // DUMPVISITOR_HEADER_GUARD__
// Copyright(C) 2004 Yoshinori Oota All rights reserved.
#include <iostream>
#include "dumpVisitor.h"
#include "terminalExpression.h"
#include "addExpression.h"
#include "subExpression.h"
#include "mulExpression.h"
#include "divExpression.h"

dumpVisitor::dumpVisitor() { }
dumpVisitor::~dumpVisitor() { }

void dumpVisitor::Visit(const terminalExpression* exp) {
    std::cout << exp->getValue();
}
void dumpVisitor::Visit(const addExpression* exp) {
    std::cout << "(";
    const Expression* lhs = exp->getLeftHandSide();
    lhs->accept(this);
    std::cout << " + ";
    const Expression* rhs = exp->getRightHandSide();
    rhs->accept(this);
    std::cout << ")";
}
void dumpVisitor::Visit(const subExpression* exp) {
    std::cout << "(";
    const Expression* lhs = exp->getLeftHandSide();
    lhs->accept(this);
    std::cout << " - ";
    const Expression* rhs = exp->getRightHandSide();
    rhs->accept(this);
    std::cout << ")";
}
void dumpVisitor::Visit(const mulExpression* exp) {
    std::cout << "(";
    const Expression* lhs = exp->getLeftHandSide();
    lhs->accept(this);
    std::cout << " * ";
    const Expression* rhs = exp->getRightHandSide();
    rhs->accept(this);
    std::cout << ")";
}
void dumpVisitor::Visit(const divExpression* exp) {
    std::cout << "(";
    const Expression* lhs = exp->getLeftHandSide();
    lhs->accept(this);
    std::cout << " / ";
    const Expression* rhs = exp->getRightHandSide();
    rhs->accept(this);
    std::cout << ")";
}
calcVisitor
// Copyright(C) 2004 Yoshinori Oota All rights reserved.
#ifndef CALCVISITOR_HEADER_GUARD__
#define CALCVISITOR_HEADER_GUARD__

#include "Visitor.h"

class calcVisitor : public Visitor {
public:
    calcVisitor();
    virtual ~calcVisitor();
    virtual void Visit(const terminalExpression* exp);
    virtual void Visit(const addExpression* exp);
    virtual void Visit(const subExpression* exp);
    virtual void Visit(const mulExpression* exp);
    virtual void Visit(const divExpression* exp);
    void clear();
    int getResult() const;
private:
    int value_;
};

#endif  // CALCVISITOR_HEADER_GUARD__
// Copyright(C) 2004 Yoshinori Oota All rights reserved.
#include "calcVisitor.h"
#include "terminalExpression.h"
#include "addExpression.h"
#include "subExpression.h"
#include "mulExpression.h"
#include "divExpression.h"

calcVisitor::calcVisitor() : value_(0) { }
calcVisitor::~calcVisitor() { }

void calcVisitor::Visit(const terminalExpression* exp) {
    value_ = exp->getValue();
}
void calcVisitor::Visit(const addExpression* exp) {
    const Expression* lhs = exp->getLeftHandSide();
    lhs->accept(this);
    int value = value_;
    const Expression* rhs = exp->getRightHandSide();
    rhs->accept(this);
    value_ += value;
}
void calcVisitor::Visit(const subExpression* exp) {
    const Expression* lhs = exp->getLeftHandSide();
    lhs->accept(this);
    int value = value_;
    const Expression* rhs = exp->getRightHandSide();
    rhs->accept(this);
    value_ = value - value_;
}
void calcVisitor::Visit(const mulExpression* exp) {
    const Expression* lhs = exp->getLeftHandSide();
    lhs->accept(this);
    int value = value_;
    const Expression* rhs = exp->getRightHandSide();
    rhs->accept(this);
    value_ = value * value_;
}
void calcVisitor::Visit(const divExpression* exp) {
    const Expression* lhs = exp->getLeftHandSide();
    lhs->accept(this);
    int value = value_;
    const Expression* rhs = exp->getRightHandSide();
    rhs->accept(this);
    value_ = value / value_;
}
void calcVisitor::clear() {
    value_ = 0;
}
int calcVisitor::getResult() const {
    return value_;
}

【補足】
・C++版では、本来はコピーコンストラクタ、代入演算子を定義すべきですが、コードが冗長になるため省いています。

ご意見、ご感想はこちらまで。

Copyright(C) 2000-2004 Yoshinori Oota All rights reserved.

本ホームページのリンクは自由です。複製、転載される場合は、必ず著者までご連絡をください。