【问题标题】:Is this reserve declaration hard to understand or defective?这份储备声明是否难以理解或有缺陷?
【发布时间】:2018-06-21 16:58:38
【问题描述】:

我在使用保留(反斜杠)声明进行优先级消歧时遇到了问题。下面是一个独立的例子。生产“Ipv4Address”是“Domain0”的严格子集。但是,在解析 URL 时,您希望点分四组地址的处理方式与域名不同,因此您希望将“Domain0”分成两部分; 'Domain1' 是这两个部分之一。但是,包含的测试套件在 't3()' 处失败,其中 'Domain1' 接受 IP 地址,看起来应该排除它。

这是保留声明的问题,还是当前版本的 Rascal 存在缺陷?我目前在 0.10.x 不稳定分支上,根据建议查看是否解决了不同的问题(与导师)。我没有检查过 stable 分支,因为同时安装它们意味着并行 Eclipse 环境,我没有这样做的动力。

module grammar_test

import ParseTree;

syntax Domain0 = { Subdomain '.' }+;
syntax Domain1 = Domain0 \ IPv4Address ;
lexical Subdomain = [0-9A-Za-z]+ | [0-9A-Za-z]+'-'[a-zA-Z0-9\-]*[a-zA-Z0-9] ;
lexical IPv4Address = DecimalOctet '.' DecimalOctet '.' DecimalOctet '.' DecimalOctet ; 
lexical DecimalOctet = [0-9] | [1-9][0-9] | '1'[0-9][0-9] | '2'[0-4][0-9] | '25'[0-5] ;

test bool t1()
{
    return parseAccept(#IPv4Address, "192.168.0.1");
}   

test bool t2()
{
    return parseAccept(#Domain0, "192.168.0.1");
}   

test bool t3()
{
    return parseReject(#Domain1, "192.168.0.1");
}   

bool parseAccept( type[&T<:Tree] begin, str input )
{
    try
    {
        parse(begin, input, allowAmbiguity=false);
    }
    catch ParseError(loc _):
    {
        return false;
    }
    return true;
}

bool parseReject( type[&T<:Tree] begin, str input )
{
    try
    {
        parse(begin, input, allowAmbiguity=false);
    }
    catch ParseError(loc _):
    {
        return true;
    }
    return false;
}

此示例已从较大的代码中删减。我第一次遇到更大范围的错误。使用规则“IPv4Address | Domain1”引发了一个歧义异常,我追查到“Domain1”接受不应该接受的东西的行为。奇怪的是,“IPv4Address > Domain1”也引发了歧义,但我猜这与目前的孤立示例具有相同的根本原因。

【问题讨论】:

    标签: rascal


    【解决方案1】:

    目前,关键字保留的差异运算符仅在右侧是一种有限语言时才能正常工作` 用于某些效果。

    对于其他类型的非终端,解析器只是生成,但\ 约束无效。你写了Domain0 \ IPv4Address,而 IPv3Address 不符合上述假设。

    (我们应该添加一个警告或者生成一个可以实现语言差异的完整语义的解析器;但那是另一次了)。

    诚然,如此强大的差分运算符可用于表达非终结符之间的某种偏好顺序。唉。

    可能的(草图)解决方案:

    • 阶段两遍解决方案:使用更通用的Subdomain 语法解析输入,然后在单遍中进行模式和匹配重写所有四倍到 IPv4Address
    • 最大咀嚼解决方案:使用跟随限制调整语法以实现 IPv4Address 的急切行为,例如 {Subdomain !&gt;&gt; [.][0-9] "."}+ 或其他徒劳的东西。

    【讨论】:

    • 感谢您的快速回答。我想说的第一件事是记录差异运算符的实际限制。另外,如果不满足第二个参数的先决条件,我建议使用错误而不是警告;这不是解析错误,而是限制错误。无论如何,我宁愿根本没有解析器,也不愿有一个我可能会相信与我编写的语法相匹配的解析器。
    • 还有。我有点惊讶没有实现差异,因为 GLR 已经有了所需的机制。在识别“A\B”时,您始终可以拆分(就像解析歧义一样)。然后,如果 A 先承认(接受或拒绝),则使用其结果并丢弃 B。如果 B 先接受,则丢弃 A 和 B 并拒绝 A\B。如果 B 先拒绝,则丢弃 B。这种方法不需要任何静态语法分析。现在,话虽如此,似乎将其与递归规则结合使用可能会导致指数行为。添加某种递归限制可能是谨慎的。
    • glr 算法(我知道并实现的 sdf2 算法)确实更通用,但由于减少调度和顺序依赖性而以非常微妙的方式被破坏。所以对于流氓,我们首先选择了一个更简单的解决方案,它有明显的局限性,但没有意外的漏洞。 GLL 算法将是可行的,但只能通过选择深度优先而不是面包优先探索。不过,这有一些令人讨厌的记忆效应。所以陪审团还在外面。我希望在不久的将来使用 Afroozeh 和 Izmaylova 的数据依赖 GLL 的更优雅的解决方案。可以在“booleaN 语法”中找到灵感。
    • 关于文档的观点和快速失败!我们将更改静态检查器(正在开发中),顺便说一句,它还可以预测语法中的许多常见歧义。
    • 顺便说一句,Visser 针对 sdf2 拒绝规则的 glr 解决方案不是指数级的。最坏的情况是多项式。所以这很好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-25
    • 2017-08-30
    • 2023-01-12
    • 2019-08-04
    • 1970-01-01
    • 2022-12-13
    • 1970-01-01
    相关资源
    最近更新 更多