2012-04-13 3 views
5

필자는 antlr 렉서 규칙의 이상한 부작용이 있으며 필자는이를 증명할 (거의) 최소한의 작업 예제를 만들었다. 예를 들어, 문자열 [0..1]과 일치시키고 싶습니다. 그러나 문법을 디버깅 할 때 구문 분석기에 도달하는 토큰 스트림은 [..1] 만 포함합니다. 첫 번째 정수는 얼마나 많은 자릿수가 포함되어 있어도 항상 소비되며 어떻게되는지에 대한 단서가 없습니다. 내가 FLOAT 규칙을 제거하면 모든 것이 잘되므로 실수는 그 규칙의 어딘가에 있다고 생각합니다. 그러나 그것은 전혀 일치하지 않아야합니다. [0..1] 나는 전혀 의아해합니다.ANTLR 렉서 규칙은 일치하지 않아도 문자를 소비합니까?

내가 잘못했을지도 모를 포인터에 대해 기뻐할 것입니다. 이건 내 예입니다

grammar min; 
options{ 
language = Java; 
output = AST; 
ASTLabelType=CommonTree; 
backtrack = true; 
} 
tokens { 
    DECLARATION; 
} 

declaration : LBRACEVAR a=INTEGER DDOTS b=INTEGER RBRACEVAR -> ^(DECLARATION $a $b); 

EXP : 'e' | 'E'; 
LBRACEVAR: '['; 
RBRACEVAR: ']'; 
DOT: '.'; 
DDOTS: '..'; 

FLOAT 
    : INTEGER DOT POS_INTEGER 
    | INTEGER DOT POS_INTEGER EXP INTEGER 
    | INTEGER EXP INTEGER 
    ; 

INTEGER : POS_INTEGER | NEG_INTEGER; 
fragment NEG_INTEGER : ('-') POS_INTEGER; 
fragment POS_INTEGER : NUMBER+; 
fragment NUMBER: ('0'..'9'); 

답변

6

'0'는 렉서에 의해 삭제되며, 다음과 같은 오류가 생성됩니다

렉서는 '0.'가 발생하면, 그것은 FLOAT 토큰을 만들려고하기 때문입니다
line 1:3 no viable alternative at character '.' 
line 1:2 extraneous input '..' expecting INTEGER 

, 그러나 할 수 없다. '0.'과 일치하는 다른 규칙이 없기 때문에 오류가 발생하고 '0'을 버리고 DOT 토큰을 만듭니다.

이것은 ANTLR의 렉서의 작동 방식을 단순히 : 그것은 DDOTS 뒤에 INTEGER에 맞게 철수하지 않을 것이다 (backtrack=true는 규칙을 파서에만 적용됩니다!).

FLOAT 규칙의 내부에서, 당신은 이중 '.' 앞서있을 때, 당신은 대신 INTEGER 토큰을 생성 있는지 확인해야합니다. 단 하나의 문자가 '.' 다음에 숫자 (('.' DIGIT)=> 부분)가 오는 경우에만 구문 술어 (('..')=> 부분)를 추가하고 FLOAT 토큰을 생성하여이를 수행 할 수 있습니다. 다음 데모를 참조하십시오.

declaration 
: LBRACEVAR INTEGER DDOTS INTEGER RBRACEVAR 
; 

LBRACEVAR : '['; 
RBRACEVAR : ']'; 
DOT  : '.'; 
DDOTS  : '..'; 

INTEGER 
: DIGIT+ 
; 

FLOAT 
: DIGIT+ (('.' DIGIT)=> '.' DIGIT+ EXP? 
      | ('..')=>  {$type=INTEGER;} // change the token here 
      |    EXP 
     ) 
; 

fragment EXP : ('e' | 'E') DIGIT+; 
fragment DIGIT : ('0'..'9'); 
+0

예기치 않은 문제가 발생했습니다. 포괄적 인 예제를 주셔서 감사합니다. 지금까지 모든 것을 실행하고 있습니다 :-) – Lichtblitz

+0

@Lichtblitz, 천만에요, 네, 토큰 화'..' (INT-와 FLOAT- 토큰과 함께)는 까다 롭습니다. ! :) –