5

我需要一些指导来编写语法来解析游戏 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'; 

因此,我需要一个示例,说明如何在不为没有时间戳的行生成错误的情况下对其进行解析。

谢谢!

4

2 回答 2

5

没有人会笑。事实上,你第一次尝试就做得很好。当然,还有改进的余地!:)

首先是一些评论:您只能否定单个字符。由于您的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's 和TextLine's。

于 2010-05-12T14:37:25.023 回答
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 : '/' | '\\';

希望对你有帮助,祝你好运。

于 2010-05-12T15:06:12.727 回答