14

私はantlr4レクサー文法を持っています。単語には多くのルールがありますが、他のルールでは一致しない単語に対して不明なトークンを作成することも必要です。私はこのようなものを持っています:

Whitespace : [ \t\n\r]+ -> skip;
Punctuation : [.,:;?!];
// Other rules here
Unknown : .+? ; 

生成されたマッチャーは「〜」を不明としてキャッチしますが、単一の「~~~」トークンではなく、入力「~~~」に対して3つの「〜」不明なトークンを作成します。不明な連続文字の単語トークンを生成するようにレクサーに指示するにはどうすればよいですか。「不明:。;」も試してみました および「不明:。+;」結果はありません。

編集:現在のantlrバージョンでは。+?残りの単語をキャッチするようになったため、この問題は解決されたようです。

4

2 に答える 2

14

.+?レクサールールの最後では、常に1文字に一致します。しかし.+、可能な限り消費します。これは、ANTLR v3(v4もおそらく同様)のルールの最後では違法でした。

できることは、1つの文字を一致させ、パーサーでこれらを「接着」することです。

unknowns : Unknown+ ; 

...

Unknown  : . ; 

編集

...しかし、私にはレクサーしかなく、パーサーはありません...

ああ、なるほど。nextToken()次に、メソッドをオーバーライドできます。

lexer grammar Lex;

@members {

  public static void main(String[] args) {
    Lex lex = new Lex(new ANTLRInputStream("foo, bar...\n"));
    for(Token t : lex.getAllTokens()) {
      System.out.printf("%-15s '%s'\n", tokenNames[t.getType()], t.getText());
    }
  }

  private java.util.Queue<Token> queue = new java.util.LinkedList<Token>();

  @Override
  public Token nextToken() {    

    if(!queue.isEmpty()) {
      return queue.poll();
    }

    Token next = super.nextToken();

    if(next.getType() != Unknown) {
      return next;
    }

    StringBuilder builder = new StringBuilder();

    while(next.getType() == Unknown) {
      builder.append(next.getText());
      next = super.nextToken();
    }

    // The `next` will _not_ be an Unknown-token, store it in 
    // the queue to return the next time!
    queue.offer(next);

    return new CommonToken(Unknown, builder.toString());
  }
}

Whitespace  : [ \t\n\r]+ -> skip ;
Punctuation : [.,:;?!] ;
Unknown     : . ; 

それを実行する:

java -cp antlr-4.0-complete.jar org.antlr.v4.Tool Lex.g4
javac -cp antlr-4.0-complete.jar * .java
java -cp。:antlr-4.0-complete.jar Lex

印刷されます:

不明な「foo」
句読点'、'
不明な「バー」
句読点'。'
句読点'。'
句読点'。'
于 2013-02-05T19:23:14.810 に答える
3

受け入れられた回答は機能しますが、Javaでのみ機能します。

提供されたJavaコードをC#ANTLRランタイムで使用するために変換しました。他の誰かがそれを必要とするなら...ここに行きます!

@members {
private IToken _NextToken = null;
public override IToken NextToken()
{
    if(_NextToken != null)
    {
        var token = _NextToken;
        _NextToken = null;
        return token;
    }

    var next = base.NextToken();
    if(next.Type != UNKNOWN)
    {
        return next;
    }

    var originalToken = next;
    var lastToken = next;
    var builder = new StringBuilder();
    while(next.Type == UNKNOWN)
    {
        lastToken = next;
        builder.Append(next.Text);
        next = base.NextToken();
    }
    _NextToken = next;
    return new CommonToken(
        originalToken
    )
    {
        Text = builder.ToString(),
        StopIndex = lastToken.Column
    };
}
}
于 2020-01-18T00:16:53.980 に答える