2010-05-12 4 views
5

게임 Aion의 로그 파일을 구문 분석하기위한 문법을 ​​작성하는 데 필요한 약간의 지침이 필요합니다. 나는 Antlr3을 사용하여 결정했습니다 (왜냐하면 그것은 일을 할 수있는 도구 인 것 같아서 그것을 사용하는 법을 배우는 것이 좋다고 생각했기 때문입니다). 그러나 로그 파일이 정확하게 구조화되지 않았기 때문에 문제가 발생했습니다.로그 파일 (ANTLR3) 구문 분석에 대한 도움말

나는 아래와 같은 모습을 구문 분석 할 필요가 로그 파일 : 당신이 볼 수 있듯이

2010.04.27 22:32:22 : You changed the connection status to Online. 
2010.04.27 22:32:22 : You changed the group to the Solo state. 
2010.04.27 22:32:22 : You changed the group to the Solo state. 
2010.04.27 22:32:28 : Legion Message: www.xxxxxxxx.com (forum) 



ventrillo: 19x.xxx.xxx.xxx 

Port: 3712 

Pass: xxxx (blabla) 

4/27/2010 7:47 PM 
2010.04.27 22:32:28 : You have item(s) left to settle in the sales agency window. 

는 대부분의 라인은 타임 스탬프와 함께 시작하지만 예외가 있습니다. Antlr3에서 내가하고 싶은 것은 조용히 다른 것들을 버리는 동안 timestamp로 시작하는 라인만을 사용하는 파서를 작성하는 것입니다.

grammar Antlr; 

options { 
    language = Java; 
} 

logfile: line* EOF; 

line : dataline | textline; 

dataline: timestamp WS ':' WS text NL ; 
textline: ~DIG text NL; 

timestamp: four_dig '.' two_dig '.' two_dig WS two_dig ':' two_dig ':' two_dig ; 

four_dig: DIG DIG DIG DIG; 
two_dig: DIG DIG; 

text: ~NL+; 

/* Whitespace */ 
WS: (' ' | '\t')+; 

/* New line goes to \r\n or EOF */ 
NL: '\r'? '\n' ; 

/* Digits */ 
DIG : '0'..'9'; 

그래서 내가 필요한 것은이 구문 분석하는 방법의 예입니다

내가 (D 내가 그렇게 웃지 마십시오 이러한 것들로 초보자 해요) 지금까지 작성한 것입니다 시간 소인이없는 행에 오류를 생성하지 않습니다.

감사합니다.

답변

5

아무도 웃지 않을 것입니다. 사실, 당신은 첫 번째 시도에서 꽤 좋은 직장을 가졌습니다. 물론 개선의 여지가 있습니다! :)

처음 몇 가지주의 사항 : 하나의 문자 만 무효화 할 수 있습니다. NL 규칙은 두 개의 문자로 구성 될 수 있으므로이를 부정 할 수 없습니다. 또한 파서 규칙 내에서 무효화 할 때 단일 문자를 무효화하지 않지만 렉서 규칙을 무효화합니다. 이것은 다소 혼란 스러울 수 있으므로 예를 들어 명확히 설명하겠습니다. 당신이 볼 수 있듯이

grammar T; 

// parser rule 
foo 
    : ~A 
    ; 

// lexer rules 
A 
    : 'a' 
    ; 

B 
    : 'b' 
    ; 

C 
    : 'c' 
    ; 

, 내가 foo 파서 규칙에서 A 렉서 규칙을 부정 해요 : 결합 (파서 & 렉서) 문법 T을 가져 가라. foo 규칙은 이제 이 아니며'a'을 제외한 모든 문자와 일치하지만 A을 제외한 모든 렉서 규칙과 일치합니다. 즉, 'b' 또는 'c' 문자와 일치합니다.

또한, 당신은 넣어 필요가 없습니다

options { 
    language = Java; 
} 

을 문법에 : 기본 목표는 자바 인 (거기 과정에 둘 다치게하지 않습니다).

이제 문법에서 렉서 문법에 data-와 text- 라인을 구분할 수 있습니다. 여기에 그렇게 할 수있는 가능한 방법이다 : 렉서 규칙에 fragment 부분이 더 토큰이 그 규칙에서 만들어지지되고 있다는 것을 의미

logfile 
    : line+ 
    ; 

line 
    : dataline 
    | textline 
    ; 

dataline 
    : DataLine 
    ; 

textline 
    : TextLine 
    ; 

DataLine 
    : TwoDigits TwoDigits '.' TwoDigits '.' TwoDigits Space+ TwoDigits ':' TwoDigits ':' TwoDigits Space+ ':' TextLine 
    ; 

TextLine 
    : ~('\r' | '\n')* (NewLine | EOF) 
    ; 

fragment 
NewLine 
    : '\r'? '\n' 
    | '\r' 
    ; 

fragment 
TwoDigits 
    : '0'..'9' '0'..'9' 
    ; 

fragment 
Space 
    : ' ' 
    | '\t' 
    ; 

하는 것으로 : 그들은 단지 다른 렉서 규칙에 사용됩니다. 따라서 렉서는 두 가지 유형의 토큰, 즉 DataLineTextLine을 생성합니다.

+0

이것은 꽤 잘 작동하는 것처럼 보입니다. 간단하고 명확합니다. Ofcouse, 내가 할 일이 무엇이든 바꿀거야 .. 고마워! – Unknown

+0

@ user188106, 언제든지 환영합니다. –

2

문법을 가능한 한 가깝게 지키려는 시도가 여기 예제 입력을 기반으로 작동하도록 만들었습니다. 공백 문자가 렉서에서 파서로 전달되기 때문에 필자는 파서의 모든 토큰을 실제 렉서 규칙으로 옮겼습니다.주요 변경 사항은 실제로 다른 라인 옵션을 추가 한 다음 테스트 데이터와 실제 기타 좋은 데이터가 일치하지 않도록하기 위해서입니다. 규칙에 의해 알 수 있듯이 빈 라인을 버려야한다고 가정했습니다. 그래서 내가 일할 수 있었던 것이 여기에 있습니다 :

logfile: line* EOF; 

//line : dataline | textline; 
line : dataline | textline | discardline; 

dataline: timestamp WS COLON WS text NL ; 
textline: ~DIG text NL; 

//"new" 
discardline: (WS)+ discardtext (text|DIG|PERIOD|COLON|SLASH|WS)* NL 
    | (WS)* NL; 
discardtext: (two_dig| DIG) WS* SLASH; 
// two_dig SLASH four_dig; 

timestamp: four_dig PERIOD two_dig PERIOD two_dig WS two_dig COLON two_dig COLON two_dig ; 

four_dig: DIG DIG DIG DIG; 
two_dig: DIG DIG; 

//Following is very different 
text: CHAR (CHAR|DIG|PERIOD|COLON|SLASH|WS)*; 

/* Whitespace */ 
WS: (' ' | '\t')+ ; 

/* New line goes to \r\n or EOF */ 
NL: '\r'? '\n' ; 

/* Digits */ 
DIG : '0'..'9'; 

//new lexer rules 
CHAR : 'a'..'z'|'A'..'Z'; 
PERIOD : '.'; 
COLON : ':'; 
SLASH : '/' | '\\'; 

잘하면, 행운을 빕니다.

+0

노력해 주셔서 감사합니다. – Unknown