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

誰も笑うつもりはありません。実際、あなたは最初の試みでかなり良い仕事をしました。もちろん、改善の余地はあります!:)

最初のいくつかの注意:あなたは単一の文字だけを否定することができます。ルールは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です(もちろん、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。これらは、他のレクサールールでのみ使用されます。したがって、レクサーは2つの異なるタイプのトークンのみを作成します: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 に答える