如何在流氓MPL中使用SDF的{avoid}

时间:2013-11-17 10:42:01

标签: c++ grammar context-free-grammar rascal parse-forest

我正在尝试使用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

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

ambiguous parse tree

据我所知Rascal Documentation,使用“优先级” - 操作员可能不是我的理由,但我没有看到任何其他可能性。我假设有一种方法,因为流氓的作者清楚地表明每个SDF语法都可以转换为流氓语法。

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

1 个答案:

答案 0 :(得分: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中定义水行为,它也不是流氓。原因是水比其替代品更长。首选和避免只能在子句长度方面选择相等长度的替代方案。 在流氓中处理水的一种可靠但缓慢的方法是在每种替代方案中计算它并选择用较少水的衍生物。

偏好和避免的另一个问题是使用会开始干扰,特别是当它们被计算时。通过专门针对特定非终结符甚至替代规则的过滤器,可以避免这种情况。

另一种选择是使用\和!解除歧视的经营者。请参阅手册。然而,全部和所有 我相信post parse过滤选项目前是处理岛语法的最佳方式,因为你可以控制正在发生的事情。