Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
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
Archives
Today
Total
관리 메뉴

개발자되기 프로젝트

해석 - Interpreter Pattern 본문

Java/디자인 패턴

해석 - Interpreter Pattern

Seung__ 2021. 11. 17. 23:03

1. Interpreter Pattern ??


  • 문법 규칙을 클래스로 표현
  • 간단한 프로그램을 해석하기 위한 패턴

 

 

2. 의도와 동기


  • 간단한 언어에 대한 해석기 패턴
  • 각 문법에 대한 해석을 클래스로 표현
  • 미니언어나 게임에서 사용하는 간단한 언어에 대한 문법 해석기

 

 

3. Class diagram


 

 

4. 객체 협력 (collaborations)


  • AbstractExpress

추상 구문 트리에 속한 모든 노드가 가져야할 공통의 메서드 interpte() 오퍼레이션 선언

  • TerminalExpression

터미널 기호에 대한 해석방법을 구현

  • NonterminalExpression

재귀적으로 호출되어 다른 AbstractExpression으로 구문을 패쓰하게 된다.

  • Context

번역기에 대한 포괄적인 정보 포함

  • Client

Syntax를 실제로 정의하고 추상 구문 트리를 생성하고 각 문법 표현 클래스의 interpret() 메서드를 호출한다.

 

 

5. 중요한 결론 (consequence)


  • 문법의 변경이나 확장이 쉽고
  • 문법의 구현이 쉽다.
  • 복잡한 문법은 사용할 수 없다.

 

 

6. 예제


자동차를 움직이는 간단한 언어

프로그램의 시작: program 프로그램의 끝 : end

자동차를 움직이게 하는 명령들 go : 앞으로 1미터 전진 right : 오른쪽으로 향함 left : 왼쪽으로 향함 repeat : 반복명령

 

 

  • Grammar 정의

  • 각 노드의 역할이 있고, 문법에 따라 객체를 통해 문법에 맞는지 확인하는 기능을 수행.
public class Context {
    private StringTokenizer tokenizer;
    private String currentToken;

    public Context(String text){
        tokenizer = new StringTokenizer(text);
        nextToken();
    }

    public String nextToken() {

        if (tokenizer.hasMoreTokens()){
            currentToken = tokenizer.nextToken();
        }
        else {
            currentToken = null;
        }

        return currentToken;
    }

    public String getCurrentToken(){
        return currentToken;
    }

    public void skipToken(String token) throws ParseException{
        if (!token.equals(currentToken)){
            throw new ParseException("Warning: " + token + " is excepted, but " + currentToken + "is found");
        }
        nextToken();
    }

    public int currentNumber() throws ParseException{
        int number = 0;

        try{
            number = Integer.parseInt(currentToken);
        }catch (NumberFormatException e){
            throw new ParseException("Warning: " + e);
        }

        return number;

    }
}
public abstract class Node {

    public abstract void parse(Context context) throws ParseException;

}
  • ProgramNode는 "program"을 제외한 나머지 부분은 CommanListNode에 parsing을 넘김.
/**
 * <program> ::=program <command list>
 */
public class ProgramNode extends Node{

    private Node commandListNode;

    @Override
    public void parse(Context context) throws ParseException {
        context.skipToken("program");
        commandListNode = new CommandListNode();
        commandListNode.parse(context);
    }

    @Override
    public String toString() {
        return "[program " + commandListNode + "]";

    }
}
  • CommandListNode는 command를 리스트로 가지고 있고, end로 끝난다.
    • CommandNode가 있을 경우 CommandNode 객체로 넘겨서 처리함.
    • 계속 돌면서 CommandListNode에서 end를 만나는 경우 루프 나감.
    • 그 외에는 계속 깊게? 들어가면서 parsing 계속"
/**
 *  <command list> ::= <command>* end
 */

import java.util.Vector;

public class CommandListNode extends Node {

    private Vector list= new Vector();

    @Override
    public void parse(Context context) throws ParseException {
        while (true){
            if (context.getCurrentToken() == null){
                throw new ParseException("Missing end");
            }
            else if (context.getCurrentToken().equals("end")){
                context.skipToken("end");
                break;
            }
            else {
                Node commandNode = new CommandNode();
                commandNode.parse(context);
                list.add(commandNode);
            }

        }
    }

    @Override
    public String toString() {
        return "" + list;
    }
}
  • CommandNode는 repeat command와 primitive command로 구성되어있음.
    • repeat command, primitive command객체로 넘겨서 처리함.
/**
 * <command> ::= <repeat command> | <primitive command>
 */

public class CommandNode extends Node {

    private Node node;

    @Override
    public void parse(Context context) throws ParseException {

        if(context.getCurrentToken().equals("repeat")){
            node = new RepeatCommandNode();
            node.parse(context);
        } else {
            node = new PrimitiveCommandNode();
            node.parse(context);
        }
    }

    @Override
    public String toString() {
        return node.toString();
    }
}
  • RepeatCommandNode는 "repeat"와 number, command List로 구성되어 있음.
    • repeat는 넘기고, number와 commentListNode를 parsing한다.
    • CommandListNode 객체로 넘겨서 처리한다.
    • 계속 돌면서 CommandListNode에서 end를 만나는 경우 루프 나감.
/**
 * <repeat command> ::= repeat <number> <command list>
 */

public class RepeatCommandNode extends Node {

    private int number;
    private Node commandListNode;

    @Override
    public void parse(Context context) throws ParseException {
        context.skipToken("repeat");
        number = context.currentNumber();
        context.nextToken();
        commandListNode = new CommandListNode();
        commandListNode.parse(context);
    }

    @Override
    public String toString() {
        return "[repeat " + number + " " + commandListNode + "]";
    }
}
  • primitive command는 go, righr, left로 구성됨.
/**
 * <primitive command> ::= go | right | left
 */
public class PrimitiveCommandNode extends Node {

    private String name;

    @Override
    public void parse(Context context) throws ParseException {
        name = context.getCurrentToken();
        context.skipToken(name);
        if (!name.equals("go") && !name.equals("right") && !name.equals("left")){
            throw new ParseException(name + "is undefined");
        }

    }

    @Override
    public String toString() {
        return name;
    }
}
public class Main {

    public static void main(String[] args) {
        BufferedReader reader;

        {
            try {
                reader = new BufferedReader(new FileReader("program.txt"));
                String text;

                while ((text = reader.readLine()) != null){
                    System.out.println("text = \"" + text + "\"");
                    Node node = new ProgramNode();
                    node.parse(new Context(text));
                    System.out.println("node = " + node);
                }
            } catch (IOException | ParseException e) {
                e.printStackTrace();
            }
        }
    }
}
text = "program end"
node = [program []]
text = "program go end"
node = [program [go]]
text = "program go right go right go right go right end"
node = [program [go, right, go, right, go, right, go, right]]
text = "program repeat 4 go right end end"
node = [program [[repeat 4 [go, right]]]]
text = "program repeat 4 repeat 3 go right go left end right end end"
node = [program [[repeat 4 [[repeat 3 [go, right, go, left]], right]]]]

 

 

7. GitHub :211117 Interpreter Pattern


 

GitHub - bsh6463/designPattern

Contribute to bsh6463/designPattern development by creating an account on GitHub.

github.com

 

Comments