我有一个循环,使用令牌取出字符串中的每个单词,然后我希望能够像这样对它进行计算:
(1 2加3 4加)
但是你编码的任何方式我一直在
7
add
2
1
我希望它是
7
3
这就是我正在使用的
{ %loop
pstack
(repl> )print flush
(%lineedit)(r)file
dup bytesavailable string readstring pop
{
token
{}{exit}ifelse
exch
dup () eq {pop exec exit}if
exec
}loop
}loop
答案 0 :(得分:3)
我建议你在每一行的末尾写下堆栈注释。这真的有帮助。
{ %loop
pstack
(repl> )print flush
(%lineedit)(r)file % f
dup bytesavailable string readstring pop % s
{
token % s t b
{}{exit}ifelse % s t
exch % t s
dup () eq {pop exec exit}if % t s
exec % t
}loop
}loop
因此,您正在执行剩余的子字符串而不是令牌。在内循环中的exch
之前,您需要另一个exec
。这将执行令牌而不是子串。但问题是字符串是坐在堆栈上的。所以add
将无效,因为它会在堆栈顶部找到一个字符串而不是下面的数字。
因此,在执行之前按名称保存子字符串可能会更好,然后在下一次迭代之前将其放回。
{ % s
token % s t b
{}{exit}ifelse % s t
exch % t s
dup () eq {pop exec exit}if % t s
/rem exch def % t
exec
rem % s
}loop
这部分可能比对postcript的新手更有帮助。继续自担风险。 如果你迷失在中间,请务必看到最终超级简单技术的最终结果。
后记黑客应该问的下一个问题是:“如何在不使用此rem
名称污染名称空间的情况下执行此操作?”
我将使用的疯狂技巧是利用loop
运算符来创建具有额外存储空间的过程体。
{ procedure body } exec
{ procedure body exit extra storage } loop
上面的两个构造都将执行procedure body
然后返回控制。但是使用带有显式loop
的{{1}}可以让我们将更多内容打包到数组中。
所以,我们从上面采取内循环。
exit
将其包裹在“退出循环”中。
token{}{exit}ifelse exch dup()eq{pop exec exit}if/rem exch def exec rem
我们将在{
token{}{exit}ifelse exch dup()eq{pop exec exit}if/rem exch def exec rem
exit } loop
之后存储字符串余数。
exit
将{
token{}{exit}ifelse exch dup()eq{pop exec exit}if/rem exch def exec rem
exit STR } loop
替换为存储在数组中的代码。这个数组将是循环体的子数组,它只保存/name exch def
额外的存储空间。
[ STR ]
这个循环当然是直接的:它实际上并没有循环。所以要从上面替换内部循环,我们将它包装在另一个循环中。
/rem exch def --> ARR exch 0 exch put
rem --> ARR 0 get
{
token{}{exit}ifelse exch dup()eq{pop exec exit}if ARR exch 0 exch put exec ARR 0 get
exit STR } loop
然后我们需要插入代码中{ {
token{}{exit}ifelse exch dup()eq{pop exec exit}if ARR exch 0 exch put exec ARR 0 get
exit STR } loop } loop
所在的子数组。这是包含(虚拟)ARR
标记的(内部)内部循环的子数组。
STR
所以我们需要在数组[10]和数组[16]中插入一个子数组[20,1]。我们可以在外部范围内调用% 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
{ { token{}{exit}ifelse exch dup()eq{pop exec exit}if ARR exch 0 exch put exec ARR 0 get exit STR } loop } loop
之前执行此操作。
loop
那里有一个没有名字的循环。 :)
注意,我们在代码中仍然有假名{ {
token{}{exit}ifelse exch dup()eq{pop exec exit}if ARR exch 0 exch put exec ARR 0 get
exit STR } loop }
dup 0 get % loop-body inner-loop get a copy of the exit-loop
dup 20 1 getinterval % loop-body inner-loop [STR] take a subarray of the exit-loop
2 copy 10 exch put % loop-body inner-loop [STR] insert in position 10
16 exch put % loop-body' insert in position 16
loop % call the loop operator
,这没关系。它将作为名称进行解析并在数组中分配一个额外的插槽。并且它不需要在任何地方定义,因为它永远不会被执行。
对上述方面的改进。我们实际上不需要模板代码中的第二个STR
。我们可以将字符串直接存储在过程数组中需要它的位置。然后我们甚至不需要“退出循环”。所以模板变成了:
ARR
完全清晰的循环
% 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
{ token{}{exit}ifelse exch dup()eq{pop exec exit}if ARR exch 0 exch put exec STR } loop
改进的改进。我们实际上也不需要子阵列。我们可以将整个循环数组存储在ARR位置,并在存储代码中使用索引16而不是0。
{ token{}{exit}ifelse exch dup()eq{pop exec exit}if ARR exch 0 exch put exec STR }
dup dup 10 exch % loop loop 10 loop prepare stack
16 1 getinterval % loop loop 10 [STR] take a subarray
put % loop insert in position 10
loop % call loop operator
-
很久以后......
这比它需要的更复杂。我们可以简单地创建一个小数组来对这两件事的执行进行排序。
{ token not{exit}if exch dup()eq{pop exec exit}if ARR exch 16 exch put exec STR }
dup 10 1 index % loop loop 10 loop prepare stack
put % loop insert in position 10
loop % call loop operator
因此:
{exec rem}
答案 1 :(得分:0)
Token只是在堆栈上返回'tokenised'对象,它不会对它做任何进一步的操作。如果要执行操作,则必须检查返回对象的类型,并“执行”可执行文件。