表达式结构

首先,我们需要让 lval 能够存储 S-表达式。这意味着我们还要能存储符号(Symbols)和数字。我们向枚举中添加两个新的类型。LVAL_SYM 表示操作符类型,例如 + 等,LVAL_SEXPR 表示 S-表达式。

  1. enum { LVAL_ERR, LVAL_NUM, LVAL_SYM, LVAL_SEXPR };

S-表达式是一个可变长度的列表。在本章的开头已经提到,我们不能创建可变长度的结构体,所以只能使用指针来表示它。我们为 lval 结构体创建一个 cell 字段,指向一个存放 lval* 列表的区域。所以 cell 的类型就应该是 lval**。指向 lval* 的指针。我们还需要知道 cell 列表中的元素个数,所以我创建了 count 字段。

我们使用字符串来表示符号(Symbols),另外我们还增加了另一个字符串用来存储错误信息。也就是说现在 lval 可以存储更加具体的错误信息了,而不只是一个错误代码,这使得我们的错误报告系统更加灵活好用。我们也可以删除掉之前写的错误枚举了。升级过后的 lval 结构体如下所示:

  1. typedef struct lval {
  2. int type;
  3. long num;
  4. /* Error and Symbol types have some string data */
  5. char* err;
  6. char* sym;
  7. /* Count and Pointer to a list of "lval*" */
  8. int count;
  9. struct lval** cell;
  10. } lval;

有指向指向指针的指针的指针吗?

这里有个古老的笑话,说是可以根据 C 程序员的程序中指针后面的星星数(*)作为其水平的评分。:P

初级水平的人写的程序可能只会用到像 char* 或是奇怪的 int* 等一级指针,所以他们被称为一星程序员。而大多数中级的程序员则会用到诸如 lval** 这类的二级指针,所以他们被称为二星程序员。但据说能用三级指针的就真的很少见了,你可能会在一些伟大的作品中见到,这些代码的妙处凡夫俗子自然也是体会不到的。果真如此,三星程序员这个称号真是极大的赞誉了。

但据我所知,还没有人用到过四级指针。