2010-05-12 15 views
5

Necesito una pequeña guía para escribir una gramática para analizar el archivo de registro del juego Aion. Decidí usar Antlr3 (porque parece ser una herramienta que puede hacer el trabajo y pensé que era bueno para mí aprender a usarlo). Sin embargo, me he encontrado con problemas porque el archivo de registro no está exactamente estructurado.Ayuda con el análisis de un archivo de registro (ANTLR3)

El archivo de registro que necesito para analizar miradas como la siguiente:

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. 

Como se puede ver, la mayoría de las líneas de empezar con una marca de tiempo, pero hay excepciones. Lo que me gustaría hacer en Antlr3 es escribir un analizador sintáctico que usa solo las líneas que comienzan con la marca de tiempo y descarta silenciosamente a las demás.

Esto es lo que he escrito hasta ahora (soy un principiante con estas cosas así que por favor no se rían: 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'; 

Así que lo que necesito es un ejemplo de cómo analizar esta sin generar errores para líneas sin la marca de tiempo.

Gracias!

Respuesta

5

Nadie se va a reír. De hecho, hiciste un muy buen trabajo en un primer intento. Por supuesto, ¡hay margen de mejora! :)

Primero algunas observaciones: solo puede negar caracteres individuales. Como su regla NL puede consistir en dos caracteres, no puede negarla. Además, al negar desde su regla (s) de analizador, no niega los caracteres individuales, pero está negando las reglas lexer. Esto puede sonar un poco confuso, así que déjame aclararlo con un ejemplo. Tome el combinado (analizador léxico &) gramática T:

grammar T; 

// parser rule 
foo 
    : ~A 
    ; 

// lexer rules 
A 
    : 'a' 
    ; 

B 
    : 'b' 
    ; 

C 
    : 'c' 
    ; 

Como se puede ver, estoy negando la A léxico-regla en el analizador en reglas foo. La regla foo hace ahora no coincide con cualquier carácter excepto el 'a', pero coincide con cualquier regla lexer excepto A. En otras palabras, solo coincidirá con un carácter 'b' o 'c'.

Además, no es necesario poner:

options { 
    language = Java; 
} 

en su gramática: el destino predeterminado es Java (que no hace daño a dejarlo ahí, por supuesto).

Ahora, en su gramática, ya puede hacer una distinción entre data - y text -líneas en su gramática del lexer. He aquí una posible forma de hacerlo:

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

Tenga en cuenta que la parte fragment en las reglas lexer significa que no hay fichas están siendo creados a partir de esas reglas: sólo se usan en otras normas analizadoras. Por lo tanto, el lexer solo creará dos tipos de tokens diferentes: DataLine y TextLine.

+0

Esto parece funcionar bastante bien y es simple y claro. Por supuesto, voy a cambiar algunas cosas para hacer lo que sea que necesite ... ¡Gracias! – Unknown

+0

@ user188106, de nada. –

2

Tratando de mantener su gramática lo más cerca posible, he aquí cómo pude hacer que funcione en función de la entrada de ejemplo. Debido a que el espacio en blanco se está transfiriendo al analizador desde el lector lexer, moví todos los tokens desde el analizador sintáctico a las reglas reales de lectura y escritura.El cambio principal es simplemente agregar otra opción de línea y luego tratar de que coincida con los datos de prueba y no con los otros datos buenos reales, también asumí que una línea en blanco debería descartarse como puede ver la regla. Así que esto es lo que pude hacer funcionar:

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

Espero que eso te ayude, buena suerte.

+0

¡También gracias por su esfuerzo! – Unknown

Cuestiones relacionadas