解释器:先判断,再选择
本节阅读量:
第二章的解释器已经有 environment,并用 switch 处理整数、加法、变量和 let。
第三章只增加两个分支:
代码在:
1
|
code/03_conditionals/src/interp/interpreter.cpp
|
eq? 先求左右两边
1
2
3
4
5
6
|
case ExprKind::equal: {
const auto& eq_expr = static_cast<const EqExpr&>(expr);
long lhs = eval_expr(*eq_expr.lhs, env);
long rhs = eval_expr(*eq_expr.rhs, env);
return lhs == rhs ? 1 : 0;
}
|
这里先把左右结果分别保存下来,再比较它们。eq? 自己仍然只返回 0 或 1。判断某个表达式是不是零,也走这一条分支,例如 (eq? x 0)。
if 只调用一个分支
1
2
3
4
5
6
7
|
case ExprKind::conditional: {
const auto& if_expr = static_cast<const IfExpr&>(expr);
if (eval_expr(*if_expr.condition, env) != 0) {
return eval_expr(*if_expr.then_branch, env);
}
return eval_expr(*if_expr.else_branch, env);
}
|
注意代码形状:
1
2
3
|
先 eval condition
条件非 0,return eval(then)
否则,return eval(else)
|
它没有提前求值 then 和 else。两个分支中只有一个会进入 eval_expr()。
environment 继续正常工作
条件表达式可以放在 let 里面:
1
|
(let x 0 (if (eq? x 0) 42 7))
|
求值过程是:
1
2
3
4
5
6
|
value: 0
push x -> 0
condition: (eq? x 0) -> 1
选择 then: 42
pop x -> 0
return 42
|
第三章没有改变第二章的作用域规则。分支里查变量时,仍然从 environment 后面向前寻找最近的绑定。
运行几个例子
1
2
3
4
5
6
|
cd code/03_conditionals
make
./mini run examples/if.lang
./mini run examples/if_else.lang
./mini run examples/eq.lang
./mini run examples/short_branch.lang
|
输出依次是:
short_branch.lang 是:
condition 是非零整数,因此解释器直接返回 then 分支的 42。
3.5 IR:把一条直线变成几条可选择的路
下一节