• PostScript With Continuations

    From Lawrence D'Oliveiro@21:1/5 to All on Wed Jun 5 23:06:47 2024
    I’ve been messing around with a toy implementation (in Python) of a
    variant of the old PostScript language that I call “GXScript”.

    One of the features I added to it is continuations, à la Scheme and other Lisps. I added an operator called “cexec”, which invokes a procedure you pass to it but first pushes on the stack a continuation that, when
    invoked, resumes execution from just after the cexec call.

    Such continuations can be used in the all usual ways, for example to
    implement looping:

    {
    /Count 5 ldef
    /Top null ldef
    {/Top exch lstore} cexec
    {
    /Break exch ldef
    Count =
    /Count Count 1 sub lstore
    Count 0 eq {Break} if
    Top
    }
    cexec
    }
    exec

    Output:

    5
    4
    3
    2
    1

    Note that care has to be taken that no extra code inadvertently
    occurs after the first cexec, since that would also be reexecuted when “Top” is invoked. For example, the lines

    /Top null ldef
    {/Top exch lstore} cexec

    cannot be written in a form such as

    /Top {} cexec exch ldef

    since you do not want the “exch ldef” to be reexecuted after “Top” has been defined. Hence there is some slightly convoluted code to ensure
    that 1) the “Top” variable is initially defined in the right block
    scope, and 2) it gets assigned a continuation pointing at the right
    point in the code.

    Of course it would be fiddly to have to write this sort of thing out
    every time you wanted to use continuations to implement a loop. Here
    is a wrapper routine that is invoked with a procedure as argument:
    that procedure is repeatedly invoked, each time passing it a
    continuation that it can use to exit the loop.

    /DoLoop
    {
    /Proc exch ldef
    /Top null ldef
    {/Top exch lstore} cexec
    {Proc Top} cexec
    }
    ddef

    DoLoop will take your loop-body procedure as argument, and execute it repeatedly, each time pushing a continuation that can be used to exit the
    loop, until you invoke that continuation. Example use:

    /Count 5 ddef
    {
    /Break exch ldef # always pop arg even if not used
    Count =
    /Count Count 1 sub lstore
    Count 0 eq {Break} if
    }
    DoLoop

    The output is the same as before.

    Note that DoLoop is defined as a procedure, not a macro. PostScript never
    had macros, and I’m not sure I need to add them to GXScript.

    The source is here <https://bitbucket.org/ldo17/gxscript/>.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)