PostScript字符串标记

时间:2014-03-05 19:38:54

标签: token postscript

我有一个循环,使用令牌取出字符串中的每个单词,然后我希望能够像这样对它进行计算:

(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

2 个答案:

答案 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'对象,它不会对它做任何进一步的操作。如果要执行操作,则必须检查返回对象的类型,并“执行”可执行文件。