Помогите с разбором лог-файла (ANTLR3)

Мне нужно небольшое руководство по написанию грамматики для разбора лог-файла игры Aion. Я решил использовать 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'; 

Так что мне нужен пример того, как разобрать это без ошибок для строк без метки времени.

Спасибо!


person Unknown    schedule 12.05.2010    source источник


Ответы (2)


Никто не будет смеяться. На самом деле, вы неплохо поработали для первого раза. Конечно, есть куда расти! :)

Сначала несколько замечаний: вы можете отрицать только отдельные символы. Поскольку ваше правило NL может состоять из двух символов, вы не можете отменить его. Кроме того, при отрицании из правил (правил) синтаксического анализатора вы не отрицаете отдельные символы, но вы отрицаете правила лексера. Это может показаться немного запутанным, поэтому позвольте мне пояснить на примере. Возьмем комбинированную (парсер и лексер) грамматику T:

grammar T;

// parser rule
foo
  :  ~A
  ;

// lexer rules
A
  :  'a'
  ;

B
  :  'b'
  ;

C
  :  'c'
  ;

Как видите, я отрицаю правило лексера A в правиле парсера foo. Правило 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 в правилах лексера означает, что токены не создаются из этих правил: они используются только в других правилах лексера. Таким образом, лексер создаст только два разных типа токенов: DataLine и TextLine.

person Bart Kiers    schedule 12.05.2010
comment
Это, кажется, работает довольно хорошо, и это просто и ясно. Конечно, я кое-что изменю, чтобы делать то, что мне нужно.. Спасибо! - person Unknown; 12.05.2010

Пытаясь сохранить вашу грамматику как можно ближе, вот как я смог заставить ее работать на основе ввода примера. Поскольку пробелы передаются парсеру из лексера, я переместил все ваши токены из парсера в настоящие правила лексера. Основное изменение заключается в том, чтобы просто добавить еще один параметр строки, а затем попытаться привести его в соответствие с вашими тестовыми данными, а не с другими хорошими данными. Я также предположил, что пустая строка должна быть отброшена, как вы можете сказать по правилу. Итак, вот что я смог заставить работать:

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

Надеюсь, это поможет вам, удачи.

person WayneH    schedule 12.05.2010