Factor 手册的这一页讨论了存储在延续中的这些类型的堆栈:
- 数据栈
- 保留堆栈
- 调用栈
- 名称堆栈
- 捕捉堆栈
这些堆栈到底有什么?对我来说最令人困惑的三个是调用堆栈、保留堆栈和名称堆栈。
我当然不是因素大师,但因为他们的名字似乎暗示了他们的用途:
datastack:用于通常的值的推送和弹出。3 4 +
使用数据堆栈推送“3”,然后推送“4”。运行“+”会从数据堆栈中弹出 2 个值,并将答案 5 推回数据堆栈。运行 factor 的交互式会话(至少在 Linux 上)会在每次交互后打印此堆栈的内容:
$> 1
--- Data stack:
1
$> 2
--- Data stack:
1
2
$> +
--- Data stack:
3
$> .
3
$>
callstack:用于存储正在运行的单词及其组件单词执行时的各个进度。想象一下,您定义了一个更好的 sum 版本:(: sum' ( seq-of-int -- summmation ) 0 [ + ] reduce 20 + ;
更好,因为您可以免费获得额外的 20!)。想要重用代码,您已经利用了reduce
标准因子附带的词。在运行时执行时sum'
,它会调用reduce
. 但是,由于我们仍然需要添加额外的 20 个,因此必须有人记录返回后在哪里再次启动reduce
。这些注释存储在调用堆栈中,很可能在调试运行期间带有一些辅助数据,以帮助调试器了解正在发生的事情。
retainstack:用于在某种辅助数据堆栈上保留值。在 Forth 中,可以滥用返回栈(Forth 的调用栈的类似物)来充当保留栈。这种方法的一个问题是,在没有清理你的肮脏黑客的情况下从你的话中返回将使你跳到不正确的位置并造成普遍的破坏。Forth 的运行时会看到你的值,期望它们是它在调用一个词并感到困惑时所做的漂亮笔记。通过为返回地址使用单独的堆栈,Factor 可以避免这种情况。
namestack:用于保存实现动态变量所需的数据。通过使用堆栈,您可以在执行子例程时用新名称隐藏旧名称,然后弹出绑定并恢复旧名称。
catchstack:用于支持异常处理。通过使用堆栈,子例程可以为异常和影子默认行为注册自己的专用处理程序。然后,一旦单词返回,旧的处理程序可以通过从堆栈中弹出来轻松恢复。