我无法理解手册页中给出的这个例子dc:
$ dc
1 0:a 0Sa 2 0:a La 0;ap
1
Run Code Online (Sandbox Code Playgroud)
对我来说答案应该是 2 因为:
1 0:a
这里我们将 1 存储在 array 的第 0 个位置a。
0Sa
现在我们将 0 压入 register 的堆栈a。
2 0:a
现在我们再次将 2 存储在数组的第 0 个位置,a从而覆盖先前存储在该位置的 1。
La
现在我们弹出存储在寄存器堆栈中的 0a并将其推送到主堆栈。
0;a
现在我们再次将 0 推送到主堆栈,然后将其弹出以用作数组索引,因此我们将存储在数组第 0 个位置的 2 推a送到主堆栈。
p
现在我们打印主堆栈的顶部,即 2。所以答案应该是 2。
我错过了什么?
PS- 我想dc用作标签,但看起来它不存在,因此必须至少使用一个标签debian(我的工作站操作系统)。
就像在混合数组和堆栈中一样。在示例中,寄存器a既用作数组又用作堆栈。
1 0:a
0 Sa
2 0:a
La
0;a p
Run Code Online (Sandbox Code Playgroud)
:a-register a被视为一个数组。Sa- 寄存器a被视为堆栈。实际上将数组从 pt 1. 向下推送并创建一个新数组。As by man:请注意,寄存器的每个堆叠实例都有自己的关联数组。:a- 寄存器a被视为一个数组。将先前值和第一个数组值向下推。La- 寄存器a被视为堆栈。要获得第一个堆叠数组,将丢弃a[0]=2它,因为它是一个数组。;a- 寄存器a被视为一个数组。现在只剩下一个值了,添加到a的第一个数组值是1。有关更多示例,请参阅答案底部。
«每个寄存器有多少个数组和堆栈?我以为一个寄存器有一个堆栈和一个单独的数组。»
入栈dc是下推栈或 LIFO(后进先出)。和餐厅里的盘子一样。
,------ pop / push - take / leave
/
|
v
[-----] top
[-----] ... ... .
[-----] [-----] [-----] ..
(main) (register-a) (register-b) ...
Run Code Online (Sandbox Code Playgroud)
我们有一个主堆栈或工作堆栈,除非指定了需要寄存器的操作,否则将使用该堆栈。每个寄存器都有自己的堆栈。
Sr:从主堆栈中弹出一个值并将其压入由 register 指定的堆栈。两个堆栈都修改了。rLr:弹出一个由指定的寄存器堆栈的值r和推它到主栈。两个堆栈都修改了。sr:从主堆栈中弹出一个值并将其写入寄存器。实际上更改 register 指定的堆栈中的最顶层值。如果该堆栈中没有值 – 添加它。主堆栈已修改。寄存器堆栈保留在更改的值旁边。rrlr:从寄存器读取值r。如果有多个,则实际上是最高值。主要改变了。寄存器堆栈保留。:r:从主堆栈中弹出两个值,并使用第一个,最上面的,作为将第二个值存储在 register 数组中的位置的索引。主要改变了。寄存器堆栈保留。r;r:从主堆栈中弹出一个值并将其用作索引,从哪里读取指定的寄存器中的当前数组。主要改变了。寄存器堆栈保留。r一种查看方式是成对查看。当您开始时,所有寄存器都是空的。当您通过 将元素添加到堆栈时Sr,您隐藏了该堆栈中的所有底层元素。说你这样做:
1 Sx
2 Sx
4 Sx
x = (S) 4 VISIBLE
(S) 2 HIDDEN
(S) 1 HIDDEN
Run Code Online (Sandbox Code Playgroud)
现在您可以更改寄存器x 中的值,即;更改最顶部的元素 by sx,您可以读取 by lx– 无需更改堆栈中的元素数量:
lx p # Read value in register x - in effect read topmost element from stack.
4 # Printed value by p.
3 sx # Change value in register x - in effect change topmost element in stack.
x = (S) 3 VISIBLE
(S) 2 HIDDEN
(S) 1 HIDDEN
Run Code Online (Sandbox Code Playgroud)
如果您决定添加数组元素,事情就会朝着更复杂的方向发展。
4 1:x
5 2:x
x = [A]
[2]=5 VISIBLE
[1]=4 VISIBLE
(S) 3 VISIBLE
(S) 2 HIDDEN
(S) 1 HIDDEN
Run Code Online (Sandbox Code Playgroud)
现在我们已经向堆栈中的当前数组添加了值。我们可以读取和修改任何VISIBLE元素。
44 1:x
55 2:x
33 sx
1;x p # Read and print index 1
44
lx p # Read and print stack top.
33
x = [A]
[2]=55 VISIBLE
[1]=44 VISIBLE
(S) 33 VISIBLE
(S) 2 HIDDEN
(S) 1 HIDDEN
Run Code Online (Sandbox Code Playgroud)
如果我们然后添加一个堆栈元素,一种方式可以说堆栈框架是不可扩展的,因为我们已经向其上方的数组添加了值。因此添加了一个新的堆栈帧。
6 Sx
7 Sx
x = (S) 7 VISIBLE
(S) 6 HIDDEN
[A]
[2]=55 HIDDEN
[1]=44 HIDDEN
(S) 33 HIDDEN
(S) 2 HIDDEN
(S) 1 HIDDEN
Run Code Online (Sandbox Code Playgroud)
如果我们现在尝试访问最后一个数组,它是隐藏的。实际上,我们从一个空数组中读取,结果是默认值0。我们可以修改寄存器的值7的sr,但不能访问数组两级下来,除非我们摆脱上述两个堆元件。
如果我们现在决定添加一些数组元素,它们将被添加到一个新的数组中(作为一个配对数组),它位于栈顶元素。
8 1:x
9 2:x
x = [A]
[2]=9 VISIBLE
[1]=8 VISIBLE
(S) 7 VISIBLE
(S) 6 HIDDEN
[A]
[2]=55 HIDDEN
[1]=44 HIDDEN
(S) 33 HIDDEN
(S) 2 HIDDEN
(S) 1 HIDDEN
Run Code Online (Sandbox Code Playgroud)
现在,如果我们弹出堆栈,我们会弹出7,但由于中间有一个数组(可以这么说),它也被删除了。
Lx p # Pop + print top stack element.
7 # Value printed.
x = (S) 6 VISIBLE
[A]
[2]=55 HIDDEN
[1]=44 HIDDEN
(S) 33 HIDDEN
(S) 2 HIDDEN
(S) 1 HIDDEN
Run Code Online (Sandbox Code Playgroud)
8和9的数组消失了。值为6的堆栈元素可见。但是底层数组被阻塞了。通过1;x pyield 0读取。
在某种程度上,我们可以说堆栈元素是阻塞的,而数组是不透明的。数组有点挂在堆栈元素上。
我们需要从堆栈中再次弹出以显示底层堆栈元素 + 数组。
Lx p # Pop + print top stack element.
6 # Value printed.
x = [A]
[2]=55 VISIBLE
[1]=44 VISIBLE
(S) 33 VISIBLE
(S) 2 HIDDEN
(S) 1 HIDDEN
Run Code Online (Sandbox Code Playgroud)
总之,可以说数组和堆栈的数量不限于每个寄存器一个。
–每个寄存器有多少个数组和堆栈?
– 取决于您在该寄存器上执行的交替Sr和:r操作次数。
另一种看待它的方式是只有一个堆栈但有多个数组,如果我们在添加数组元素之间添加堆栈元素......
另一种方式是说在任何给定时刻当前数组不是
[register][array]
Run Code Online (Sandbox Code Playgroud)
但
[register][stack-element][array]
Run Code Online (Sandbox Code Playgroud)
这使:
[register][stack-element][array][...]
[register][stack-element][array][1]
[register][stack-element][array][0]
Run Code Online (Sandbox Code Playgroud)
并且该stack-element部分是不透明的、只读的等等。尽管在这种情况下我们还必须记住,我们不需要堆栈元素的值。只将数组值添加到寄存器是可以的。
或者每个堆栈元素都与一个我们可以修改的零填充数组配对:
1 Sx
2 Sx
3 Sx
4 1:x
5 2:x
6 Sx
7 Sx
8 1:x
9 2:x
x = (S) 7 + A[0]=0 A[1]=8 A[2]=9 A[3]=0 ... A[2048]=0
(S) 6 + A[0]=0 ... A[2048]=0
(S) 33 + A[0]=0 A[1]=4 A[2]=5 A[3]=0 ... A[2048]=0
(S) 2 + A[0]=0 ... A[2048]=0
(S) 1 + A[0]=0 ... A[2048]=0
Run Code Online (Sandbox Code Playgroud)
希望它使它更清楚一点。
$ dc
[ein] 0:a
[zwei] Sa
[drei] 0:a
0;ap # Copy + print index 0 of topmost array in register a
drei
Lap # Throws away [drei] and pops+prints first element in stack*
zwei
0;ap # Copy + print index 0 of first array
ein
Run Code Online (Sandbox Code Playgroud)
$ dc
[uno] 0:a # Array a(1)
[dos] 1:a # Array a(1)
[tres] 2:a # Array a(1)
[cuatro] Sa # Array a(2)
[cinco] Sa # Array a(2)
[seis] Sa # Array a(2)
[siete] 0:a # Array a(3)
[ocho] 1:a # Array a(3)
[nueve] 2:a # Array a(3)
Laf # Throws away Array 3 to get to first stack array, Array 2.
seis
Laf
cinco
seis
Laf
cuatro
cinco
seis
2;af # Now we're at the first array, Array 1.
tres
cuatro
cinco
seis
1;af
dos
tres
cuatro
cinco
seis
0;af
uno
dos
tres
cuatro
cinco
seis
Run Code Online (Sandbox Code Playgroud)
你必须记住,这dc是一个编译器——而且是一个疯狂的旧编译器。它是一种机器语言——面向堆栈的计算器。它非常强大,但它的界面并不是为您设计的 - 它的设计目的是在所有用户友好性都经过机器处理后,有效地处理您用其他语言编写的指令。
dc不以直观的方式存储数据。dc 东西东西。当它读取新输入时,如果不立即执行,则该值只会被扔到堆栈上。堆栈中的所有内容都已被向下推 - 最新的位于顶部,最旧的位于底部。您必须处理最新的堆栈成员才能检索最旧的堆栈成员。
很多人都能得到这么多。毕竟,堆栈并不那么奇怪——它有点像洗衣篮。但这也是相当一维的,而且dc比这更进一步。
所以就有了输入堆栈——主堆栈。默认情况下,这是所有dc指令输入和输出的所在。当你向它发出命令时,它就会工作。但还有所有其他寄存器 - 至少 256 个。其中每一个本身也是一个堆栈。
[Ss]您通常使用ave 和oad 命令来处理寄存器[Ll]。要将主堆栈上的顶部值作为标量值保存到寄存器中,a请执行以下操作sa。然后,您可以l随时使用 将此标量值加载回主堆栈的顶部la。好吧,只要寄存器的当前实例a保持当前状态,就可以。
要在旧的标量值保留的地方创建新的寄存器标量实例,您可以使用. 该命令弹出主堆栈并入栈寄存器堆栈。与 不同,该命令是寄存器的破坏性负载 - 当使用该命令将标量值弹出到主堆栈时,该寄存器实例中的任何内容都会被破坏,并且寄存器的任何先前实例都可以再次访问。aSaalaLaL
这也很容易通过一点练习就能掌握——它就像主堆栈一样,但每个寄存器都有一个。但每个寄存器还有一个更进一步的维度——它们的数组。
每个寄存器的每个实例都有一个数组。我认为默认大小是每个 2048 个索引 - 尽管我经常想知道堆栈有多深并且只能说它相当深。当您实例化寄存器的新标量值时,您不仅会下推其标量值,还会下推其数组。新实例有一个新数组,旧实例的数组保持不变,并且在弹出新实例后将像标量值一样可供您访问。
数组索引访问有点棘手。首先,几乎所有主堆栈操作都是破坏性的。访问数组索引的唯一方法是从主堆栈中提取其值,然后调用它。因为您的索引引用此时已被破坏,所以很难召回它。o并且O对于保留索引计数器很有用 - 但不要尝试使用索引 1 或 0。
不管怎样,寄存器的数组和它的堆栈不是独立的,而是相互依赖和多维的。通过练习、耐心和一点超人的决心,可以用它完成一些很酷的事情。祝你好运。