我正在尝试使用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} 功能?或者是否有可能以某种方式过滤解析森林,重新应用优先级?