感谢 2024 级的王浩宸同学

使用Vscode的Debug功能解析

怎么使用Debug

  • 直接按照助教的提示修改.vscode/launch.json文件即可。其中 "args" 是一个数组,记录了将会传入给 python scheme 指令的参数。例如下面的例子等价于调用 python scheme -i tests.scm,即对 tests.scm 文件执行我们的 scheme 解释器。

{ "version": "0.2.0", "configurations": [ { "name": "Python: Current File", "type": "python", "request": "launch", "program": "scheme.py", "args":[ "-i", "tests.scm" ], "console": "integratedTerminal", "justMyCode": true, } ] }
  • 你可以修改tests.scm里面的测试用例来测试,下面是我的例子
(define (factor n acc)   (if (= n 0)       acc       (factor (- n 1) (* acc n)))) (factor 10 1)
  • 当然别忘打断点了

Debug,启动!

  • 点击Start Debugging

  • |300

  • 然后你会发现左边出来这些东西,分别是你的VARIABLESWATCHCALL_STACK

    • VARIABLES是当前的变量
    • WATCH可以添加自己想看的表达式或者变量的值
    • CALL_STACK看调用的堆栈

我们发现他停到了if这个语句停下来了

现在解释器在干啥?

  • 我们发现左上角的expr的第一个symdefine,说明他正在进行do_define_form

怎么让解释器往下走?

在最上面有几个按钮,分别是下面几个

  • Step Into 如果当前语句是一个call expression,他就会进入函数体让你看函数体内部是怎么执行的;否则和Step Over一样。
  • Step Over:不管是否是call expression直接当一条普通语句运行过去。
  • Step Out:跳出当前Frame(比如A里面调用了B函数,我现在通过Step Into进入了B所在的Frame,Step Out就直接回到A里面)

所以我们按Step Into,你会发现他跳过了上面的if语句;这是因为我们现在是在do_define_form,并不是尾递归操作,所以就调用原始的eval_call.

  • 我们再次选择Step Into,发现:

这个部分就比较好理解了,他就是在做define的内容,我就不解释了。

做完define form之后

  • 按照解释器解释的规则,我们把factor绑定到对应的lambda函数之后,就会执行(factor 10 1)

那么他的的执行顺序就是(请你注意看左下角的CALL_STACK

  1. eval factor
  2. eval 10
  3. eval 1 图略,类似上面
  4. apply lambda 10 1