티스토리 뷰
* 이클립스에서 비지터 사용하기
- 기본적으로 비지터 생성되지 않음
(no-visitor 옵션)
- 프로젝트->우클릭>Properties > ANTLR > Enable project specific setting
(프로젝트에 ANTLR 설정 적용 안 된 경우)
- 비지터 켜기 위해선
> tool Generate parse tree visitors 체크하면
ANTLR 실행시 -visitor 옵션 주는것과 같음
- 참고: External... 로 실행할 때 -no-visitor 만 빼면 되는게 아니라, -visitor 를 꼭 넣어줘야 함
* 컴파일 하면 (문법 이름이 Abc 라면)
AbcBaseVisitor
AbcVisitor 가 생김
* 사용 방법
AbcVisitor 를 상속한 후
visit얼터너티브이름(얼터너티브이름Context) 이란 메서드를 오버라이딩 함.
* ctx.토큰이름() or ctx.룰이름() 사용 가능
visitXX() return 값이 해당 얼터너티브의 치환값이 됨.
* 참고 : 비지터는 서브트리 탐색 위해서 명시적으로 visit() 를 호출해야 한다
안 하면 누락
(물론 AbcVisitor 에 다 구현되어 있긴 함)
[ Visitor 선언 및 활용 ]
* 예제 문법 Hello
grammar Hello;
r : 'hello' myId ;
myId : ID;
ID : [a-z]+ ;
WS : [ \t\r\n]+ -> skip ;
기본 문법에서 myId 룰 추가함.. (child 테스트 하려고..)
* Visitor 클래스 선언 코드
문법 'Hello'를 선언했으므로
인터페이스 HelloVisiitor 와
이를 구현한 클래스 HelloBaseVisitor 가 기본으로 생성된다
이를 상속한 HelloMyVisitor 를 정의해보면....
public class HelloMyVisitor extends HelloBaseVisitor<Integer> {
@Override public Integer visitR(@NotNull HelloParser.RContext ctx) {
return visitChildren(ctx);
}
@Override public Integer visitMyId(@NotNull HelloParser.MyIdContext ctx) {
System.out.println("visitMyId() " + ctx.getText());
return visitChildren(ctx);
}
}
반환값 Integer 는 임의로 지정한것.. (사용자가 임의 지정할 수 있음)
HelloBaseVisitor 를 상속하면 따로 구현할 메서드는 없지만,
visitr룰이름() 메서드를 오버라이드할 수 있음.
* Visitor 사용 코드
// 파스 트리 생성
String s = "hello abc";
HelloLexer lex = new HelloLexer(CharStreams.fromString(s));
CommonTokenStream cts = new CommonTokenStream(lex);
HelloParser par = new HelloParser(cts);
ParseTree pt = par.r();
// 비지터 호출
HelloMyVisitor v = new HelloMyVisitor();
v.visit(pt);
- 리스너에서도 있었던 Lexer 선언, Parser 선언, ParserTree 생성 그대로 있음.
다만 리스너는 ParseTreeWalker 에 리스너 넣어서 사용했지만,
비지터는 직접 v.visit(ParserTree) 로 직접 호출함
- 리스너와 동일하게 HelloParser.룰이름Context 를 파라메터로 받음.
- 참고 : Visitor 가 직접 파싱하는게 아님.. 이미 생성된 ParseTree 를 순회하는 역할만 함
- visit룰() 메서드 언제나 visitChildren(ctx) 메서드를 호출하도록 되어있음.
안 하면 하위노드를 순회하지 않음.
순회하지 않지만 ctx.getChild() 로 값을 가져올 순 있음.
(이미 파싱은 되어있고, 순회만 하는거니까.)
- 리스너는 enter룰이름() , exit룰이름() 이 존재하지만
비지터는 visit룰이름() 하나만 있음.
- 만약 "hello 123" 이란 텍스트를 집어넣는다면
ID 규칙이 <영어 소문자> 로만 정의 되어있어서 문법에 맞지 않음.
<룰 myId> 는 방문할 수 없을 것 같지만
visit() 호출 => visit(R) 호출 -> visitMyId() 호출은 정상적으로 일어남.
다만 해당 노드의 값은 <어휘 ID>의 규칙을 만족하지 못해서 <missing ID> 로 표시됨.
- 정리하면 visit룰이름() 메서드는 노드 방문시 호출되며,
visitChild() 을 직접 호출해줘야 하위 노드를 방문할 수 있고,
문법을 틀려 파싱에 실패한 노드도 호출됨.
[[ 기타
* 왜 기본값이 no-visitor 일까?
j/ ??
'SW개발 > ANTLR' 카테고리의 다른 글
Listener , Visitor 비교 (0) | 2018.07.27 |
---|---|
ANTLRInputsream DEPRECATED (0) | 2018.06.16 |
ANTLR Hello 예제 (0) | 2018.05.21 |
antlr ide Package 지정 (0) | 2017.09.25 |
ANTLR - IDE 설치, 프로젝트시작 / Eclipse (0) | 2017.09.21 |