首页 > 解决方案 > Antlr4 相邻令牌优先级

问题描述

我在构建复杂的语法时遇到了问题。一个宠物语法来说明它如下:

grammar test;

start: (r1 | r2 | .)*
r1: A B
r2: B C

// A B C are tokens

当出现以下输入时:

ABC

解析树如下所示:

start
|   \
r1   C
| \
A  B

但我真正想要的是它看起来像这样:

start
|   \
A   r2
    | \
    B  C

我已经尝试重新排序规则并添加<assoc=right>,但除了删除规则之外似乎没有任何效果r1,这是不正确的,因为我期望AB并且BC是有效的输入。我错过了什么?

编辑

上面的问题描述似乎过于简化了实际问题,所以我将提供更多细节:

r3: rA r4          // prefers rA(classB classC) over (rA classB)classC
r4: classB? classC // also used elsewhere other than r3

rA: // rules to build A subtree, ends with classB? in 'some' cases
classB: B1 | B2 | ... | Bm
classC: C1 | C2 | ... | Cn

我发现以下“类型”有效:

r3: rA Bx classC | ...

但以下没有:

r3: <assoc=right> rA r4 | ... // still builds (rA classB)classC

我想知道是否有一种方法可以正确构建树,同时能够利用r4及其相关代码(并且避免为所有实例添加另外 m 行B)?

PS。rA是昂贵的,所以像上面那样扩展B令牌r3会给狗带来性能。

标签: antlr4

解决方案


我在这里看到的问题是您告诉解析器生成您不想要的解析树。如果你不想要它,那么不要指定应该产生它的语法。

与 Mike Cargal 提出的类似,我认为真正的解决方案是更明确地指定您希望在最后看到的内容。这里有一些效果很好的东西(使用你最初的问题描述和 MikeC 的测试输入):

parser grammar testparser;

options {
    tokenVocab = testlexer;
}

start: (A r2 | r1 | .)*? EOF;
r1: A B;
r2: B C;
lexer grammar testlexer;

A: 'A';
B: 'B';
C: 'C';

WHITE_SPACE: [ \u000B\t\r\n] -> skip ;
OTHER: .;

通过输入AB!C2,我得到了这个解析三:

在此处输入图像描述

省略C此更改为:

在此处输入图像描述

主要变化是您通过添加r2 alt 并将其放在首位来专门化规则以BC在他们自己的子解析树中进行匹配。A

笔记

将该单曲A移至 r2 规则将打破这一点,因为然后您告诉解析器创建一个包含其中的子树ABC(您不想要的)。


推荐阅读