Skip to content
This repository has been archived by the owner on Aug 31, 2022. It is now read-only.

Commit

Permalink
Update S-Expressions.md
Browse files Browse the repository at this point in the history
  • Loading branch information
ksco committed May 11, 2016
1 parent dac2d6a commit 961557e
Showing 1 changed file with 48 additions and 4 deletions.
52 changes: 48 additions & 4 deletions S-Expressions.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@ Lisp 程序代码与数据的形式完全相同,这使得它非常强大,能

本章结束后,程序的运行结果会和上一章的有轻微的不同。这是因为我们会花时间去更改程序内部的工作方式。在软件开发中,这被叫做**重构**。重构可能对于当前的程序运行结果并没有太大的影响,但因为工作方式的优化,会使我们在后面的开发中更加省心。

为了存储输入,我们需要创建一个内部列表结构,能够递归的表示数字、操作符号、其他的列表。在 Lisp 中,这个结构被称为 S-表达式(Symbolic Expression)。我们将扩展 `lval` 结构来表示它。S-表达式求值也是典型的 Lisp 式过程:首先取列表第一个元素为操作符,然后遍历所有剩下的元素,作为操作数
为了存储输入,我们需要创建一个内部列表结构,能够递归地表示数字、操作符号以及其他的列表。在 Lisp 中,这个结构被称为 S-表达式(Symbolic Expression)。我们将扩展 `lval` 结构来表示它。S-表达式求值也是典型的 Lisp 式过程:首先取列表第一个元素为操作符,然后遍历所有剩下的元素,将它们作为操作数

有了 S-表达式,我们才算真正迈进了 Lisp 的大门。

## 指针

在 C 语言中,要表示列表,就必须正确的使用指针。C 语言中的指针一直如洪水猛兽般存在。虽然概念上非常简单,但是用起来却变幻多端,神秘莫测,这使得指针看上去比实际要可怕得多。幸运的是,在本书中我们只会用一些指针在 C 语言中最常规的用法。

我们之所以需要指针,主要是由 C 语言中函数的工作方式决定的。C 语言函数的参数都是通过值传递的。也就是说,传递给函数的是实参的拷贝。对于 `int``long``char`等系统类型以及用户自定义的结构体都是成立的。这种方式适用于绝大多数情况,但也会偶尔出现问题。
我们之所以需要指针,主要是由 C 语言中函数的工作方式决定的。C 语言函数的参数**全部**是通过值传递的。也就是说,传递给函数的实际是实参的拷贝。对于 `int``long``char`等系统类型以及用户自定义的结构体都是成立的。这种方式适用于绝大多数情况,但也会偶尔出现问题。

一种常见的情况是,当我们有一个巨大结构体需要作为参数传递的时候,每次调用函数,就会对实参进行一次拷贝,这无疑是对性能和内存的浪费。
一种常见的情况是,如果我们有一个巨大结构体需要作为参数传递,则每次调用函数,就会对实参进行一次拷贝,这无疑是对性能和内存的浪费。

另外一个问题是,结构体的大小终究是有限的,只能是个固定的大小。而如果我们想向函数传递一组数据,而且数据的总数还是不固定的,结构体就明显的无能为力了。
另外一个问题是,结构体的大小终究是有限的,无论多大,也只能是个固定的大小。而如果我们想向函数传递一组数据,而且数据的总数还是不固定的,结构体就明显的无能为力了。

为了解决这个问题,C 语言的开发者们想出了一个聪明的办法。他们把内存想象成一个巨大的字节数组,每个字节都可以拥有一个全局的索引值。这有点像门牌号:第一个字节索引为 0,第二个字节索引为 1,等等。

Expand Down Expand Up @@ -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;
}
```

0 comments on commit 961557e

Please sign in to comment.