在ANTLR4中使用token令牌

Use token tokens in ANTLR4

我 运行 遇到了 ANTLR 的问题,我想知道这样的情况在 ANTLR 中是否可以接受。我在下面准备了一个非常简单的例子。

grammar test;

test
    : statement*
    ;

statement
    : s1
    | s2
    ;

s1
    : 'OK' INT
    ;

s2
    : 'ABC' US_INT
    ;

INT
    : S_INT
    | US_INT
    ;

S_INT
   : [+-] [0-9]+
   ;

US_INT
    : [0-9]+
    ;

OK 5 一切正常,但 ABC 5 出现以下错误:

line 1:4 mismatched input '5' expecting US_INT

我是 运行 grun-tokens 选项,我在这里 INT 而不是 US_INT

[@1,4:4='5',<INT>,1:4]

这让我想知道在 ANTLR 中是否可能出现这种情况。以前,我尝试过重新排序令牌,将 US_INT 移出 INT、片段和其他一些东西,但效果不佳。唯一的变化是 OK 5 停止工作而 ABC 5 开始工作。我希望这两种情况都能正常工作。

您面临的问题非常简单:5 可以同时匹配:US_INT(因为它包含 US_INT)和 S_INT 本身。但是,只要 INT 被声明为高于 US_INT,词法分析器就会将 5 解析为 INT.

要解决它,我建议您将 INT 从词法分析器标记移动到解析器规则,如下所示:

grammar test;

test
    : statement*
    ;

statement
    : s1
    | s2
    ;

s1
    : 'OK' int_stmt
    ;

s2
    : 'ABC' US_INT
    ;
    
int_stmt
    : S_INT | US_INT
    ;

S_INT
   : [+-] [0-9]+
   ;

US_INT
    : [0-9]+
    ;

如果你想逃避,在这种情况下,从lexing的优先级,你可以在Tunnel Grammar Studio中使用这个ABNF解析器语法,它根本没有这个问题:

test         = *statement
statement    = s-ok / s-abc
s-ok         = "OK" 1*ws int
s-abc        = "ABC" 1*ws unsigned-int
int          = signed-int / unsigned-int
signed-int   = ('+' / '-') unsigned-int 
unsigned-int = 1*('0'-'9')
ws           = %x20 / %x9 / %xA / %xD

这是 case-insensitive 匹配的情况,如 ABNF (RFC 5234) 中所定义。您还可以将每个字符串的区分大小写或不区分大小写的匹配分别明确定义为 %s"ABC"%i"ABC" (RFC 7405)。当你开始有更多的语句时,一些字符串会开始重叠,这时你可以在词法分析器语法中自己制作关键字:

keyword      = %s"OK" / %s"OK2"

并在解析器语法中执行:

s-ok         = {keyword, %s"OK"} 1*ws int 
s-ok-2       = {keyword, %s"OK2"} 1*ws int 1*ws int 
s-ok-any     = {keyword} 1*ws int *(ws 0*1 int)

请注意,最后一条规则将允许您在整数和任何关键字之间添加任何白色 space。

*我开发了 Tunnel Grammar Studio。语法很简单,所以演示可能就足够了。