读取表达式

首先我们会读取整个程序,并构造一个 lval* 来表示它,然后我们对这个 lval* 进行遍历求值来得到程序的运行结果。第一阶段负责把抽象语法树(abstract syntax tree)转换为一个 S-表达式,第二阶段则根据我们已由的 Lisp 规则对 S-表达式进行遍历求值。

为了完成第一步,我们可以递归的查看语法分析树中的每个节点,并根据节点的 tagcontents 字段构造出不同类型的 lval*

如果给定节点的被标记为 numbersymbol,则我们可以调用对应的构造函数直接返回一个 lval*。如果给定的节点被标记为 rootsexpr,则我们应该构造一个空的 S-表达式类型的 lval*,并逐一将它的子节点加入。

为了更加方便的像一个 S-表达式中添加元素,我们可以创建一个函数 lval_add,这个函数将表达式的子表达式计数加一,然后使用 realloc 函数为 v->cell 字段重新扩大申请内存,用于存储刚刚加入的子表达式 lval* x

  1. lval* lval_read_num(mpc_ast_t* t) {
  2. errno = 0;
  3. long x = strtol(t->contents, NULL, 10);
  4. return errno != ERANGE ?
  5. lval_num(x) : lval_err("invalid number");
  6. }
  1. lval* lval_read(mpc_ast_t* t) {
  2. /* If Symbol or Number return conversion to that type */
  3. if (strstr(t->tag, "number")) { return lval_read_num(t); }
  4. if (strstr(t->tag, "symbol")) { return lval_sym(t->contents); }
  5. /* If root (>) or sexpr then create empty list */
  6. lval* x = NULL;
  7. if (strcmp(t->tag, ">") == 0) { x = lval_sexpr(); }
  8. if (strstr(t->tag, "sexpr")) { x = lval_sexpr(); }
  9. /* Fill this list with any valid expression contained within */
  10. for (int i = 0; i < t->children_num; i++) {
  11. if (strcmp(t->children[i]->contents, "(") == 0) { continue; }
  12. if (strcmp(t->children[i]->contents, ")") == 0) { continue; }
  13. if (strcmp(t->children[i]->tag, "regex") == 0) { continue; }
  14. x = lval_add(x, lval_read(t->children[i]));
  15. }
  16. return x;
  17. }
  1. lval* lval_add(lval* v, lval* x) {
  2. v->count++;
  3. v->cell = realloc(v->cell, sizeof(lval*) * v->count);
  4. v->cell[v->count-1] = x;
  5. return v;
  6. }