ESC
输入关键词搜索文章
目录

条件分支

Build Your Own Lisp · 第 13 章
为 Lisp 添加条件分支和比较运算
Chapter 13 · 条件分支
比较与逻辑运算

章节信息

原书章节:第 13 章 Conditionals

中文翻译KSCO (GitHub)

原书地址buildyourownlisp.com

比较运算

为了让我们的语言能够进行条件判断,我们需要添加比较运算符。这些运算符接受两个数字作为输入,返回一个表示比较结果的值。

我们将使用数字 1 表示真(true),0 表示假(false)。这是最简单的布尔表示方法。

比较运算符

我们将实现以下比较运算符:

  • >:大于
  • <:小于
  • >=:大于等于
  • <=:小于等于
  • :等于
  • !=:不等于

实现比较运算符的代码如下:

lval* builtin_gt(lenv* e, lval* a) { return builtin_ord(e, a, ">"); }
lval* builtin_lt(lenv* e, lval* a) { return builtin_ord(e, a, "<"); }
lval* builtin_ge(lenv* e, lval* a) { return builtin_ord(e, a, ">="); }
lval* builtin_le(lenv* e, lval* a) { return builtin_ord(e, a, "<="); }

lval* builtin_ord(lenv* e, lval* a, char* op) {
  LASSERT_NUM(op, a, 2);
  LASSERT_TYPE(op, a, 0, LVAL_NUM);
  LASSERT_TYPE(op, a, 1, LVAL_NUM);

  int r;
  if (strcmp(op, ">") == 0) {
    r = (a->cell[0]->num > a->cell[1]->num);
  } else if (strcmp(op, "<") == 0) {
    r = (a->cell[0]->num < a->cell[1]->num);
  } else if (strcmp(op, ">=") == 0) {
    r = (a->cell[0]->num >= a->cell[1]->num);
  } else if (strcmp(op, "<=") == 0) {
    r = (a->cell[0]->num <= a->cell[1]->num);
  }

  lval_del(a);
  return lval_num(r);
}
相等比较

相等比较稍微复杂一些,因为我们需要比较不同类型的值。我们需要能够比较数字、字符串、错误、符号和列表。

lval* builtin_eq(lenv* e, lval* a) {
  LASSERT_NUM("==", a, 2);
  int r = lval_eq(a->cell[0], a->cell[1]);
  lval_del(a);
  return lval_num(r);
}

lval* builtin_ne(lenv* e, lval* a) {
  LASSERT_NUM("!=", a, 2);
  int r = !lval_eq(a->cell[0], a->cell[1]);
  lval_del(a);
  return lval_num(r);
}

int lval_eq(lval* x, lval* y) {

  /* Different Types are always unequal */
  if (x->type != y->type) { return 0; }

  /* Compare Based upon type */
  switch (x->type) {
    /* Compare Number Value */
    case LVAL_NUM: return (x->num == y->num);

    /* Compare String Values */
    case LVAL_ERR: return (strcmp(x->err, y->err) == 0);
    case LVAL_SYM: return (strcmp(x->sym, y->sym) == 0);

    /* If Builtin compare functions, otherwise compare formals and body */
    case LVAL_FUN:
      if (x->builtin || y->builtin) {
        return x->builtin == y->builtin;
      }
      return lval_eq(x->formals, y->formals)
        && lval_eq(x->body, y->body);

    /* If list compare every individual element */
    case LVAL_QEXPR:
    case LVAL_SEXPR:
      if (x->count != y->count) { return 0; }
      for (int i = 0; i < x->count; i++) {
        if (!lval_eq(x->cell[i], y->cell[i])) { return 0; }
      }
      return 1;
    break;
  }
  return 0;
}
逻辑运算

我们还需要逻辑运算符:&&(与)、||(或)和 !(非)。

逻辑运算符

逻辑运算符用于组合多个条件:

  • &&(与):两个条件都为真时返回真
  • ||(或):至少一个条件为真时返回真
  • !(非):反转条件的真假
lval* builtin_and(lenv* e, lval* a) {
  LASSERT_NUM("&&", a, 2);
  LASSERT_TYPE("&&", a, 0, LVAL_NUM);
  LASSERT_TYPE("&&", a, 1, LVAL_NUM);

  int r = a->cell[0]->num && a->cell[1]->num;
  lval_del(a);
  return lval_num(r);
}

lval* builtin_or(lenv* e, lval* a) {
  LASSERT_NUM("||", a, 2);
  LASSERT_TYPE("||", a, 0, LVAL_NUM);
  LASSERT_TYPE("||", a, 1, LVAL_NUM);

  int r = a->cell[0]->num || a->cell[1]->num;
  lval_del(a);
  return lval_num(r);
}

lval* builtin_not(lenv* e, lval* a) {
  LASSERT_NUM("!", a, 1);
  LASSERT_TYPE("!", a, 0, LVAL_NUM);

  int r = !a->cell[0]->num;
  lval_del(a);
  return lval_num(r);
}
条件分支

最后,我们需要实现 if 函数,它接受三个参数:条件、真值表达式和假值表达式。

lval* builtin_if(lenv* e, lval* a) {
  LASSERT_NUM("if", a, 3);
  LASSERT_TYPE("if", a, 0, LVAL_NUM);
  LASSERT_TYPE("if", a, 1, LVAL_QEXPR);
  LASSERT_TYPE("if", a, 2, LVAL_QEXPR);

  /* Mark Both Expressions as evaluable */
  lval* x;
  a->cell[1]->type = LVAL_SEXPR;
  a->cell[2]->type = LVAL_SEXPR;

  if (a->cell[0]->num) {
    /* If condition is true evaluate first expression */
    x = lval_eval(e, lval_pop(a, 1));
  } else {
    /* Otherwise evaluate second expression */
    x = lval_eval(e, lval_pop(a, 2));
  }

  /* Delete argument list and return */
  lval_del(a);
  return x;
}

复习速查

  • 比较运算符><>=<=!=
  • 逻辑运算符&&(与)、||(或)、!(非)
  • if 函数:接受条件、真值表达式、假值表达式三个参数
  • 布尔值:使用数字 1 表示真,0 表示假