“无上下文语法”在术语“无上下文语法”中是什么意思?


55

鉴于试图解释什么是上下文无关文法(CFG)的材料数量众多,我发现令人惊讶的是,很少有人(在我的示例中,少于20个样本中有1份)对为何将这种语法称为“上下文文法”进行了解释。自由”。而且,在我看来,没有人能成功做到这一点。

我的问题是,为什么无上下文语法称为无上下文语法?什么是“上下文”?我有一种直觉,即上下文可以是围绕当前分析的构造的其他语言构造,但事实并非如此。谁能提供准确的解释?


4
查找C ++的“最令人烦恼的分析”,它将教你为什么上下文无关性很方便
棘手的怪胎

6
我以为我知道什么是上下文无关的语法,直到我刚刚阅读了一些Googled定义。现在我希望我有一个素描画和一块柔软的布兰妮...也许我会出去... + 1一个好问题。期待一些可理解的答案!
BrianH

我的理解是您的直觉,即使“围绕当前分析的构造的其他语言构造”的正式定义适当地是奥秘的。但是我不确定是否可以将其发布为答案。
Telastyn

1
请参阅有关上下文无关语法Chomsky层次结构的Wikipage。在实践中,编程语言解析 具有某些上下文,通常在“无上下文”(LR或LL)解析的“外部”进行处理,例如通过某些符号表,属性或环境进行处理
Basile Starynkevitch 2014年

1
在这里,有一个xkcd参考:xkcd.com/1090
CaptainCodeman

Answers:


61

这意味着其所有生产规则的左侧都具有一个非终结符。

例如,此语法可识别匹配括号的字符串(“()”,“()()”,“(())(),...)”是与上下文无关的:

S → SS
S → (S)
S → ()

每个规则的左侧都由一个非终结符组成(在这种情况下,它总是S,但可以有更多个。)

现在考虑一种识别形式为{a ^ nb ^ nc ^ n:n> = 1}的字符串的语法(例如“ abc”,“ aabbcc”,“ aaabbbccc”):

S  → abc
S  → aSBc
cB → WB
WB → WX
WX → BX
BX → Bc
bB → bb

如果非终端B,由终端/文字字符开头c,你重写这个词来WB,但如果它是由前面b,你扩大到bb代替。大概就是上下文敏感语法的上下文敏感所暗示的。

上下文无关的语言可以识别为下推式自动机。有限状态机不使用辅助存储,即,其决策仅基于其当前状态和输入,而下推式自动机也可以使用堆栈,并且可以窥视堆栈顶部以进行决策。

要查看实际情况,您可以通过以下方式解析嵌套的括号:在每次遇到一个括号时将其左移并推入堆栈,并在每次遇到一个右括号时将其弹出。如果您从未尝试过从一个空堆栈中弹出,并且该堆栈在字符串末尾为空,则该字符串有效。

对于上下文相关的语言,PDA是不够的。您将需要一个线性有界自动机,就像图灵机一样,它的磁带不是无限的(尽管可用的磁带数量与输入成比例)。请注意,这很好地描述了计算机-我们喜欢将它们视为图灵机,但在现实世界中,您无法任意获取更多的中间程序RAM。如果您不知道LBA比PDA更强大,LBA可以通过将一部分磁带作为堆栈来模拟PDA,但是它也可以选择以其他方式使用它的磁带。

(如果您想知道有限状态机可以识别的内容,答案是正则表达式。但不是类固醇的正则表达式,它们具有在程序语言中看到的捕获组和后向/向前看;我的意思是可以构建的正则表达式与像运营商[abc]|*+,和?。你可以看到,abbbz相匹配的正则表达式ab*z只是保持字符串和正则表达式在你的当前位置,无需堆栈。)


14
很好的解释。虽然,图灵机的磁带不需要是无限的,而只是无限的。两端可能都有一个磁带工厂,当机器撞到它时,只会制造更多的磁带。这样,在任何时间点,它都是有限的。
2014年

2
@MikeDunlavey感谢您的澄清,将其修复。
Doval

10
但是磁带工厂将需要无限的磁带制作材料,或无限的磁带制作材料制作,或者... [堆栈溢出]
flamingpenguin 2014年

8
@Mehrdad:您可以使用两个堆栈模拟任意数量的堆栈:将所有堆栈堆叠在一个堆栈上,当您需要进一步向下访问某些堆栈时,弹出较高的堆栈,然后将它们推入第二个堆栈。这证明n> 2堆栈的功能不比2堆栈强大。现在,我不知道2个堆栈是否比1个堆栈更强大。我的直觉说不,但这可能取决于堆栈原语到底是什么。
约尔格W¯¯米塔格

