为什么围绕作品的可选部分进行布局会导致歧义?

Why is layout around optional parts of a production causing ambiguity?

在Rascal中,为什么在一个产生式的可选部分位置有布局时,会出现歧义?例如。 "{ }"Start1 不明确,而它从以下语法中解析为 Start2,我希望它完全相同。

layout Layout                               = " "?;
start syntax Start1                         = "{" "c"? "}";
start syntax Start2                         = "{" "c" "}"
                                            | "{" "}";

此外,我想知道是否有另一种表示 Start2 而不重复 Start1 的方法,它不会引起同样的歧义。

显然这段代码没有大量重复,Start2 是一个不错的选择,但这只是一个例子。我正在处理一个语法,其中包含许多包含三个或四个可选部分的作品,在最后一种情况下,Start2 中显示的符号已经需要将作品的非可选部分复制 2^4=16 次,这确实在我看来很麻烦

在生成解析器之前,您的语法首先被扩展为与此类似的内容:

layout Layout                         = " "?;
syntax " "?                           =  | " ";
syntax Start1                         = "{" Layout "c"? Layout "}";
syntax "c"?                           =  | "c";
lexical " "                           = [\ ];
lexical "c"                           = [c];
lexical "{"                           = [{];
lexical "}"                           = [}];
syntax Start2                         = "{" Layout "c" Layout "}"
                                      | "{" Layout "}";
syntax start[Start1] = Layout Start1 Layout;
syntax start[Start2] = Layout Start2 Layout;

所以对于像{ }这样的输入(space在卷曲之间),space可以由Start1右侧的第一个Layout实例导出规则,或由 Layout 的第二个实例。由于解析器生成所有派生树,在这种情况下,解析是模棱两可可以这么说。

通常情况下,通过引入 贪婪 来解决歧义,使用如下限制:

layout Layout = " "? !>> " "

或(等价地)像这样:

layout Layout = " "? !>> [\ ]

限制作为对布局规则的约束:如果后面有 space,它不会派生任何东西(甚至不是空字符串)。这使得只有第一个推导有效,其中 space 进入 Start1 的第一个 Layout 实例。在这之后有 } 满足约束并且解析是明确的。