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