上下文敏感度与歧义

时间:2011-05-22 12:56:45

标签: c++ grammar ambiguity

我对上下文敏感度和模糊性如何相互影响感到困惑。

我认为正确的是:

歧义:

模糊语法导致使用左或右派生构造多个解析树。所有可能的语法都含糊不清的语言是一种含糊不清的语言。

例如,C ++是一种含糊不清的语言,因为x * y总是指两个不同的东西,如:Why can't C++ be parsed with a LR(1) parser?中所述。

上下文灵敏度:

上下文敏感语法具有这样的规则,其中这些规则的左侧可以包含(非)终端符号,而不是在不同类型语法的所有规则的lhs内所需的一个非终结符号。这意味着您不能在降序时替换非终结符。相反,你必须先看看周围的非终结者。


现在困扰我的是那些或多或少地说上下文敏感的解析器可以解析像x * y这样的歧义的语句。例如,在上面的链接问题中,声明“... [在创建语法树时装饰语法树]的解析器不是上下文无关的,而LR解析器(纯粹的解析器)是无上下文的。”在我看来,这意味着上下文敏感的解析器(与无上下文解析器相反?)可以做到这一点。另一个例子是Is any part of C++ syntax context sensitive?,其中这个问题用“是......”回答。同上:what is an ambiguous context free grammar?

我不知道这个C ++模糊性与上下文敏感性有什么关系。我不认为有任何上下文敏感的语法可以处理这种歧义。例如,如果你采取像虚构的规则 Typedef,< other> *,PointerDeclaration - >标识“*”标识

然后你仍然无法确定(使用纯解析)在Typedef期间是否使用了具体的第一个Ident(例如“x”)(例如typedef double x;)。


因此有可能在链接的问题中使用术语“上下文敏感性”,尽管意味着像上下文依赖一样简单(例如,需要比简单解析器提供的更多信息)。或者“真实的”情境敏感性与歧义之间是否有任何联系。

编辑更多指定问题:在无上下文语法中是否存在任何可以通过使用上下文相关语法处理的歧义。这个问题发生在我身上,因为在链接的问题中,它听起来像C ++模糊性有时被称为上下文敏感性问题。

Edit2 其他信息:第346页的书Computer Systems指出,上下文相关语法可以表示具有相同数量的实际和形式参数等要求。但这非常麻烦,因为你需要很多复杂的规则。但也许这也适用于前面提到的C ++模糊性。所以我们有像

这样的规则

“Typedef double x”,< other> *,PointerDeclaration - > “x”“*”标识

当然,这些规则将非常有限,您需要大量的表达每种可能性。至少这可能是问题答案的一种方法,如果(理论上)无上下文的自由歧义可以被上下文敏感规则的使用所取代

3 个答案:

答案 0 :(得分:5)

上下文敏感度和模糊性完全正交。存在模糊的无上下文语言和明确的上下文敏感语言。

上下文相关语言是一种可以通过上下文相关语法(CSG)解析的形式语言。每个无上下文语言也是一种上下文敏感语言,因为无上下文语法是简化的上下文相关语言。不是每种形式语言都是上下文敏感的;有些语言甚至连CSG也无法描述。

答案 1 :(得分:4)

如果要使用无上下文解析器解析上下文相关语言,可以定义一个无上下文语法,该语法接受上下文相关语言的超集(因为它们功能较弱)。因为您接受超集,所以可能会出现歧义或误报结果,必须在解析后解决。

示例一:类似XML的语言,允许任何标记名称。因为无上下文语法无法解析由两个重复单词 w = {a,b} +组成的句子 ww ,所以无法解析其中ID为<ID></ID>的句子也是平等的。因此,定义了一个接受超集的无上下文语法:

start -> elem
elem  -> open elem* close
open  -> '<' ID '>'
close -> '</' ID '>'
ID    -> ('a' / 'b')+

这显然会解析一个人不想要的句子,因此必须对openclose中的等效ID进行额外检查。

示例二:C-like Typedef ,用一种非常简单的语言。想象一下只包含typedef,指针和乘法的语言。它只有两个ID,ab。这种语言的一个例子:

typedef a;
b * a;                    // multiplication
a * b;                    // b is pointer to type a 

无上下文语法如下:

start                     -> typedef multiplication-or-pointer+
typedef                   -> 'typedef' ID ';'
multiplication-or-pointer -> ID '*' ID ';'
ID                        -> 'a'
ID                        -> 'b'

语法不接受超集,但它不知道它是否看到乘法或指针,因此它是不明确的。因此,必须通过结果并决定,如果它是乘法或指针,则取决于typedef中定义的类型。

使用上下文相关语法,可以做更多事情。非常粗略(并且不精确):

start                                     -> typedef multiplication-or-pointer+
typedef                                   -> 'typedef' ID ';'
multiplication-or-pointer                 -> pointer / multiplication
'typedef' 'a' ';' WHATEVER pointer        -> 'a' '*' ID   
'typedef' 'b' ';' WHATEVER pointer        -> 'b' '*' ID   
'typedef' 'b' ';' WHATEVER multiplication -> 'a' '*' ID
'typedef' 'a' ';' WHATEVER multiplication -> 'b' '*' ID
ID                                        -> 'a'
ID                                        -> 'b'

请注意,我在这里展示的内容并不精确,因为我的身份证数量有限。通常,可以存在无限数量的ID。你可以为一般情况编写一个上下文敏感的语法(尽管它必须绝对不直观),但是你不能编写一个无上下文语法。

关于你的编辑1:我希望上一个例子能够回答这个问题。

关于你的编辑2:还有另外一些技巧如何表达,所以规则不是那么有限,但它们通常令人兴奋和IMO这就是没有人使用CSG形式主义的原因。

注意:上下文敏感语法相当于线性有界自动机,无上下文语法相当于下推自动机。说上下文解析器与上下文相关的解析器相反是不对的。

答案 2 :(得分:0)

编译器不使用“纯粹”(无论可能意味着什么)语法来进行解析 - 它们是真实世界的程序,可以完成所有真实世界程序所做的事情 - 在某些情况下应用启发式算法。这就是为什么C ++编译器(以及大多数其他语言的编译器,除了本科练习)不是使用编译器生成器生成的。