Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- SpringBoot
- AOP
- 알고리즘
- 스프링 핵심 기능
- kotlin
- jpa
- 인프런
- transaction
- Exception
- 스프링 핵심 원리
- Servlet
- 스프링
- QueryDSL
- JPQL
- 자바
- 김영한
- Greedy
- spring
- http
- Thymeleaf
- 그리디
- Android
- Spring Boot
- java
- pointcut
- Proxy
- db
- springdatajpa
- 백준
- JDBC
Archives
- Today
- Total
개발자되기 프로젝트
해석 - Interpreter Pattern 본문
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
'Java > 디자인 패턴' 카테고리의 다른 글
명령 - Command Pattern (0) | 2021.11.15 |
---|---|
낭비를 없애기 - Proxy Pattern (0) | 2021.11.15 |
낭비를 없애기 - Flyweight Pattern (0) | 2021.11.15 |
구조 안을 돌아다니며 처리 - Chain of Responsibility (0) | 2021.11.15 |
구조 안을 돌아다니며 처리 - Visitor (0) | 2021.11.13 |
Comments