2010-05-12 15 views
5

Ho bisogno di una piccola guida per scrivere una grammatica per analizzare il file di registro del gioco Aion. Ho deciso di usare Antlr3 (perché sembra essere uno strumento in grado di fare il lavoro e ho capito che è bene per me imparare a usarlo). Tuttavia, ho incontrato problemi perché il file di registro non è esattamente strutturato.Aiuto per l'analisi di un file di registro (ANTLR3)

Il file di registro che ho bisogno di analizzare sguardi come quello qui sotto:

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. 

Come potete vedere, la maggior parte delle linee di iniziare con un timestamp, ma ci sono delle eccezioni. Quello che mi piacerebbe fare in Antlr3 è scrivere un parser che usa solo le righe che iniziano con il timestamp mentre si scartano in silenzio le altre.

questo è quello che ho scritto finora (sono un principiante con queste cose quindi si prega di non ridere: 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'; 

Quindi quello che mi serve è un esempio di come analizzare questo senza generare errori per le righe senza il timestamp.

Grazie!

risposta

5

Nessuno ride. In effetti, hai fatto un ottimo lavoro per un primo tentativo. Certo, c'è spazio per migliorare! :)

Prima alcune osservazioni: è possibile negare solo i singoli caratteri. Poiché la tua regola può essere composta da due caratteri, non puoi negarla. Inoltre, quando si annulla la regola del parser, non si annullano i singoli caratteri, ma si annullano le regole del lexer. Questo può sembrare un po 'confuso quindi lasciatemi chiarire con un esempio. Prendere la combinata (parser & lexer) grammatica T:

grammar T; 

// parser rule 
foo 
    : ~A 
    ; 

// lexer rules 
A 
    : 'a' 
    ; 

B 
    : 'b' 
    ; 

C 
    : 'c' 
    ; 

Come potete vedere, sto negando la A lexer-regola nel parser-regola foo. La regola foo ora non corrisponde a qualsiasi carattere tranne lo 'a', ma corrisponde a qualsiasi regola del lexer tranne A. In altre parole, corrisponderà solo a un carattere 'b' o 'c'.

Inoltre, non c'è bisogno di mettere:

options { 
    language = Java; 
} 

nella tua grammatica: la destinazione predefinita è Java (non fa male a lasciarlo lì ovviamente).

Ora, nella tua grammatica, puoi già fare una distinzione tra le righe data e text nella grammatica lessico. Ecco un possibile modo per farlo:

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

nota che la parte fragment nelle regole lexer significa che non i token sono stati creati da tali norme: sono utilizzati solo in altre regole lexer. Quindi il lexer creerà solo due diversi tipi di token: DataLine e TextLine.

+0

Questo sembra funzionare piuttosto bene ed è semplice e chiaro. Ofcouse, cambierò alcune cose per fare tutto ciò che mi serve per farlo .. Grazie! – Unknown

+0

@ user188106, prego. –

2

Cercando di mantenere la grammatica il più vicino possibile, ecco come sono riuscito a farlo funzionare in base all'input di esempio. Poiché lo spazio bianco viene passato al parser dal lexer, ho spostato tutti i token dal parser in regole di lexer reali.Il cambiamento principale è in realtà solo aggiungendo un'altra opzione di linea e quindi cercando di farlo corrispondere ai dati del test e non agli altri buoni dati effettivi, ho anche ipotizzato che una riga vuota dovrebbe essere scartata come si può vedere dalla regola. Ecco cosa sono riuscito a ottenere:

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 : '/' | '\\'; 

Speriamo che questo ti aiuti, buona fortuna.

+0

Grazie anche per il tuo impegno! – Unknown

Problemi correlati