正如 cmets 中所指出的,这些语法是错误的,因为它们生成的字符串不是该语言。以下是两种语法中abcc 的推导:
S -> aS -> abA -> abcA -> abccA -> abcc
S -> Sc -> Scc -> Abcc -> Aabcc -> abcc
正如 cmets 中所指出的,这种语言有一个简单的线性文法,其中线性文法被定义为在任何产生式的 RHS 中最多有一个非终结符:
S -> aSc | b
有一些构建语言语法的一般规则。这些要么是显而易见的简单规则,要么是源自闭包属性和语法工作方式的规则。例如:
- 如果
L = {a} 是字母符号a,那么S -> a 是L 的伽玛。
- 如果
L = {e} 为空字符串e,那么S -> e 是L 的语法。
- 如果
L = R U T 用于语言R 和T,那么S -> S' | S'' 连同R 和T 的语法是L 的语法,如果S' 是R 和 S'' 的语法是 T 语法的开始符号。
- 如果
L = RT 用于语言R 和T,则S = S'S'' 是L 的语法如果S' 是R 和S'' 语法的开始符号是开始T 的语法符号。
- 如果
L = R* 表示语言R,那么S = S'S | e 是L 的语法,如果S' 是R 语法的开始符号。
所写的规则 4 和 5 不保持线性。可以为左线性和右线性文法保留线性(因为这些文法描述了常规语言,而常规语言在这些操作下是封闭的);但一般不能保持线性。为了证明这一点,一个例子就足够了:
R -> aRb | ab
T -> cTd | cd
L = RT = a^n b^n c^m d^m, 0 < a,b,c,d
L' = R* = (a^n b^n)*, 0 < a,b
假设L 有一个线性语法。我们必须为开始符号S 产生一个产生某些东西的结果。为了产生一些东西,我们需要一串终端和非终端符号。要成为线性的,我们最多只能有一个非终结符。也就是说,我们的生产必须是形式
S := xYz
其中 x 是一串终结符,Y 是单个非终结符,z 是一串终结符。如果x 非空,反射显示唯一有用的选择是a;其他任何东西都无法派生该语言中的已知字符串。同样,如果z 不为空,则唯一有用的选择是d。这给出了四种情况:
-
x 空,z 空。这是没有用的,因为我们现在要解决非终端 Y 的问题与解决 S 的问题相同。
-
x = a、z 为空。 Y 现在必须准确生成 a^n' b^n' b c^m d^m 其中n' = n - 1。但同样的论点也适用于起始符号为 Y 的语法。
-
x 空,z = d。 Y 现在必须准确生成 a^n b^n c c^m' d^m',其中 m' = m - 1。但同样的论点也适用于起始符号为 Y 的文法。
-
x = a,z = d。 Y 现在必须准确生成 a^n' b^n' bc c^m' d^m',其中 n' 和 m' 与 2 和 3 相同。但是完全相同的论点适用于起始符号为 Y 的语法。
对于S 的有用产生式的所有可能选择实际上都无法使我们更接近语言中的字符串。因此,没有导出字符串,这是一个矛盾,这意味着L 的语法不能是线性的。
假设L' 有一个语法。然后该语法必须生成(a^n b^n)R(a^m b^m) 中的所有字符串,以及e + R 中的字符串。但它不能通过上面使用的论点生成前者:任何对此有用的产生式都不会让我们更接近语言中的字符串。