rascal - 歧义规则无法解决流氓歧义
问题描述
我试图消除歧义,与我几天前提出的问题相同。在上一个问题中,语言实现存在未记录的限制;我想知道这里是否有类似的事情发生。
测试[tuvw]1
都抛出歧义异常(顺便说一句:你如何捕捉到这些?[编辑:已回答])。他们看起来都应该通过。请注意,它们必须是明确的才能通过。优先规则Scheme
和保留规则UnknownScheme[23]
似乎都没有消除歧义。可能与我不理解的遵循规则有一些互动;这可能是另一个限制或缺陷。这是怎么回事?
我在不稳定的分支上。版本(来自 Eclipse):0.10.0.201806220838
编辑。我修改了示例代码以更清楚地突出显示正在发生的事情。我删除了一些多余的测试和行为正确的测试。我扩展了一些可能冗长的诊断。我更改了上面的说明以匹配。更新的结果如下。
看起来这里有两种不同的东西在起作用。"http"
被KnownScheme
和UnknownScheme
在 测试 中(正确地)接受s1[ab]
。它似乎表现得好像Scheme
just 中的优先级声明不起作用,好像>
被替换为|
.
在另一种情况下,测试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 "";
}
解决方案
我一直在制作这个歧义诊断工具,这就是它为您的语法提供的内容。您似乎发现了更多我们需要记录和编写小检查器的东西。
的良构\
是模糊的。
问题是该\
运算符只接受文字字符串,例如A \ "a" \ "b"
或定义为 like 、 used as的keyword
非终结符,而没有其他任何内容。所以也是不允许的,还有间接的非终结符,比如where ; 也不允许。只有最简单的形式。keyword Hello = "a" | "b";
A \ Hello
A \ ("a" | "b")
A \ Hello
lexical Hello = Bye; lexical Bye = "if" | "then"
遵循限制的良好形成
!>>
禁止运算符右侧的任何非终端的类似规则!>>
。
所以[a-z]+ !>> [a-z]
或[a-z]+ !>> "*"
,但不是 [a-z]+ \ myCharClass
在哪里lexical myCharClass = [a-z];
角色类的名称在我们的待办事项清单上;但它们不会像非终端一样。更像是在解析器生成器时被替换的别名。
整个单词
关键字保留仅在您从整个单词中减去句子时才有效。有时您必须对非终端进行分组才能做到这一点:
lexical Ex = ([a-z]+ "*") \ "https*"
代替lexical Ex = [a-z]+ "*" \ "https*")
后者会尝试"https*"
从语言中减去"*"
语言。第一个作品。
不区分大小写
'if'
定义为lexical 'if' = [iI][fF];
"if"
定义为lexical "if" = [i][f];
'*'
定义为lexical '*' = [*];
"*"
定义为lexical "*" = [*];
新语法
我使用了一个随机生成器来生成我能找到的所有歧义,并通过添加关键字保留逐步解决它们:
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 ;