代码之家  ›  专栏  ›  技术社区  ›  eh9

无法用消歧规则解决的流氓歧义

  •  1
  • eh9  · 技术社区  · 6 年前

    我在努力消除歧义 the question I asked 几天前。在前一个问题中,语言实现中有一个未经记录的限制;我想知道这里是否也发生了类似的事情。

    测验 [tuvw]1 是否都抛出了歧义异常(顺便问一下:你如何捕捉这些异常?[编辑:回答].他们看起来都应该通过。请注意,它们必须明确无误才能通过。也不是优先权规则 Scheme 也不是保留规则 UnknownScheme[23] 似乎在消除模糊性。可能有一些我不理解的遵循规则的交互;这可能是另一个限制或缺陷。怎么了?

    我在不稳定的分支上。版本(来自eclipse):0.10.0.201806220838

    编辑。 我修改了示例代码,以便更清楚地强调正在发生的事情。我删除了一些多余的测试和运行正常的测试。我扩展了一些可能冗长的诊断。我把上面的说明改了。新的结果随之而来。

    看起来这里有两件事在起作用。 "http" 被双方(正确地)接受 KnownScheme UnknownScheme 在测试中 s1[ab] .它的行为好像 方案 只是不起作用,好像 > 被替换为 | 是的。

    在另一种情况下,测试 s1[cde] 失败了,但是 s1f 正在通过。这看起来更像是一个缺陷。很明显,可以保留一个关键字,但不能超过一个。由于各种各样的保留声明都失败了,所以当把它们放到一个替代方案中时会出现歧义也就不足为奇了。

    module ssce
    
    import analysis::grammars::Ambiguity;
    import IO;
    
    lexical Scheme = AnyScheme ; 
    lexical AnyScheme = KnownScheme > UnknownScheme ;
    lexical AnySchemeChar = [a-z*];
    lexical KnownScheme = KnownSchemes !>> AnySchemeChar ;  
    lexical KnownSchemes = "http" | "https" | "http*" | "javascript" ;
    lexical UnknownScheme = UnknownFixedScheme | UnknownWildScheme ;
    lexical UnknownFixedScheme = [a-z]+ !>> AnySchemeChar ;
    lexical UnknownWildScheme = [a-z]* '*' AnySchemeChar* !>> AnySchemeChar ;
    
    lexical Scheme2 = UnknownScheme2 | KnownScheme ;
    lexical UnknownScheme2 = UnknownScheme \ KnownSchemes ;
    lexical Scheme3 = UnknownScheme3 | KnownScheme ;
    lexical UnknownScheme3 = AnySchemeChar+ \ KnownSchemes ;
    lexical Scheme4 = UnknownScheme4 | KnownScheme ;
    lexical UnknownScheme4 = AnySchemeChar+ \ ("http"|"https") ;
    lexical Scheme5 = UnknownScheme5 | KnownScheme ;
    lexical UnknownScheme5 = AnySchemeChar+ \ "http" ;
    
    test bool t1() { return parseAccept( #Scheme, "http" ); }
    test bool u1() { return parseAccept( #Scheme2, "http" ); }
    test bool v1() { return parseAccept( #Scheme3, "http" ); }
    test bool w1() { return parseAccept( #Scheme4, "http" ); }
    test bool x1() { return parseAccept( #Scheme5, "http" ); }
    test bool s1a() { return parseAccept( #KnownScheme, "http" ); }
    test bool s1b() { return parseAccept( #UnknownScheme, "http" ); }
    test bool s1c() { return parseReject( #UnknownScheme2, "http" ); }
    test bool s1d() { return parseReject( #UnknownScheme3, "http" ); }
    test bool s1e() { return parseReject( #UnknownScheme4, "http" ); }
    test bool s1f() { return parseReject( #UnknownScheme5, "http" ); }
    
    bool verbose = false;
    
    bool parseAccept( type[&T<:Tree] begin, str input )
    {
        try
        {
            parse(begin, input, allowAmbiguity=false);
        }
        catch ParseError(loc _):
        {
            return false;
        }
        catch Ambiguity(loc l, str a, str b):
        {
            if (verbose)
            {
                println("[Ambiguity] " + a + ", " + b);
                Tree tt = parse(begin, input, allowAmbiguity=true) ;
                iprintln(tt);
                list[Message] m = diagnose(tt) ;
                println( ToString(m) );
            }
            fail;
        }
        return true;
    }
    
    bool parseReject( type[&T<:Tree] begin, str input )
    {
        try
        {
            parse(begin, input, allowAmbiguity=false);
        }
        catch ParseError(loc _):
        {
            return true;
        }
        return false;
    }
    
    str ToString( list[Message] msgs ) =
        ( ToString( msgs[0] ) | it + "\n" + ToString(m) | m <- msgs[1..]  );
    
    str ToString( Message msg)
    {
        switch(msg)
        {
            case error(str s, loc _): return "error: " + s;
            case warning(str s, loc _): return "warning: " + s;
            case info(str s, loc _): return "info: " + s;
        }
        return "";
    }
    
    1 回复  |  直到 6 年前
        1
  •  2
  •   Jurgen Vinju    6 年前

    我一直在做这个歧义诊断工具,下面是它为你的语法设计的。看来你已经发现了更多我们需要记录和编写小检查的东西。

    格式良好 \ 很模糊。

    问题是 \ 运算符只接受文本字符串,例如 A \ "a" \ "b" 或者 keyword 非终端定义如下 keyword Hello = "a" | "b"; ,用作 A \ Hello ,请 没有别的了 是的。同样 A \ ("a" | "b") 不允许,也不允许间接非终端 A\你好 哪里 lexical Hello = Bye; lexical Bye = "if" | "then" ;也不允许。只有最简单的形式。

    遵循限制的良好性

    类似的规则 !>> 不允许在 啊!>gt; 接线员。

    所以 [a-z]+ !>> [a-z] [a-z]+ !>> "*" ,但是 [a-z]+ \ myCharClass 哪里 lexical myCharClass = [a-z];

    字符类的名称在todoy列表中;但它们不像非终端。更像是将在解析器生成器时被替换的别名。

    整句话

    关键字保留仅在从整个单词中减去句子时有效。有时您必须对非终端进行分组才能正确执行此操作:

    • lexical Ex = ([a-z]+ "*") \ "https*" 而不是 lexical Ex = [a-z]+ "*" \ "https*")

    后者试图减去 "https*" 语言来自 "*" 语言。第一个成功了。

    病例不敏感

    • 'if' 由定义 lexical 'if' = [iI][fF];
    • "if" 由定义 lexical "if" = [i][f];
    • '*' 由定义 lexical '*' = [*];
    • “*” 由定义 lexical "*" = [*];

    新语法

    我使用一个随机生成器生成所有我能找到的歧义,并通过添加关键字reservation逐步解决它们:

    lexical Scheme = AnyScheme ; 
    lexical AnyScheme = KnownScheme > UnknownScheme ;
    lexical AnySchemeChar = [a-z*];
    lexical KnownScheme = KnownSchemes !>> AnySchemeChar ;  
    keyword KnownSchemes = "http" | "https" | "http*" | "javascript" ;
    lexical UnknownScheme = UnknownFixedScheme | UnknownWildScheme ;
    lexical UnknownFixedScheme = [a-z]+ !>> AnySchemeChar \ KnownSchemes ;
    lexical UnknownWildScheme = ([a-z]* '*' AnySchemeChar*) !>> AnySchemeChar  \ KnownSchemes ;