代码之家  ›  专栏  ›  技术社区  ›  Unknown

解析日志文件的帮助(ANTLR3)

  •  5
  • Unknown  · 技术社区  · 16 年前

    我需要一个小的指导,在编写语法来解析游戏的日志文件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.
    

    这是我到目前为止写的(我是这些东西的初学者,所以请不要笑: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'; 
    

    谢谢!

    2 回复  |  直到 16 年前
        1
  •  5
  •   Bart Kiers    16 年前

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

    先说几句:你只能否定单个字符。自从你的 NL 规则可能由两个字符组成,你不能否定它。另外,当从解析器规则中取反时,不会取反单个字符,而是取反lexer规则。这听起来可能有点混乱,所以让我用一个例子来澄清。取组合的(解析器和;(词汇)语法 T :

    grammar T;
    
    // parser rule
    foo
      :  ~A
      ;
    
    // lexer rules
    A
      :  'a'
      ;
    
    B
      :  'b'
      ;
    
    C
      :  'c'
      ;
    

    A 中的lexer规则 foo '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 lexer规则的一部分意味着没有从这些规则创建令牌:它们只在其他lexer规则中使用。因此lexer只会创建两种不同类型的令牌: DataLine 的和 TextLine

        2
  •  2
  •   WayneH    16 年前

    为了尽可能地保持语法,下面是我如何根据示例输入让它工作的。因为空白是从lexer传递给解析器的,所以我确实将解析器中的所有标记移到了实际的lexer规则中。主要的变化实际上只是添加了另一个行选项,然后试图让它与您的测试数据匹配,而不是与实际的其他好数据匹配,我还假设应该丢弃一个空行,正如您可以从规则中看出的那样。所以我能做的就是:

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

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

    推荐文章