PostScript字符串令牌 [英] PostScript String Token

查看:76
本文介绍了PostScript字符串令牌的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a loop that takes out each word in a string using token, then I want to be able to do computations on it like this:

(1 2加3 4加)

但是无论用什么方式编码,我都会不断得到

But any way you code it i keep getting

    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


推荐答案

我建议您最后写堆栈注释每行。

I would advise you to write stack comments at the end of each line. It really helps.

{ %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

因此,您正在执行其余的子字符串而不是令牌。在内部循环中的 exec 之前,您还需要另一个 exch 。那将执行令牌而不是子字符串。但是与此有关的一个问题是字符串位于堆栈上。因此 add 将不起作用,因为它将在堆栈顶部找到一个字符串,而不是下面的数字。

So you're executing the remaining substring instead of the token. You need another exch in there before the exec in the inner loop. That would execute the token instead of the substring. But a problem with this is that the string is sitting there on the stack. So add won't work because it will find a string on top of the stack instead of the numbers below.

因此,最好在执行前按名称保存子字符串,然后在下一次迭代之前将其放回去。

So it may be better to save the substring by name before exec-ing, and then put it back before the next iteration.

    {  % 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






对于刚起步的人来说,这部分可能比帮助更令人困惑。 如果您迷失在中间,请确保从头到尾看到最终的超级简单技术。

后记黑客应该问的下一个问题是:如何在不使用此 rem 名称?

The next question a postscript hacker should ask is: "How can I do this without polluting the name space with this rem name?"

我为此使用的疯狂技巧是利用 loop 运算符具有额外存储空间的过程主体。

The insane trick I would use for this is to exploit the loop operator to make a procedure body with extra storage.

{ procedure body } exec
{ procedure body exit extra storage } loop

以上两个构造都将执行程序体,然后返回控制。但是,将 loop 与明确的 exit 结合使用,我们可以将多余的东西打包到数组中。

Both constructs above will execute procedure body and then return control. But using loop with an explicit exit lets us pack extra things into the array.

因此,我们从上面进行内循环。

So, we take the inner loop from above.

token{}{exit}ifelse exch dup()eq{pop exec exit}if/rem exch def exec rem

将其包装在出口中-loop。

Wrap it in an "exit-loop".

{
    token{}{exit}ifelse exch dup()eq{pop exec exit}if/rem exch def exec rem
exit } loop

然后我们要存储 exit 之后的字符串剩余部分。

And we're going to store the string remainder just after exit.

{ 
    token{}{exit}ifelse exch dup()eq{pop exec exit}if/rem exch def exec rem
exit STR } loop

用存储在数组中的代码替换 / name exch def 。该数组将是循环主体的子数组,其中仅包含 [STR] 额外的存储空间。

Replace the /name exch def with code that stores into an array. This array will be a subarray of the loop body which just holds the [ STR ] extra storage.

/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

当然,此循环是直截了当的:实际上并没有循环。因此,要从上方替换内部循环,请将其包装在另一个循环中。

This loop is of course a straight-shot: it doesn't actually loop. So to replace the inner loop from above, we wrap it in another 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 令牌。

Then we need to insert the subarray where ARR is in the code. This is the subarray of the (inner) inner loop that contains the (dummy) STR token.

%   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

子数组[20,1]将插入到数组[10]和数组[16]处。我们可以在外部范围调用 loop 之前完成此操作。

So we need a subarray [20, 1] to be inserted at array[10] and array[16]. And we can do this before calling loop at the outer scope.

{ {
    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

那里是一个没有名字的循环。 :)

There, a loop with no name. :)

注意,我们在代码中仍然有虚拟名称 STR ,这没关系。它将解析为一个名称,并在数组中分配一个额外的插槽。而且不需要在任何地方定义它,因为它永远不会执行。

Notice, we still have the dummy name STR in the code, and that's ok. It will parse as a name and allocate an extra slot in the array. And it doesn't need to be defined anywhere because it never gets executed.

对上述内容的改进。我们确实不需要模板代码中的第二个 ARR 。我们可以将字符串直接存储到过程数组中所需的位置。然后,我们甚至不需要退出循环。因此模板变为:

An improvement over the above. We really do not need the second ARR in the template code. We can store the string directly into the procedure array at the position where it is needed. Then we don't even need the "exit-loop". So the template becomes:

% 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

和完全铰接的循环

{ 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






改进的改进。我们实际上也不需要子数组。我们可以将整个循环数组存储在ARR位置,并在存储代码中使用索引16而不是0。


An improvement of the improvement. We don't actually need a subarray either. We can store the entire loop array in the ARR position and use the index 16 instead of 0 in the storing code.

{ 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

-

更晚的时间...

这比需要的复杂得多。我们可以简单地排列一个数组来对这两件事的执行进行排序。

This is way more complicated than it needs to be. We can simply make a little array to sequence the execution of these two things.

{exec rem}

因此:

{  % s
    token                       % s t b
    not{exit}if                 % s t
    exch                        % t s
    dup () eq {pop exec exit}if % t s
    /exec cvx exch 2 array astore cvx % t {exec s}
    exec
}loop

这篇关于PostScript字符串令牌的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