在antlr4 lexer中,如何有一个规则来捕获所有剩余的;字;作为未知标记?

在antlr4 lexer中,如何有一个规则来捕获所有剩余的;字;作为未知标记?,antlr,lexer,antlr4,Antlr,Lexer,Antlr4,我有一个antlr4词法语法。它有许多单词规则,但我也希望它为任何其他规则无法匹配的单词创建未知标记。我有这样的想法: Whitespace : [ \t\n\r]+ -> skip; Punctuation : [.,:;?!]; // Other rules here Unknown : .+? ; 现在生成的matcher将“~”捕获为未知,但为输入“~~~”创建3个“~”未知标记,而不是单个“~~~”标记。我应该如何告诉lexer为未知的连续字符生成单词标记。我还尝试了“未知:

我有一个antlr4词法语法。它有许多单词规则,但我也希望它为任何其他规则无法匹配的单词创建未知标记。我有这样的想法:

Whitespace : [ \t\n\r]+ -> skip;
Punctuation : [.,:;?!];
// Other rules here
Unknown : .+? ; 
现在生成的matcher将“~”捕获为未知,但为输入“~~~”创建3个“~”未知标记,而不是单个“~~~”标记。我应该如何告诉lexer为未知的连续字符生成单词标记。我还尝试了“未知:.;”和“未知:.+;”,但没有结果


编辑:在当前antlr版本中?现在捕获剩余的单词,所以这个问题似乎得到了解决。

+?
在lexer规则的末尾将始终匹配单个字符。但是
+
将消耗尽可能多的资源,这在ANTLR v3(可能也是v4)中的规则末尾是非法的

您可以做的只是匹配一个字符,并在解析器中将它们“粘合”在一起:

unknowns : Unknown+ ; 

...

Unknown  : . ; 
编辑 。。。但我只有一个lexer,没有解析器

啊,我明白了。然后可以重写
nextToken()
方法:

lexer语法Lex;
@成员{
公共静态void main(字符串[]args){
Lex-Lex=new-Lex(新的antlInputStream(“foo,bar…\n”));
对于(令牌t:lex.getAllTokens()){
System.out.printf(“%-15s'%s'\n”,标记名[t.getType()],t.getText());
}
}
private java.util.Queue Queue=new java.util.LinkedList();
@凌驾
公共令牌nextToken(){
如果(!queue.isEmpty()){
返回queue.poll();
}
令牌next=super.nextToken();
if(next.getType()!=未知){
下一步返回;
}
StringBuilder=新的StringBuilder();
while(next.getType()==未知){
append(next.getText());
next=super.nextToken();
}
//“下一个”将不是未知标记,请将其存储在
//下一次返回的队列!
排队。报价(下一个);
返回新的CommonToken(未知,builder.toString());
}
}
空白:[\t\n\r]+->跳过;
标点符号:[,:;?!];
未知:;
运行它:

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 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 '.' 未知的“foo” 标点符号“,” 未知的“酒吧” 标点符号“.” 标点符号“.”
标点符号“.”公认的答案有效,但它只适用于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
    };
}
}

谢谢,但我只有一个lexer,没有解析器,我用它来标记NLP工具的文本。我们想要的是,对于lexer无法识别为令牌的任何内容,都有一个未知或无法识别的令牌。也许我可以截取这些未知字符标记并连接自己。@mdakin,签出我的编辑。这适用于我给出的有限示例,但现在我明白我的问题更深,实际上不容易解决。如果我有另一条规则,比如:“word:[a-zA-Z]+;”,Lexer会将它标记为:“~a~a”为“~”:未知的“a”:单词“~”:未知的“a”:单词。原因是,我跳过了空格,所以我没有单词开始或结束的上下文。但不管怎样,你的回答仍然帮助我了解了lexer的工作原理。为了后代:我刚刚在ANTLR 4.7中用
创建了一个lexer规则,并且它工作了(使用IntellJ IDEA插件中的解释器)。根据下面@CAD97的评论,这在ANTLR 4.7中是有效的?捕捉单词而不是单个字符。