解释器:先判断,再选择

本节阅读量:

第二章的解释器已经有 environment,并用 switch 处理整数、加法、变量和 let

第三章只增加两个分支:

1
2
equal
conditional

代码在:

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? 自己仍然只返回 01。判断某个表达式是不是零,也走这一条分支,例如 (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

输出依次是:

1
2
3
4
42
42
1
42

short_branch.lang 是:

1
(if 1 42 (+ 1 2))

condition 是非零整数,因此解释器直接返回 then 分支的 42


3.3 Parser:读出谓词和 if

上一节

3.5 IR:把一条直线变成几条可选择的路

下一节