在antlr4词法分析器中,如何获得一个将所有剩余"单词"作为未知标记捕获的规则?

mda*_*kin 10 antlr lexer antlr4

我有一个antlr4 lexer语法.它有很多单词规则,但我也希望它为任何其他规则无法匹配的单词创建一个Unknown标记.我有这样的事情:

Whitespace : [ \t\n\r]+ -> skip;
Punctuation : [.,:;?!];
// Other rules here
Unknown : .+? ; 
Run Code Online (Sandbox Code Playgroud)

现在生成的匹配器卡子"〜"为未知的,但对于输入创建3"〜"未知令牌"~~~",而不是一个单一的"~~~"令牌.我该怎么做才能告诉lexer为未知的连续字符生成单词标记.我也试过"未知:.;" 和"未知:.+;" 没有结果.

编辑:在当前的antlr版本.+?现在抓住剩余的单词,所以这个问题似乎得到了解决.

Bar*_*ers 11

.+?词法分析器规则的末尾将始终匹配单个字符.但是.+会尽可能多地消耗,这在ANTLR v3的规则结束时是非法的(v4可能也是如此).

你可以做的只是匹配一个char,并在解析器中"粘合"这些:

unknowns : Unknown+ ; 

...

Unknown  : . ; 
Run Code Online (Sandbox Code Playgroud)

编辑

...但我只有一个词法分析器,没有解析器......

啊,我明白了.然后你可以覆盖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     : . ; 
Run Code Online (Sandbox Code Playgroud)

运行它:

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

将打印:

Unknown         'foo'
Punctuation     ','
Unknown         'bar'
Punctuation     '.'
Punctuation     '.'
Punctuation     '.'

  • @mdakin,查看我的 **EDIT**。 (2认同)