Antlr4를 사용하여 자바로 코드 변환기를 작성하려고하는데, 지금까지 문법 파트로 큰 성공을 거두었습니다. 그러나 나는 지금 내 머리가 파스 트리 데이터 구조 주위에 내 마음을 감싸고 내 머리를 두드리는 소리를 내 입력이 파싱 된 후 작업해야합니다.Antlr4에서 컨텍스트 데이터 구조 이해하기
방문자 템플릿을 사용하여 구문 분석 트리를 탐색하려고합니다. 내 혼란의 요점을 보여주는 예를 보여 드리겠습니다.
내 문법 :
grammar pqlc;
// Lexer
//Schlüsselwörter
EXISTS: 'exists';
REDUCE: 'reduce';
QUERY: 'query';
INT: 'int';
DOUBLE: 'double';
CONST: 'const';
STDVECTOR: 'std::vector';
STDMAP: 'std::map';
STDSET: 'std::set';
C_EXPR: 'c_expr';
INTEGER_LITERAL : (DIGIT)+ ;
fragment DIGIT: '0'..'9';
DOUBLE_LITERAL : DIGIT '.' DIGIT+;
LPAREN : '(';
RPAREN : ')';
LBRACK : '[';
RBRACK : ']';
DOT : '.';
EQUAL : '==';
LE : '<=';
GE : '>=';
GT : '>';
LT : '<';
ADD : '+';
MUL : '*';
AND : '&&';
COLON : ':';
IDENTIFIER : JavaLetter JavaLetterOrDigit*;
fragment JavaLetter : [a-zA-Z$_]; // these are the "java letters" below 0xFF
fragment JavaLetterOrDigit : [a-zA-Z0-9$_]; // these are the "java letters or digits" below 0xFF
WS
: [ \t\r\n\u000C]+ -> skip
;
COMMENT
: '/*' .*? '*/' -> skip
;
LINE_COMMENT
: '//' ~[\r\n]* -> skip
;
// Parser
//start_rule: query;
query :
quant_expr
| qexpr+
| IDENTIFIER // order IDENTIFIER and qexpr+?
| numeral
| c_expr //TODO
;
c_type : INT | DOUBLE | CONST;
bin_op: AND | ADD | MUL | EQUAL | LT | GT | LE| GE;
qexpr:
LPAREN query RPAREN bin_op_query?
// query bin_op query
| IDENTIFIER bin_op_query? // copied from query to resolve left recursion problem
| numeral bin_op_query? //^
| quant_expr bin_op_query? //^
|c_expr bin_op_query?
// query.find(query)
| IDENTIFIER find_query? // copied from query to resolve left recursion problem
| numeral find_query? //^
| quant_expr find_query?
|c_expr find_query?
// query[query]
| IDENTIFIER array_query? // copied from query to resolve left recursion problem
| numeral array_query? //^
| quant_expr array_query?
|c_expr array_query?
// | qexpr bin_op_query // bad, resolved by quexpr+ in query
;
bin_op_query: bin_op query bin_op_query?; // resolve left recursion of query bin_op query
find_query: '.''find' LPAREN query RPAREN;
array_query: LBRACK query RBRACK;
quant_expr:
quant id ':' query
| QUERY LPAREN match RPAREN ':' query
| REDUCE LPAREN IDENTIFIER RPAREN id ':' query
;
match:
STDVECTOR LBRACK id RBRACK EQUAL cm
| STDMAP '.''find' LPAREN cm RPAREN EQUAL cm
| STDSET '.''find' LPAREN cm RPAREN
;
cm:
IDENTIFIER
| numeral
| c_expr //TODO
;
quant :
EXISTS;
id :
c_type IDENTIFIER
| IDENTIFIER // Nach Seite 2 aber nicht der Übersicht. Laut übersicht id -> aber dann wäre Regel 1 ohne +
;
numeral :
INTEGER_LITERAL
| DOUBLE_LITERAL
;
c_expr:
C_EXPR
;
이제
의 다음과 같은 문자열을 구문 분석 할 수 :
하는의 내 방문자가 visitQexpr(@NotNull pqlcParser.QexprContext ctx)
에 가정 해 봅시다 :
double x: x >= c_expr
가 시각적으로 나는이 나무를 얻을 수 있습니다를 루틴이 분기 Qexpr (x bin_op_query)에 도달하면 루틴을 호출합니다.
제 질문은, 왼쪽 자식 노드 ("x"는 트리)가 종단 노드이고, 구체적으로 "IDENTIFIER"라고 어떻게 말할 수 있습니까? 터미널 노드는 규칙이 아니기 때문에 방문 규칙이 없습니다. ctx.getChild(0)
에는 RuleIndex가 없습니다. 나는 내가 터미널에 있는지 아닌지를 확인하기 위해 그것을 사용할 수 있다고 생각하지만, IDENTIFIER 또는 다른 종류의 터미널 토큰에 있었는지 여전히 알려주지 않습니다. 어떻게 든 그 차이를 말할 수 있어야합니다.
나는 더 많은 질문을했지만 그 시간에 나는 그들을 잊어 버린 설명을 쓰려고했다. < 미리 감사드립니다.
id :
c_type labelA = IDENTIFIER
| labelB = IDENTIFIER
;
또한 다른 방문을 생성 할 수 있습니다 :
id :
c_type IDENTIFIER #idType1 //choose more appropriate names!
| IDENTIFIER #idType2
;
이 생성됩니다
일반적인 해결책은 구문 분석 트리를 방문하는 대신 [AST (추상 구문 트리)] (https://en.wikipedia.org/wiki/Abstract_syntax_tree)를 방문하는 것입니다. 그러나이 기능은 [제거되었습니다 since antlr4] (http://stackoverflow.com/questions/15823333/how-can-i-build-anast-using-antlr4).어쩌면 당신은'symbol table '(https://en.wikipedia.org/wiki/Symbol_table)의 왕을 사용하여'x'가 식별자인지 알 수 있습니다 :) 행운을 빌어 요! – NiziL
Child의 payLoad()를 가져 오는 경우 토큰 ID가 거기에 있습니다 (다른 것들 사이에 있음). 정보가 데이터 구조에 저장되므로 쉽게 액세스 할 수있는 적절한 방법이 있어야합니다. ctx에는 ctx.IDENTIFIER()와 같은 다른 터미널 노드의 기능이 있지만 정확히 무엇을하고 있는지 말할 수는 없습니다. 터미널 노드와 텍스트가없는 경우 ctx.IDENTIFIER()의 반환 값이 null 인 것으로 보입니다. 그것은 나에게 말하지 않을 것입니다/어떤/어떤 아이들이 있다면 말단 노드입니다. 전체 데이터 구조가 매우 혼란 스럽습니다. \ – user2323596
서브 루/터미널 노드가 일부 컨텍스트에서 방문 중인지 알고 싶을 때 대개이 subrule/terminal이 null인지 (방문하지 않음) 또는 null이 아닌지 확인합니다. (방문 중). 그러나 나는 또한 당신이 원하는 것을 얻을 수있는 좋고 깨끗한 방법보다는 오히려 해키를 발견합니다. – schauk11erd