3.5 宏
“宏”(第15章)是一种工具,既可以用于内部DSL,也可以用于外部DSL。宏曾经得到广泛应用,但如今已不那么常见了。在大多数情况下,我建议尽量避免使用宏,但偶尔,它也有一些用处。所以,接下来,就谈论宏的运作方式以及使用时机。
宏有两种风格:文本宏和语法宏。文本宏最容易理解,简单说就是文本替换。使用文本宏会带来便利,一个很好的例子就是,在CSS文件中指定颜色。除了少数几种特定情况外,CSS强制我们以颜色代码指定颜色,比如#FFB595。这样的代码并不表意,更糟糕的是,如果要在多个地方使用同一种颜色,就要重复同样的代码。任何形式的代码重复都是坏味道。我们可以给它一个在上下文中有意义的名字,比如MEDIUM_SHADE,在一个地方定义它,比如,MEDIUM_SHADE等于#FFB595。
虽然CSS(至少目前为止)并不允许这么做,但可以用一个宏处理器处理这种情况。创建一个文件,它就是CSS文件,只不过其中用MEDIUM_SHADE表示所需的颜色。然后,用宏处理器做一次简单的文本替换,把MEDIUM_SHADE替换为#FFB595。
这只是一个非常简单的宏处理例子。更复杂的宏还可以有参数。一个经典的例子是C的预处理器,比如,定义一 个宏sqr(x),它可以替换为x*x。
通过宏创建DSL有很多方式,可以使用宿主语言本身(比如,C预处理器),也可以提供单独的一个文件,将其转换为宿主语言。宏的缺点在于,它有很多诡异的问题,这使得它在实际中难于使用。所以,文本宏现在已经不再受宠,很多专业人士(比如我)都反对使用它。
语法宏也是通过替换实现的,但是它处理的是宿主语言中有效的元素,将一种表达式转换为另一种。在以“大量使用语法宏”而闻名的语言中,Lisp最为著名,虽然C++模板更广为人知。使用语法宏编写DSL,是Lisp编写内部DSL 的核心技术,但这种技术也仅限于支持宏的语言。因此,本书不会过多谈及,因为仅有很少的语言可以支持宏。