3.3 文法、语法和语义
如果要处理一种语言的语法,文法是一种很重要的工具。文法是一组规则,用以描述如何将文本流转化为语法树。大多数程序员都会在生命中的某一刻接触文法,因为文法常用以描述我们日常使用的程序设计语言。文法由一系列产生式规则组成,每个生产规则都有一个名字(term)以及一个描述如何分解它的语句(statement)。所以,一个加法语句可能看起来就像这样: additionStatement:=number'+'number。它告诉我们,如果遇到语句5+3,解析器能够将其识别为加法语句。因为规则是可以相互引用的,所以也会有一条针对数字的规则,告诉我们如何识别合法数字。通过这些规则,我们就可以得到一种语言的文法。
一种语言可以由多种不同的文法来定义,认识到这点很重要。世界上不存在某种语言的唯一文法。一种文法就定义了语言所生成语法树的一种结构,对于一段特定的文本,可能会识别出许多不同的语法树结构。一种文法只定义一种形式的语法树;选择何种文法和语法树取决于很多因素,包括语言的文法特性以及处理语法树的方式等。
文法只定义一种语言的语法─它在语法树中如何表现。而这与语义(也就是表达式的含义)无关。根据上下文不同,5+3可能等于8,也可能等于53,语法相同,但语义可能截然不同。在“语义模型”(第11章)中,语义的定义浓缩为如何根据语法树组装语义模型,以及如何处理语义模型。特别是,如果两个表达式产生相同结构的语义模型,即使语法不同,它们的语义其实也是相同的。
如果在使用外部DSL,特别是,用到了“语法指导翻译”(第18章),我们很可能会显式地使用文法来构建解析器。如果用的是内部DSL,可能没有显式的文法,但是从文法的角度思考DSL仍然是有用的,文法有助于我们在众多内部DSL模式中进行选择。
对于内部DSL,谈论文法显得有些奇怪,原因之一是,这里解析了两遍,所以包含了两种文法。第一种是宿主语言本身的解析,这显然要依赖于宿主语言的文法。这一遍解析创建宿主语言的执行指令。当宿主语言所构建的DSL执行时,鬼魅般的语法树就会在调用栈中创建。只有在第二遍解析时,才会出现这个名义上的DSL语法。