10
@JörgWMittag:两叠就像一盘磁带一样好。手动操作:相对于当前位置,将一个纸叠用作磁带的左侧,将另一纸叠用作磁带的右侧。因此,2-PDA是图灵机。对于基元,您只需要能够从一个堆栈中弹出一个值,然后将其推入另一个堆栈,这就是您沿磁带移动的方式。
史蒂夫·杰索普

20

即使是正确和正确的,其他答案也很长。这是简短的版本。

如果您有一个字符串(终结符和非终结符),并且希望替换字符串中的非终结符,则无上下文无关的语法可让您做到这一点,而与非终结符周围的字符无关。

考虑以下规则(小写为终端,大写为非终端):

A -> a
AB -> a

在第一个规则中,A 无论周围出现什么(上下文),您都可以替换。在第二条规则中,A除非后面有,否则您将无法替换B。虽然在这种情况下两个非终端都将被替换,但重要的是该A问题周围的非终端。一个人不能代替BAa,或Ba:只有A后面是B因为订单的情况下的非终结符是很重要的。这意味着第二条规则中非终结符的上下文很重要,使其与上下文相关,而第一条规则是无上下文的。


这是一个很好的解释,尽管我没有资格保证其准确性或完整性。这就是全部吗?
里克

1
计算机语法是Chomsky层次结构的一部分。那篇文章是一个很好的起点。同样,该主题应该成为计算机科学中任何学士学位课程的一部分。至少,大学应该教授常规语法和上下文无关的语法,因为它们构成了我们程序员可能会遇到的绝大多数语言。

@Snowman:非常清晰。如果您说“ 除非出现,否则就不能衍生a自” ,而不是说“您不能替换”,那将是不可能的,因为实际上您要替换的不是它吗ABABAAB
贾斯汀

@贾斯汀正确。我更新了答案,以使这一点更加清楚。

@Snowman:您是要替换A还是AB第二条规则(对上下文敏感)?我认为您仍在尝试替换A答案中的内容。
贾斯汀2015年

7

为了更好地理解区别和术语,最好将无上下文语言(如n b n)与上下文相关语言(如n b n c n)进行对比。(符号:a,b和c在这里是文字,指数n表示将文字重复n次,例如n > 0。)例如,aabbcaabbbcc不是后者语言,而是aabbcc

上下文无关的语言a n b n的接受者可以收缩一对,a并且b不管周围是什么(即,不管ab出现在什么上下文中),它都可以正常工作,仅接受该语言中的字符串并拒绝其他任何内容,即语法是S -> aSb | ab。请注意,产品左侧没有端子。(有两个生产规则,但是我们只是紧凑地编写它们。)接受者基本上可以做出本地的,无上下文的决定。

相反,对于上下文相关的语言a n b n c n,您不能做这样的事情,因为对于后者,您必须记住某种上下文,例如,您做了多少次ab收缩以使它们与收缩匹配公元前 后一种语言的语法是

S -> abc | aBSc
Ba -> aB
Bb -> bb

请注意,在最后两个规则中,您同时拥有终端和非终端。左侧的终端是可以扩展非终端的上下文。


关于“合同”与“扩展”术语等的引导注释:尽管形式语法是[正式的,哈哈]的生成,但它们在解析器中的实际实现方式实际上是简化派,即,基本上,您将所有内容与非终结符联系“反向”应用规则,这就是为什么即使上面给出的第一个语法在程序中也不实用(它会给您带来著名的shift-reduce冲突,因为您无法决定要应用哪个规则),但是上面的两个语法足以说明上下文无关和上下文敏感之间的区别。与上下文无关的语法中的歧义性问题相当复杂,并且并不是该问题的真正话题,因此在此我不再赘述,尤其是因为事实证明维基百科对此有不错的报道。。相反,其有关上下文无关的文章,尤其是有关上下文敏感的语言的文章是!@#$ @!#$,特别是如果您是该主题的新手……我想我的TODO列表上还有更多内容。


5

上面的答案对它是一个很好的定义。让我们看看我是否可以用自己的话来表达它,这样您将有23种解释而不是20种解释。语法(任何语法)的全部目的是弄清楚某个特定句子是否是给定语言的句子。但是,我们真正使用语法和解析的目的是弄清楚句子的含义。就像旧的句子图解法一样,您可能会或可能不会在学校上过英语课。句子由主语部分和谓语部分组成,主语部分有名词,也许还有一些形容词,谓词部分有动词,也许还有宾语,还有更多形容词,等等。

