所谓语法,定义的是一种语言。而语言,是语句的集合。所以一们语法定义的是一组语句组成的集合。但是,一个语言包含的语句通常是无穷无尽的。因此,不可能通过枚举的方法来描述一门语言。为此,便有了语法规则的概念。
具体来说,一个语言由下面4部分组成。
- 终结符组成的集合。一门语言的终结符是语句中不能分割的语法单元。例如在汉语中,可以将单个汉字看成是终结符,英语中将单词看成是终结符。而在编程语言中,终结符包括运算符,保留字,常量和变量等。
- 非终结符组成的集合。非终结符是一个抽象的语法单元。例如自然语言中的动词,名词,动词短语,名词短语等概念,都可以看做是非终结符。这一类抽象的语法单元可以进行进一步的细分。例如,名词短语可能由一个形容词+一个名词组成(这样的结构在语法称为偏正结构)。所以终结与非终结的区别,在于看这个语法单元能否再进行细分。在编程语言中,非终结符包括表达式语句,if语句,while语句,函数调用语句等。
- 产生式组成的集合。一个产生式是一个语法规则,它用来定义语法单元的具体意义。例如
<名词短语>→<形容词><名词><script type="math/tex; mode=display" id="MathJax-Element-2605"> <名词短语> \rightarrow <形容词> <名词> </script>
<形容词>→lovely<script type="math/tex; mode=display" id="MathJax-Element-2606"> <形容词> \rightarrow lovely</script>
<名词>→dog<script type="math/tex; mode=display" id="MathJax-Element-2607"> <名词> \rightarrow dog</script>
上面三个产生式中第1个产生式告诉我们名词短语由形容词和名词构成。第2个产生式告诉我们lovely是一个形容词,第3个产生式告诉我们dog是一个名词。这样我们就知道lovely dog是一个名词短语。我们可以定义一些新的形容词和名词。例如
<形容词>→beautiful<script type="math/tex; mode=display" id="MathJax-Element-2608"> <形容词> \rightarrow beautiful</script>
<形容词>→naughty<script type="math/tex; mode=display" id="MathJax-Element-2609"> <形容词> \rightarrow naughty</script>
<名词>→cat<script type="math/tex; mode=display" id="MathJax-Element-2610"> <名词> \rightarrow cat</script>
通过上面的语法产生式我们知道beautiful和naughty都是形容词,而cat也是一个名词。这样lovely cat, beautiful dog,beautiful cat, naughty dog和naughty cat这样的句子都是名词短语。我们称这样的语句为可以通过“名词短语”这个非终结符生成的语句。 - 开始符号。开始符号是一个非终结符。所有能够通过开始符号生成的语句,都是这门语言合法的语句。这样的话,我们就定义了这门语言的所有合法语句组成的集合。
根据对产生式的限制条件,可以将语法分为0型文法,1型文法,2型文法和3型文法。
0型文法又称为短语结果文法。它是最一般的文法。它包含的语言集合等价于图灵机能够识别的语言集合。
1型文法又称为上下文有关文法。它描述的自然语言的语法结构。因为在自然语言中,一个语法结构在不同的语境(上下文)下,会有不同的语义,可能生成不同的语句集合。
2型文法称为上下文无关文法。所有的编程语言都是通过上下文 无关文法来定义。它的特点是同样的语法结构在不同的语境下,生成的语句集合的相同的。
3型文法称为正则文法或者线性文法。它定义的语言集合是有限自动机能够识别的语言。
编译原理使用的文法是2型和3型文法,因此后面的博客会对这两类文法做进一步的分析,而略去0型和1型文法的介绍。
最后需要说明一点,语法规则只是用来识别一个语句是否合法,却不能分析出语句的意义。