diff --git a/S-Expressions.md b/S-Expressions.md index 193160c..01e9d2f 100644 --- a/S-Expressions.md +++ b/S-Expressions.md @@ -6,7 +6,7 @@ Lisp 程序代码与数据的形式完全相同,这使得它非常强大,能 本章结束后,程序的运行结果会和上一章的有轻微的不同。这是因为我们会花时间去更改程序内部的工作方式。在软件开发中,这被叫做**重构**。重构可能对于当前的程序运行结果并没有太大的影响,但因为工作方式的优化,会使我们在后面的开发中更加省心。 -为了存储输入,我们需要创建一个内部列表结构,能够递归的表示数字、操作符号、其他的列表。在 Lisp 中,这个结构被称为 S-表达式(Symbolic Expression)。我们将扩展 `lval` 结构来表示它。S-表达式求值也是典型的 Lisp 式过程:首先取列表第一个元素为操作符,然后遍历所有剩下的元素,作为操作数。 +为了存储输入,我们需要创建一个内部列表结构,能够递归地表示数字、操作符号以及其他的列表。在 Lisp 中,这个结构被称为 S-表达式(Symbolic Expression)。我们将扩展 `lval` 结构来表示它。S-表达式求值也是典型的 Lisp 式过程:首先取列表第一个元素为操作符,然后遍历所有剩下的元素,将它们作为操作数。 有了 S-表达式,我们才算真正迈进了 Lisp 的大门。 @@ -14,11 +14,11 @@ Lisp 程序代码与数据的形式完全相同,这使得它非常强大,能 在 C 语言中,要表示列表,就必须正确的使用指针。C 语言中的指针一直如洪水猛兽般存在。虽然概念上非常简单,但是用起来却变幻多端,神秘莫测,这使得指针看上去比实际要可怕得多。幸运的是,在本书中我们只会用一些指针在 C 语言中最常规的用法。 -我们之所以需要指针,主要是由 C 语言中函数的工作方式决定的。C 语言函数的参数都是通过值传递的。也就是说,传递给函数的是实参的拷贝。对于 `int`、`long`、`char`等系统类型以及用户自定义的结构体都是成立的。这种方式适用于绝大多数情况,但也会偶尔出现问题。 +我们之所以需要指针,主要是由 C 语言中函数的工作方式决定的。C 语言函数的参数**全部**是通过值传递的。也就是说,传递给函数的实际是实参的拷贝。对于 `int`、`long`、`char`等系统类型以及用户自定义的结构体都是成立的。这种方式适用于绝大多数情况,但也会偶尔出现问题。 -一种常见的情况是,当我们有一个巨大结构体需要作为参数传递的时候,每次调用函数,就会对实参进行一次拷贝,这无疑是对性能和内存的浪费。 +一种常见的情况是,如果我们有一个巨大结构体需要作为参数传递,则每次调用函数,就会对实参进行一次拷贝,这无疑是对性能和内存的浪费。 -另外一个问题是,结构体的大小终究是有限的,只能是个固定的大小。而如果我们想向函数传递一组数据,而且数据的总数还是不固定的,结构体就明显的无能为力了。 +另外一个问题是,结构体的大小终究是有限的,无论多大,也只能是个固定的大小。而如果我们想向函数传递一组数据,而且数据的总数还是不固定的,结构体就明显的无能为力了。 为了解决这个问题,C 语言的开发者们想出了一个聪明的办法。他们把内存想象成一个巨大的字节数组,每个字节都可以拥有一个全局的索引值。这有点像门牌号:第一个字节索引为 0,第二个字节索引为 1,等等。 @@ -118,3 +118,47 @@ typedef struct lval { ## 构造函数和析构函数 +我们可以重写 `lval` 的构造函数,使其返回 `lval` 的指针,而不是其本身。这样做会使得对 `lval` 变量进行跟踪更加简单。为此,我们需要用到 `malloc` 库函数以及 `sizeof` 操作符为 `lval` 结构体在堆上申请足够大的内存区域,然后使用 `->` 操作符填充结构体中的相关字段。 + +``` +/* Construct a pointer to a new Number lval */ +lval* lval_num(long x) { + lval* v = malloc(sizeof(lval)); + v->type = LVAL_NUM; + v->num = x; + return v; +} +``` + +``` +/* Construct a pointer to a new Error lval */ +lval* lval_err(char* m) { + lval* v = malloc(sizeof(lval)); + v->type = LVAL_ERR; + v->err = malloc(strlen(m) + 1); + strcpy(v->err, m); + return v; +} +``` + +``` +/* Construct a pointer to a new Symbol lval */ +lval* lval_sym(char* s) { + lval* v = malloc(sizeof(lval)); + v->type = LVAL_SYM; + v->sym = malloc(strlen(s) + 1); + strcpy(v->sym, s); + return v; +} +``` + +``` +/* A pointer to a new empty Sexpr lval */ +lval* lval_sexpr(void) { + lval* v = malloc(sizeof(lval)); + v->type = LVAL_SEXPR; + v->count = 0; + v->cell = NULL; + return v; +} +```