如果有一种英语语法(我不认为不是计算机科学意义上的语法),那么它将具有以下形式的规则,称为产生式。

Sentence -> SubjectPart PredicatePart
SubjectPart -> Adjective Noun

等等...

然后,您可以编写一个程序并将其交给任何句子,然后该程序可以使用该语法找出每个单词在句子的哪一部分以及它们之间的关系。

如果在每个作品中,左侧只有一个东西,那么这意味着只要您在句子中看到右侧,就可以在左侧替换。例如,每当您看到形容词名词时,您都可以说“ That's SubjectPart”,而无需关注该短语之外的任何内容。

但是,英语(甚至我上面给出的英语简化描述)也是上下文相关的。“形容词名词”并不总是SubjectPart,它可以是PredicatePart中的名词短语。这取决于上下文。让我们扩展一下伪英语语法:

Sentence -> SubjectPart PredicatePart
SubjectPart -> Adjective Noun
PredicatePart -> VerbPhrase ObjectNounPhrase
VerbPhrase ObjectNounPhrase -> VerbPhrase Adjective Noun

仅在动词短语之后才可以在ObjectNounPhrase中使用“形容词名词”。

基本上,如果您有作品,并且可以随心所欲地应用它,那么不管它周围是什么,它都是上下文无关的。

您始终可以轻松判断语法是否与上下文无关。只需检查箭头左侧是否有多个符号即可。

任何一种语言都可能用一种以上的语法来描述。如果某种语言的语法是上下文无关的,则该语言是上下文无关的。对于某些语言,可以证明没有上下文无关的语法是可能的。我想我上面描述的简化的伪英语子集可能有上下文无关的语法。

至于为什么重要,它需要一种更简单的程序来解析上下文无关的语法。正如在其他答案中指出的那样,不需要图灵机的全部功能来解析上下文无关的语法。用于特定上下文无关文法的超前LR(1)解析器(是一种下推式机器)可以在时间和空间上解析与该文法长度成线性关系的该文法中的任何句子。如果句子是用语言编写的,则解析器将生成一个结构树,以识别句子中每个符号的含义(或至少它在结构中所扮演的角色)。如果句子不在语法中,则解析器将注意到并停止在第一个符号上,该符号无法与语法和前面的符号(在第一个“错误”上)和好。

更好的是,有些程序可以为您提供语法描述,以及有关如何处理各部分的指令列表(在某种意义上将“含义”附加到每个产品上),并且该程序将编写解析器为了你。程序将解析句子,找到结构,并在结构的每个部分上运行您的指令。这种程序称为解析器生成器或编译器编译器。

发明这种语言分析是为了自动分析自然语言(例如英语),但事实证明,这对于分析计算机语言最有用。语言设计人员可以编写一种语法来捕获他的新语言,然后通过解析器生成器运行该语法以获取一个程序,该程序可以解析他的语言,并根据需要翻译,解释,编译,执行等。

实际上,在大多数情况下,您不能真正做到这一点。例如,平衡括号是一种上下文无关的语言,但是在使用它们之前需要声明所有变量的语言是上下文敏感的。解析器是编译器的一部分,但需要其他逻辑来实施这些其他要求。然后,您要做的是编写一个语法,该语法捕获尽可能多的语言,通过解析器生成器运行该语法,然后编写可满足其余要求的代码(符号表处理程序等)。

我们通常不使用上下文相关的语法,因为它们的支持程度更差。我不知道上下文相关语言是否具有等效于LR(k)解析器生成器的功能。是的,图灵机(或线性绑定机)可以解析一个,但是我不知道是否存在将上下文相关语法转换为图灵机程序的通用算法,即LR(1 )生成器为下推式计算机生成解析表。我的猜测是,作为解析器基础的表将成倍增大。无论如何,CS学生(像我一样,回到过去)通常都被教给上下文无关的语法和LR(1)解析器生成器,例如YACC。


-1

上下文无关的语法不考虑生产规则的任何上下文。上下文是终端或非终端。

因此:上下文无关文法在生产规则的左侧仅具有一个非终结符。


3
这对现有答案有什么作用?同样,在左侧具有两个或多个非终端的生产规则也不是没有上下文的。

我认为给出的答案太长了。如果要添加TL; DR,则将其删除。
2014年

真好!您是否可以说“上下文”是可以应用每个生产规则的多余字符?
里克
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.