2010-05-12 115 views
5

我需要一點點指導,寫一個語法來解析遊戲永恆之塔的日誌文件。我決定使用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中做的事情是編寫一個解析器,該解析器僅使用以時間戳開始的行,同時默默丟棄其他行。

這是我到目前爲止已經寫的(我用這些東西是初學者所以請不要笑:d)

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'; 

所以我需要的是如何分析這樣的一個例子不會爲沒有時間戳的行生成錯誤。

謝謝!

回答

5

沒有人會笑。事實上,你做了一個很好的工作,第一次嘗試。當然,還有改進的餘地! :)

首先一些說法:你只能否定單個字符。由於您的NL規則可能包含兩個字符,因此無法否定它。另外,當從你的解析器規則中否定時,你不會否定單個字符,但是你否定了詞法分析器規則。這聽起來有點令人困惑,所以讓我以一個例子來澄清。就拿合併(解析器&詞法分析器)語法T

grammar T; 

// parser rule 
foo 
    : ~A 
    ; 

// lexer rules 
A 
    : 'a' 
    ; 

B 
    : 'b' 
    ; 

C 
    : 'c' 
    ; 

正如你所看到的,我否定的foo解析器規則的A詞法規則。 foo規則現在不會而不是匹配除'a'以外的任何字符,但它匹配除A之外的任何詞法分析規則。換句話說,它只會匹配'b''c'字符。

而且,你不需要把:

options { 
    language = Java; 
} 

在你的語法:默認的目標就是Java(它不會傷害到離開它在那裏當然)。

現在,在您的語法中,您可以在您的詞法分析器語法中區分data - 和text - 行。這裏是一個可能的方式這樣做:

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' 
    ; 

注意,fragment部分在詞法規則意味着正在從這些規則不會創建令牌:它們只在其他詞法規則中使用。所以詞法分析器只會創建兩種不同類型的標記:DataLineTextLine

+0

這似乎工作得很好,它很簡單明瞭。 Ofcouse,我會改變一些東西來做我需要的東西。謝謝! – Unknown 2010-05-12 17:27:05

+0

@ user188106,不客氣。 – 2010-05-13 00:02:02

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 2010-05-12 17:24:59