我正在研究一种使用大括号来识别层次结构的数据定义语言。
typeA idS
{
paramX = value
typeB idT
{
paramY = value
}
}
有许多不同的规则来验证params和子类型对某种类型的块有效。
我想添加一些功能,允许在任何现有块或一组名称/值对周围放置一个特殊的块类型。
BLOCK
{
typeA idS
{
BLOCK
{
paramX = value
}
BLOCK
{
typeB idT
{
paramY = value
}
}
}
}
有没有办法创建一个允许其中任何内容的块,而不必专门为每个现有类型添加BLOCK支持,并且不会丢失解析器检查子param /类型对给定父级是否有效
我尝试使用通配符,贪婪和非贪婪无济于事。
block: BLOCK '{' (options {greedy=false;} : .* ) '}'
其他答案表明语法谓词可以解决它,但我无法弄清楚如何使用它们(链接到任何在线来源将不胜感激)。
有没有办法在不触及所有其他规则的情况下执行此操作? (希望不需要很多BLOCK_subtypes来保持父/子检查完好无损)。我担心可读性和维护麻烦。
由于
答案 0 :(得分:0)
这似乎需要多次通过。
在第一遍中,您基本上只需解析块和数据而无需进行任何验证,例如
blockType: BLOCK OPEN_BRACE type CLOSE_BRACE -> (BLOCK type);
blockParam: BLOCK OPEN_BRACE param CLOSE_BRACE -> (BLOCK param);
type: blockType | (typeName idName OPEN_BRACE param CLOSE_BRACE ->
(TYPE typeName idName param));
param: blockParam | (paramName EQUALS value -> (PARAM paramName value));
这会产生一个AST,它将成为第二遍的输入。在那里,你需要像
这样的规则paramA: (PARAM paramNameA value) | (BLOCK paramA);
typeB: (TYPE typeNameB idNameB paramB) | (BLOCK typeB);
块结构会侵入您的所有规则,但它是以标准方式执行的。你甚至可以写一些东西来修改你的语法文件来添加它。
您可能还想使用预处理器。用特殊的,无效的字符串替换BLOCK {和匹配}的东西并不难写。那么每条规则的格式是BLOCK_START吗? BLOCK_END的东西?您应该能够添加操作以确保在没有结束的情况下无法启动,但如果预处理器正在工作(并拒绝实际的特殊文本),那么这是不可能的。
所有这些都可能比您想要的更具侵入性,但构造相当具有侵入性。
我假设额外的标签实际上触发了某种特殊处理。如果它们只是语法糖,则任一解决方案都是本地化的。预处理器只会删除BLOCK文本。 AST解决方案将生成相同的AST,无论它与BLOCK还是裸语句匹配。