4

我正在尝试使用Rascal MPL设计一个岛语法,但遇到了一个问题:

在 SDF 中实现 Island Grammar 时,一种非常常见的方法是使用 {avoid} 属性定义“包罗万象”的水生产。如果其他产品适用,这会阻止解析器使用此产品。这允许指定一个默认行为,该行为可以被其他产品覆盖而不会产生歧义。一个非常简单的例子是:

context free syntax
    Chunk*         -> Input
    Water          -> Chunk
lexical syntax
    ~[\t\n\ ]+   -> Water {avoid}  // avoid the Water production

我尝试用 Rascal MPL 重现这种行为。我的目标是创建一个岛语法,将所有条件预处理器指令收集到一段 C/C++ 代码中,并使用 Water 生成跳过其余输入。

layout LAYOUT = [\t\n\ ];
lexical WATER = ![\t\n\ ]+;

start syntax Program = Line*;       // program consists of lines

syntax Line = ConditionalDirective  // preprocessor directives
            > WATER;                // catch-all option

syntax ConditionalDirective = "#ifdef" 
                            | "#ifndef"
                            | "#if"
                            | "#elif";

我试图通过使用 ">" 运算符为ConditionalDirective产生更高的优先级来创建 {avoid} 效果,但这显然不起作用。解析树仍然包含歧义。

#ifdef asd

例如,如果我解析上面的代码,我会得到一个如下所示的解析树:

歧义解析树

据我从Rascal Documentation可以看出,在我的情况下,使用“优先级”运算符可能不是要走的路,但我看不到任何其他可能性。不过我认为有一种方法,因为 rascal 的作者明确指出,每个 SDF 语法都可以转换为 rascal 语法。

有没有办法用流氓 MPL 重现 SDF {avoid} 功能?或者是否有可能以某种方式过滤解析森林,重新应用优先级?

4

1 回答 1

2

简短的回答:避免在 sdf2 中是一个后解析过滤器。在 rascal 中,您可以自己定义这些,请参阅https://github.com/cwi-swat/rascal/blob/master/src/org/rascalmpl/library/lang/sdf2/filters/PreferAvoid.rsc以了解模仿 sdf2 的示例在不忽略注入链且不计数的情况下避免行为。您可以在语法中导入它并使用 @avoid 和 @prefer 标记,就像在 sdf2 中一样,或者编写您自己的过滤器。

警告:避免通常不足以定义 sdf2 中的水行为,也不是流氓。原因是水可以变得比它的替代品更长。Prefer 和 Avoid 只能在子句长度相等的备选方案中进行选择。在流氓中处理水的一种可靠但缓慢的方法是在每个替代方案中计算它,并选择水较少的衍生物。

偏好和避免的另一个问题是使用会开始干扰,尤其是在计算它们时。这可以通过专门针对特定非终结符甚至替代规则的过滤器来避免流氓行为。

另一种选择是使用 \ 和 ! 消歧运算符。请参阅手册。但是,我相信解析后过滤选项是目前处理孤岛语法的最佳方法,因为您可以控制正在发生的事情。

于 2013-11-17T13:21:51.197 回答