2014-06-12 2 views
5

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 
     ; 
이제

의 다음과 같은 문자열을 구문 분석 할 수 : tree

하는의 내 방문자가 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 
    ; 

이 생성됩니다

+0

일반적인 해결책은 구문 분석 트리를 방문하는 대신 [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

+0

Child의 payLoad()를 가져 오는 경우 토큰 ID가 거기에 있습니다 (다른 것들 사이에 있음). 정보가 데이터 구조에 저장되므로 쉽게 액세스 할 수있는 적절한 방법이 있어야합니다. ctx에는 ctx.IDENTIFIER()와 같은 다른 터미널 노드의 기능이 있지만 정확히 무엇을하고 있는지 말할 수는 없습니다. 터미널 노드와 텍스트가없는 경우 ctx.IDENTIFIER()의 반환 값이 null 인 것으로 보입니다. 그것은 나에게 말하지 않을 것입니다/어떤/어떤 아이들이 있다면 말단 노드입니다. 전체 데이터 구조가 매우 혼란 스럽습니다. \ – user2323596

+1

서브 루/터미널 노드가 일부 컨텍스트에서 방문 중인지 알고 싶을 때 대개이 subrule/terminal이 null인지 (방문하지 않음) 또는 null이 아닌지 확인합니다. (방문 중). 그러나 나는 또한 당신이 원하는 것을 얻을 수있는 좋고 깨끗한 방법보다는 오히려 해키를 발견합니다. – schauk11erd

답변

3

당신은 그들이 주변 환경에 존재하는지 확인/토큰에 레이블을 추가하고 액세스 할 수 있습니다 두 가지 대안에 대한 다른 방문자와 나는 id에 대한 방문자가 호출되지 않을 것이라고 가정합니다.

는 그래도 다음과 같은 접근 방식을 선호 :

id : 
     typeDef 
    | otherId 
    ; 
typeDef: c_type IDENTIFIER; 
otherId : IDENTIFIER ; 

이가 더 많이 입력 시스템입니다. 하지만 당신은 매우 구체적으로 노드를 방문 할 수 있습니다. 내가 사용하는 엄지 손가락 규칙 :

  1. 모든 대안이 구문 분석 규칙 일 때만 사용하십시오.
  2. 각 토큰을 파서 규칙 (예 : otherId)으로 감싸서 "더 많은 의미"를 부여하십시오.
  3. 토큰이 (예 : ;과 같이) 중요하지 않으므로 구문 분석 트리에 구문 분석 규칙과 토큰을 섞어도 괜찮습니다.