Interpreter パターン (文法規則をクラスで表現したものを用い構文解析し, その結果に基づき処理を実行していく機能を提供する)

[Interpreter] = 通訳

このパターンは, なんらかの文法規則をもった文書 (プログラム言語) を解析し, その結果得られた手順 (命令) に基づき処理を実行していくというパターン.

役割

  1. AbstractExpression (抽象的な表現):
[TerminalExpression] と [NonterminalExpression] に共通のインタフェース

定義する.

  1. TerminalExpression (終端となる表現):
終端を表現するクラス. 階層関係の末端 (構造木の葉) を表す.
  1. NonterminalExpression (非終端となる表現):
非終端を表現するクラス. 階層関係のノード (構造木の節) を表す.
  1. Context (文脈, 状況判断):
[Expression] (インタプリタ) が構文解析を行うための情報を提供する.
  1. Client (利用者):
[Interpreter] パターンを適用したクラスを利用し処理する.

クラス図

Interpreter パターンの図

_images/designpattern-interpreter011.gif

ソースコード

  1. AbstractExpression.java
1
2
3
public abstract class AbstractExpression{
    public abstract int Interpret(Context context);
}
  1. TerminalExpression.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public class TerminalExpression extends AbstractExpression{
    private String saveToken;
    
    public int Interpret(Context context){
	String token = context.getToken();
	saveToken = token;
	context.nextToken();
	return Integer.parseInt(token);
    }

    public String toString(){
	return saveToken;
    }
}
  1. NonterminalExpression.java
 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
import java.util.List;
import java.util.ArrayList;

public class NonterminalExpression extends AbstractExpression{
    private int resultValue;
    private String startTagPlus = "<%>";
    private String endTagPlus = "</%>";
    private List<AbstractExpression> list = new ArrayList<AbstractExpression>();

    public int Interpret(Context context){
	AbstractExpression childExpressions;
	context.nextToken();
	String token = "";
	while(!context.isEnd()){
	    token = context.getToken();
	    if(startTagPlus.equals(token)){
		childExpressions = new NonterminalExpression();
	    }else if(endTagPlus.equals(token)){
		context.nextToken();
		break;
	    }else{
		childExpressions = new TerminalExpression();
	    }
	    resultValue += childExpressions.Interpret(context);
	    list.add(childExpressions);
	}
	return resultValue;
    }

    public String toString(){
	return "+" + list.toString();
    }
}
  1. Context.java
 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
import java.util.StringTokenizer;

public class Context{
    private StringTokenizer tokens;
    private String currentToken;
    public Context(String source){
	tokens = new StringTokenizer(source);
	nextToken();
    }

    public String getToken(){
	return currentToken;
    }

    public void nextToken(){
	String token = null;
	if( !isEnd() ){
	    token = tokens.nextToken(); // 標準の .nextToken() を呼び出す
	}
	currentToken = token;
    }

    public boolean isEnd(){
	return !tokens.hasMoreElements();
    }
}
  1. Client.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
public class Client{
    public static void main(String[] args){
	
	/*
	  注意: 数字だけなので, 文字列になったら, エラーとなる.
	*/
	String source = "<%> 1 <%> 2 3 4 5 6 <%> 7 8 </%> 9 </%> 10 11 </%>";
	
	
	Context context = new Context(source);
	AbstractExpression expression = new NonterminalExpression();

	System.out.println( expression.Interpret(context) );
	System.out.println( expression.toString() );
    }
}

上記のプログラムの実行結果:

[wtopia Interpreter]$ java Client
66
+[1, +[2, 3, 4, 5, 6, +[7, 8], 9], 10, 11]