我正在尝试使用 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 语法。
有没有办法用 rascal MPL 重现 SDF {avoid} 功能?或者是否有可能以某种方式过滤解析森林,重新应用优先级?
最佳答案
简短回答:避免在 sdf2 中是一个解析后过滤器。在 rascal 中,您可以自己定义这些,请参阅 https://github.com/cwi-swat/rascal/blob/master/src/org/rascalmpl/library/lang/sdf2/filters/PreferAvoid.rsc例如,模仿 sdf2 避免行为而不忽略注入(inject)链且不计数。您可以将它导入您的语法并使用 @avoid 和 @prefer 标签,就像在 sdf2 中一样,或者编写您自己的过滤器。
警告:避免通常不足以定义 sdf2 中的水行为,它也不是在 rascal 中。原因是水可以变得比它的替代品更长。 Prefer 和 avoid 只能在 subsentence 长度方面等长度的备选方案之间进行选择。 在 rascal 中处理水的一种可靠但缓慢的方法是在每个替代方案中计算它并选择用水较少的推导。
prefer 和 avoid 的另一个问题是使用会开始干扰,尤其是当它们被计算在内时。在 rascal 中,可以通过针对特定非终结符或什至替代规则专门化过滤器来避免这种情况。
另一种选择是使用\和 !消歧运算符。请参阅手册。然而,总而言之 我相信解析后过滤选项是目前处理孤岛语法的最佳方式,因为您可以控制正在发生的事情。
关于c++ - 如何在 rascal MPL 中使用 SDF 的 {avoid},我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20029710/