0

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

typeA idS
{
    paramX = value
    typeB idT
    {
        paramY = value
    }       
}

有大量不同的规则来验证哪些参数和子类型对某种类型的块有效。

我想添加功能以允许将特殊块类型放置在任何现有块或一组名称/值对周围。

BLOCK
{
    typeA idS
    {
        BLOCK
        {
            paramX = value
        }
        BLOCK
        {       
            typeB idT
            {
                paramY = value
            }
        }       
    }
 }

有没有一种方法可以创建一个允许其内部的任何内容的块,而不必专门为每个现有类型添加 BLOCK 支持,并且不会丢失解析器检查子参数/类型对给定父项是否有效

我试过使用通配符,贪婪和非贪婪无济于事。

block: BLOCK '{' (options {greedy=false;} : .* ) '}'

其他答案表明句法谓词可以解决它,但我无法弄清楚如何使用它们(链接到任何在线资源将不胜感激)。

有没有办法在不触及所有其他规则的情况下做到这一点?(希望不需要很多 BLOCK_subtypes 来保持父/子检查的完整性)。我担心可读性和维护麻烦。

谢谢

4

1 回答 1

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 还是裸语句。

于 2013-01-29T22:56:16.207 回答