在任意数量的其他规则中匹配规则

时间:2013-01-29 18:36:44

标签: parsing antlr predicate greedy

我正在研究一种使用大括号来识别层次结构的数据定义语言。

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来保持父/子检查完好无损)。我担心可读性和维护麻烦。

由于

1 个答案:

答案 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还是裸语句匹配。