ANTLR4 终端令牌消歧

ANTLR4 disambiguation of terminal tokens

这是我在 ANTLR4 中的语法:

grammar Hello;
r  : WORD ID ;
ID : [a-z]+ ;
WORD : [a-z]+ ;      
WS : [ \t\r\n]+ -> skip ;

当我输入如下内容时:

hello buddy

我收到以下错误消息:

line 1 missing WORD at 'hello'

但是,如果我更改

中的语法
grammar Hello;
r  : WORD ID ;
ID : [a-z]+ ;
WORD : [1-9]+ ;      
WS : [ \t\r\n]+ -> skip ;

现在WORD是一个数字,一切正常。 我强烈怀疑,因为在第一个语法中我们有两个具有相同正则表达式的终端节点,所以解析器不知道真实单词的对应关系。 那我想错了吗?如果不是,您将如何解决这个问题,让多个终端使用相同的正则表达式?

不能有两个匹配相同模式的终端。

如果您的语法实际上需要匹配两次 [a-z]+,则使用类似

的产生式
r   : WORD WORD ;

并且将在解析器/树遍历级别进行区分。

如果 WORDID 可以限制在一个固定列表中,您可以将所有可能的词声明为终结符,然后使用它们来定义,例如WORD 可以是什么。

where now WORD is a number, everything is ok.

不是真的 :

$ alias
alias grun='java org.antlr.v4.gui.TestRig'
$ grun Hello r -tokens data.txt 
[@0,0:4='hello',<ID>,1:0]
[@1,6:10='buddy',<ID>,1:6]
[@2,12:11='<EOF>',<EOF>,2:0]
line 1:0 missing WORD at 'hello'

当词法分析器可以将某些输入与两条规则匹配时,存在歧义,它会选择第一条规则。使用 hello buddy 输入,词法分析器生成两个 ID 标记

  • 使用第一种语法,因为它有歧义而且 ID 在前
  • 用第二种语法,输入只能通过ID WS ID匹配

您可以像这样在词法分析器规则中使用谓词消除歧义:

grammar Question;

/* Ambiguous input */

file
    : HELLO ID
    ;

HELLO
    : [a-z]+ {getText().equals("hello")}? ;
ID  : [a-z]+ ;
WS  : [ \t\r\n]+ -> skip ;

执行:

$ grun Question file -tokens data.txt 
[@0,0:4='hello',<HELLO>,1:0]
[@1,6:10='buddy',<ID>,1:6]
[@2,12:11='<EOF>',<EOF>,2:0]

The Definitive ANTLR Reference 中有关语义谓词的更多信息。