3.3 产生式
3.3.1 什么是产生式
现在我们已经基本了解了语法分析的思路,但是要做出一个真正的语法分析器,还需要补充不少细节。
我们看前面示例的第一句:
int m = 10;
这句似乎很简单,没有任何问题。仔细想想全局变量定义及初始化语法还有形式上的变化,可以写成:
int m = 10, n = 11, ……;
这也符合C语言全局变量定义及初始化的语法。
一个计算机语言的设计者为了尽可能提高这个语言的适用范围和解决问题的能力,就要尽可能提高这个语言的表现力。提高表现力的方法很多,其中一个方法是增加语言的基础概念(如标识符、变量、函数、参数……),增加概念肯定会使语言的表现力更丰富,伴随而来的问题是这个语言难记难学,不利于推广。另一种方法是在尽量少的概念的前提下,引入少量一看就懂的规则进行不受限制的组合、拓展。C语言就采用了这种方法,前面举的句子:
int m = 10, n = 11, ……;
就是不受限制拓展(定义及初始化变量的个数没有具体数目的限制)的示例。类似示例还有很多,如:
int fun(int a , int b);
还可以不受限制地拓展为:
int fun(int a , int b, int c,……);
除了这类拓展之外,还有另外一类拓展,如:
if(……)…… else……
可以拓展为:
if(……)…… else If…… else If…… else If………………… else If……
此外,还可以组合拓展,如:
if(函数(参数))……
加入这样简单的组合、拓展规则之后,C语言在增加很少概念的前提下表现力得到大大增强,可以写出逻辑更复杂的程序。熟悉C语言的读者根据这些规则很容易找出更多的示例。
对人而言,这是一个非常简单的规则,但如何让计算机“理解”这个规则并能识别出千变万化的语句,却不是一件容易的事。计算机只能做最简单的数字逻辑运算,让计算机“理解”规则就要把规则转化为数字逻辑运算。
3.2节的方法实际上采用了固定的语法模板作为标准去识别符号串,这种方法面对可以任意组合、拓展的C语言语法来说就显得力不从心了,因为等待识别的语句是如何组合、拓展的不得而知,甚至语句究竟包含多少个符号也是不确定的,固定模板的方法不再适用了。既然固定的语法模板不行,就采用动态的、按规则变化的、不断增长的语法模板来应对任意组合、拓展、不确定符号数量的问题。
这个解决方案就是产生式。