Common Lisp译本笔记3之第四章 语法和语义

来源:互联网 发布:网络地板价格 编辑:程序博客网 时间:2024/06/05 03:42
大多数编程语言,语言的处理器(无论是解释器或编译器)的操作方式都类似黑箱操作。
在黑箱内部,语言的处理器通常分成子系统。
一个典型的任务划分思路:将处理器分为三个阶段,每个阶段为下一个阶段提供内容。
1、一个词法分析器将字符流分拆成语元并将其送进一个解析器
2、解析器再根据该语言的语法在程序中构建一个表达式的树形表示。这棵树被称为抽象语法树。
3、随即被送进一个求值器,求值器要么直接解释它,要么将其编译成魔种其他语言(如:机器码)。

Common lisp定义了两个黑箱:读取器、求值器
读取器:将文本转为lisp对象。
求值器:用这些对象实现语言的语义。

每个黑箱都定义了一个语法层面。读取器定义了字符串如何被转换为S-表达式的lisp对象。
S-表达式适用于由任意对象及其他列表所组成的列表,因此S-表达式可用来表达任意树形表达式。
求值器随后定义了一种构建在S-表达式之上的lisp形式的语法。

此种黑箱划分带来的后果:
1、可将S-表达式用作一种可暴露的数据格式来表达源代码之外的数据。
2、由于语言的语义是用对象树而非字符串定义而成的,则可通过语言本身来生成代码,则可通过处理现有的数据生成代码,从而达到“可编程的编程语言”的效果,即lisp宏的本意。

S-表达式

S-表达式的基本元素是列表、原子。
列表由括号所包围,并可包含任何数量的由空格所分隔的元素。
原子是所有其他内容。

原子:数字、字符串、名字。

数字:任何数位的序列都会被读取为一个数字。可为整数、比值、小数、科学计数法

字符串:用双引号包含的都是字符串。用反斜杠进行转义。

字符:用#\表示,如:#\a表示字符a

名字:由称为符号的对象表示。如:format、hello-world、*db*

十个字符不能出现在名字中:开括号、闭括号、双引号、单引号、反引号、逗号、冒号、分好、反斜杠、竖线。
如真想用的,则需要用反斜杠转义或将含有需要转义的字符名字用竖线包起来。

读取器将名字转化为符号对象的方式:
1、当读取名字时,读取器将所有名字中未转义的字符都转为大写。
2、为了确保同一个文本名字总是被读取成相同的符号,读取器保留这个符号之后,在一个称为包的表汇总查询带有相同名字的已有符号,若找不到,则创建一个新的符号并添加到表中。否则返回那个符号。

名字的约定:
全局变量:开始和结尾用*。如:*db*
常量:开始和结尾用+。如:+zero+

lisp求值方式:将求值器看做一个函数,接收一个句法良好定义的lisp形式作为参数并返回一个值。

原子可被分为两个类别:符号和所有其他内容。
符号在作为lisp形式被求值时会被看作一个变量名,并会被求值为该变量的当前值。
所有原子都是自求值对象。

lisp中的真假值为:T和NIL
其中NIL既是原子也是列表,nil是空列表。
另一类自求值符号是关键字符号(以冒号开始的符号),当读取器保留这样一个名字时,会自动定义一个以此命名的常量变量并以该符号作为其值。



函数调用

函数调用规则:除第一个以外,所有的列表元素它们自身必须是一个形态良好的lisp形式。
调用格式:(函数名 参数列表)

函数的所有参数都在函数被调用之前求值。

特殊操作符

如:if
if规则:对第一个表达式求值,为非nil则执行第二个表达式,否则执行第三个表达式。
quote规则:接收一个参数,并不求值返回。即:将参数不经处理直接返回。语法糖为:'(单引号)

宏是一个以S-表达式为其参数的函数,并返回一个lisp形式然后对其求值并用改制取代宏形式。

宏形式的求值过程:
1、首先宏形式的元素不经求值即被传递到宏函数里
2、其次,由宏函数所返回的形式(展开式)按照正常的求值规则进行求值。
即宏的求值一般为两个阶段:宏展开阶段、展开式求值阶段。

真、假、等价

符号nil是唯一的一个假值。其他所有的都是真值。
符号T是标准的真值。

等价

eq:用来测试“对象标识”,只有当两个对象相同时,才等价。如:相同值的数字和字符用eq比较是不等价的。

eql:与eq相似,可保证当相同类型的两个对象标识相同的数字或字符值时,才等价。

equal:具有相同内容,就等价。

equalp:在比较字符串时忽略大小写。


格式化代码

保持美观的代码风格,可方便查找错误及阅读代码。

原创粉丝点击