条件分支
Build Your Own Lisp · 第 13 章
为 Lisp 添加条件分支和比较运算
Chapter 13 · 条件分支
比较与逻辑运算
比较运算
为了让我们的语言能够进行条件判断,我们需要添加比较运算符。这些运算符接受两个数字作为输入,返回一个表示比较结果的值。
我们将使用数字 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表示假