The user can declare initial, possibly recursive programs by composing the
tokens described above.
Programs are sequentially written
into
, starting with
at address 1.
To declare a new token (program) we write
decl(m, n, NAME, body), where
NAME is the textual name of the code. Textual names are of interest
only for the user, since the system immediately translates any new name into
the smallest integer
which gets associated with the topmost unused
code address; then
is incremented.
Argument
denotes the code's number of expected arguments
on top of the data stack ds;
denotes the number of return values;
body is a string of names of previously
defined instructions, and possibly one new name to allow
for cross-recursion. Once the interpreter
comes across a user-defined token, it
simply calls the code in
starting with that body's first token;
once the code is executed, the interpreter returns to the address of the next token,
using the callstack
.
All of this is quite similar to the case of self-made functions defined by
the system itself -- compare instruction def in
section A.2.2.
Here are some samples of user-defined tokens or programs composed from the primitive instructions defined above. Declarations omit parantheses for argument lists of instructions.
decl(-1,-1,defnp, c0 toD pushdp dec toD qot def up rt0 dec intpf cpn qot ret)
decl(-1,-1,calltp, qot topf dof intpf cpn qot ret)
decl(-1,-1,endnp,qot ret qot fromD cpnb fromD up delD fromD ex bsf ret)
decl(-1, -1, TAILREC, qot c1 c1 def up qot c2 outb qot ex rt0 del
up dec topf dof qot c3 outb qot ret qot c1 outb c3 bsjmp)
declares a tail recursion scheme TAILREC with a functional argument.
Suppose the data stack ds holds three values
, val, and codenum
above the current base pointer.
Then TAILREC will create a function that returns val
if
, else applies
the 2-argument function represented by codenum, where the arguments
are
and the result of
calling the 2-argument function itself on the value
.
For example,
the following code fragment uses TAILREC to implement yet
another version of FAC(n):
(qot c1 mul qot TAILREC ret).
Assuming
on ds, it first quotes the constant c1 (the
return value for the terminal case
) and
the function mul, then applies TAILREC.
To fully understand a given program, one may need to know which instruction has got which number. For the sake of completeness, and to permit precise re-implementation, we include the full list here:
1: 1toD, 2: 2toD, 3: mvdsk, 4: xAD, 5: xSA, 6: bsf, 7: boostq, 8: add, 9: mul, 10: powr, 11: sub, 12: div, 13: inc, 14: dec, 15: by2, 16: getq, 17: insq, 18: findb, 19: incQ, 20: decQ, 21: pupat, 22: setpat, 23: insn, 24: mvn, 25: deln, 26: intpf, 27: def, 28: topf, 29: dof, 30: oldf, 31: bsjmp, 32: ret, 33: rt0, 34: neg, 35: eq, 36: grt, 37: clear, 38: del, 39: up, 40: ex, 41: jmp1, 42: outn, 43: inn, 44: cpn, 45: xmn, 46: outb, 47: inb, 48: cpnb, 49: xmnb, 50: ip2ds, 51: pip, 52: pushdp, 53: dp2ds, 54: toD, 55: fromD, 56: delD, 57: tsk, 58: c0, 59: c1, 60: c2, 61: c3, 62: c4, 63: c5, 64: exec, 65: qot, 66: nop, 67: fak, 68: fak2, 69: c999, 70: testexp, 71: defnp, 72: calltp, 73: endnp.