转自http://www.cnblogs.com/dyllove98/p/3177738.html

在龙书Compilers – Principles, Techniques, & Tools英文版第2版42页中,提到上下文无关文法有以下的特点: 

  1. 一个终结符的有限集(A set of terminal symbols),构成文法的最基本的字符就是这个文法的终结符,例如一个能够产生个位数的文法规则digit –> 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9,则数字0~9就是这个文法的终结符,一个能够产生变量名的文法规则variable –> ('A'-'Z' | 'a'-'z') *(('A'-'Z' | 'a'-'z' | '0'-'9'),则所有的英文字母和数字就是文法的终结符。
  2. 一个非终结符的有限集(A set of nonterminals),例如上面的digit、variable就是非终结符。
  3. 一个产生式的有限集,例如上面的“digit –> …”和“variable –> …”两个规则可以构成一个产生式集
  4. 一个非终结符作为开始符号,在非终结符集中,必须指定其中一个作为开始符号。

虽然这4个特点已经规定了上下文无关文法的特征,但我们仍然好奇,为什么是“上下文无关”而不是“上下文有关”呢?这是因为在利用一个上下文无关文法生成语言的时候,我们可以随意将文法规则左边的非终结符派生(更换)为右边的终结符或非终结符。举个例子,如果有下面的文法:

  1. Number –> 0 / 1 / 2 / 3 / 4 / 5 / 6 / 7 / 8 / 9
  2. Alpha –> 'A'-'Z' / 'a'-'z'
  3. AlphaNum –> Alpha / Number
  4. Variable –> Alpha *AlphaNum

假设Variable是这个文法的开始符号,我们要根据这个文法生成一个语言实例。先应用规则4,Variable派生为Alpha AlphaNum(星号表示后面的符号可以出现0到若干次,这里我们选择出现1次)。然后对Alpha应用规则2,派生为'A',因此整个Variable就派生为'A' AlphaNum。现在来考虑AlphaNum如何派生,有没有限制这个AlphaNum可以派生为Alpha还是Number呢?它是否会受到前面的Alpha的影响而不同?我们说, 在一个上下文无关文法中,这个派生是不受上下文影响的,也就是说,我们可以随意的让其派生为Alpha或者Number,而不必考虑前后文的情况。有关解释可以参考 http://cs.union.edu/~striegnk/courses/nlp-with-prolog/html/node37.html。

因此,“文法”是用来产生语言(字符串)而不是用来识别语言的(参见http://www.cis.upenn.edu/~jean/gbooks/tcbookpdf2.pdf)。对于语言的创造者而言,“文法”是用来描述所要创造的语言的。对于语言的阅读者来说,可以将“文法”转换为有限状态机,这个状态机可以用于识别这个文法所生成的语言。

其他参考:http://en.wikipedia.org/wiki/Context-free_grammar